android 应用自启管理

因项目的需要,做一个自启管理的功能,管理其它app的自启动。看到这个功能的时候我有点无从下手,大多数第三方的管理app是没有这个功能的,网上关于这个功能的例子也很少,没有什么好的参考。只能自己研究了。很多的app的自启都是靠监听系统的广播,像最典型的就是开机广播。所以我想到的方法是禁止应用收听相关的广播来实现。有一个方法可以禁止掉android四大组件的使用。

public void setComponentEnabledSetting (ComponentName componentName, int newState, int flags)
componentName:组件名称 
newState:组件新的状态,可以设置三个值,分别是如下: 
不可用状态:COMPONENT_ENABLED_STATE_DISABLED 
可用状态:COMPONENT_ENABLED_STATE_ENABLED 
默认状态:COMPONENT_ENABLED_STATE_DEFAULT 
flags:行为标签,值可以是DONT_KILL_APP或者0。 0说明杀死包含该组件的app
public int getComponentEnabledSetting(ComponentName componentName)
获取组件的状态

特别注意setComponentEnabledSetting 这个方法是需要系统权限的,也就是说用这个方法去实现必须可以拿到系统权限。
下面说下具体的实现,首先获取到需要禁止掉应用的信息,数据保存在ArrayList里面。AutoStartInfo用来
存储信息。

 public static List<AutoStartInfo> fetchAutoApps(Context mContext) {
        PackageManager pm = mContext.getPackageManager();
        Intent[] intents=getIntents();
        List<AutoStartInfo> appList = new ArrayList<AutoStartInfo>();
        String appName = null;
        Drawable icon = null;
        String packageName =null;
        boolean isSystem = false;
        boolean isenable = true;
        List<ResolveInfo> resolveInfoList=null;
            for (Intent intent : intents) {
                resolveInfoList = pm.queryBroadcastReceivers(intent, PackageManager.MATCH_DISABLED_COMPONENTS);
                for (int i = 0; i < resolveInfoList.size(); i++) {
                    AutoStartInfo mAutoStartInfo = new AutoStartInfo();
                    Log.d(TAG, "appName "+appName+" packageName "+packageName);
                    mAutoStartInfo.setLabel(appName);
                    mAutoStartInfo.setSystem(isSystem);
                    mAutoStartInfo.setEnable(isenable);
                    mAutoStartInfo.setIcon(icon);
                    mAutoStartInfo.setPackageName(packageName);
                    if(isAdd(appList,packageName)&&packageName!=null){
                        appList.add(mAutoStartInfo);
                    }
                    appName = resolveInfoList.get(i).loadLabel(pm).toString();
                    packageName = resolveInfoList.get(i).activityInfo.packageName;
                    // Log.d(TAG, "packageName 1 " + packageName + " packageReceiver " + packageReceiver);
                    icon = resolveInfoList.get(i).loadIcon(pm);
                    ComponentName mComponentName2 = new ComponentName(resolveInfoList.get(i).activityInfo.packageName, resolveInfoList.get(i).activityInfo.name);
                    if (pm.getComponentEnabledSetting(mComponentName2) == 2) {
                        isenable = false;
                    } else {
                        isenable = true;
                    }
                    if ((resolveInfoList.get(i).activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
                        isSystem = true;
                    } else {
                        isSystem = false;
                    }
                }
            }
        return appList;
    }

intents里面包含了所要禁止的广播种类,这里我禁止了5种广播。

 public static Intent[] getIntents(){
        return new Intent[]{
                    new Intent("android.intent.action.BATTERY_CHANGED"),new Intent("android.intent.action.BOOT_COMPLETED"),new Intent("android.net.conn.CONNECTIVITY_CHANGE"),new Intent("android.intent.action.LOCALE_CHANGED"),
                new Intent("android.intent.action.USER_PRESENT")
        };
    }

这里的isAdd()方法用来限制添加相同的包名,因为有些应用可能注册了这里的几个广播。

 private static Boolean isAdd(List<AutoStartInfo> list, String packageName){
        for (AutoStartInfo autoStartInfo : list) {
            if (packageName.equals(autoStartInfo.getPackageName())) {
                Log.d("appListadd", "getPackageName " + autoStartInfo.getPackageName() + " packageName " + packageName);
                return false;
            }
        }
        return true;
    }

AutoStartInfo.java类保存信息

public class AutoStartInfo {
    private String label;
    private String packageName;
    private Drawable icon;
    private String name;

    private String packageReceiver;
    private String desc;
    /**  是否是系统进程. */
    public boolean isSystem;
    public boolean isenable;

    public String getLabel() {
        return label;
    }

    public void setLabel(String label) {
        this.label = label;
    }

    public String getPackageName() {
        return packageName;
    }

    public void setPackageName(String packageName) {
        this.packageName = packageName;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }

    public Drawable getIcon() {
        return icon;
    }

    public void setIcon(Drawable icon) {
        this.icon = icon;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public boolean isSystem() {
        return isSystem;
    }

    public void setSystem(boolean isSystem) {
        this.isSystem = isSystem;
    }

    public boolean isEnable() {
        return isenable;
    }

    public void setEnable(boolean enable) {
        this.isenable = enable;
    }

    public String getPackageReceiver() {
        return packageReceiver;
    }

    public void setPackageReceiver(String packageReceiver) {
        this.packageReceiver = packageReceiver;
    }
}

布局的话比较简单,一个ListView,ListView的item里面放一个Switch来控制开关,这里就不贴代码了。
在Adapater里面实现相关逻辑。

holder.disable_switch.setOnCheckedChangeListener(null);
            Log.i(TAG, " item.getPackageName() "+item.getPackageName()+"getView Boolean= " + getSharedPreferences(mContext,item.getPackageName(),false));
            if (getSharedPreferences(mContext,item.getPackageName(),false)) {
                holder.disable_switch.setChecked(true);
            } else {
                holder.disable_switch.setChecked(false);
            }

            holder.disable_switch.setOnCheckedChangeListener(new SwitchButtonChangeListener(item.getPackageName()));

这里本来是很简单的代码,但是我在使用的时候一直有问题,把switch的开关打开,然后滑动listView,开关又自动关闭了。在网上有人解决了,就是加上holder.disable_switch.setOnCheckedChangeListener(null)这句。

这里我使用SharedPreferences来保存数据,用包名来当key.

 private void operateSharedPreferences(Context context,String packageName,Boolean value){
        SharedPreferences preferences=context.getSharedPreferences("user",Context.MODE_PRIVATE);
        SharedPreferences.Editor editor=preferences.edit();
        editor.putBoolean(packageName,value);
        editor.commit();
    }

    private Boolean getSharedPreferences(Context context,String packageName,Boolean value){
        SharedPreferences preferences=context.getSharedPreferences("user", Context.MODE_PRIVATE);
        boolean bool=preferences.getBoolean(packageName, value);
        return bool;
    }

SwitchButtonChangeListener的实现,把packageName传进去

    private class SwitchButtonChangeListener implements CompoundButton.OnCheckedChangeListener {
     private String mPackageName ;
    SwitchButtonChangeListener(String packageName){
        mPackageName= packageName;
    }

    @Override
    public void onCheckedChanged(CompoundButton buttonView,boolean isChecked) {
        diasableApp(mPackageName,isChecked);
    }
}

最核心的方法diasableApp(),里面包含了数据的存储和是否接受相关的广播

 private void diasableApp(String packageName,Boolean isDiasableApp) {
        Intent[] intents=BootStartUtils.getIntents();
        List<String> listReceiver = BootStartUtils.addReceiver(intents, mContext.getPackageManager(), packageName);
        controlBroadcastReceiver(mContext,packageName,listReceiver,isDiasableApp);
        notifyDataSetChanged();
        operateSharedPreferences(mContext,packageName,isDiasableApp);
    }
private void  controlBroadcastReceiver(Context context,String packageName,List<String> broadcastReceiverName,boolean isStop){
        PackageManager pm=context.getPackageManager();
        for (String s : broadcastReceiverName) {
            ComponentName componentName = new ComponentName(packageName, s);
            if (isStop == true){ 
            //禁止接收相关的广播            pm.setComponentEnabledSetting(componentName,PackageManager.COMPONENT_ENABLED_STATE_DISABLED,PackageManager.DONT_KILL_APP);
            }else {
            //允许接收相关的广播    pm.setComponentEnabledSetting(componentName,PackageManager.COMPONENT_ENABLED_STATE_ENABLED,PackageManager.DONT_KILL_APP);
            }
        }
    }

到此,这个功能就基本上实现了,附上一张效果图。
这里写图片描述

猜你喜欢

转载自blog.csdn.net/qq_32072451/article/details/78844646
今日推荐