概况

Android手机上安装的很多应用都会频繁唤醒手机(唤醒系统、唤醒屏幕),造成手机耗电等现象。良好的对齐唤醒管理方案,就是对后台应用待机时不频繁唤醒,智能节省电量。

实现原理:APK作为该功能的入口,勾选应用后,将勾选的应用写入黑名单,并通知framework黑名单内容变化;framework接收到通知后,自动获取黑名单中的应用,保存到列表中;在framework调用接口中检测应用是否在黑名单中,如果在黑名单中则检测闹钟类型,如果闹钟类型是0或2,对应修改为1或3。

应用层功能实现

APK界面初始化

在ForbitAlarmLogic构造方法中初始化了数组列表listPkgs、forbitPkgs、allowPkgs、showPkgs。

listPkgs:表示需要设置对齐唤醒的应用,如果这些应用已经安装,就会显示在对齐唤醒设置的界面上。初始数据从/data/data/com.***.android.security/app_bin/forbitapplist.xml中获取,如果文件不存在,则从本地资源数组security_array_savepower_forbitalarms中获取。

forbitPkgs:表示对齐唤醒名单,即禁止唤醒的名单,界面勾选的应用。初始数据从SharedPreference数据库名ManagerUtil.PRE_NAME(com.***.android.savepowermanager_preferences)中获取键值ManagerUtil.FORBIT_ALARM_APP_LIST_KEY中保存的数据,将获取的数据保存到forbitPkgs数组中,如果没有数据则返回null。

allowPkgs:表示允许唤醒的名单,界面没有勾选的应用。初始数据从SharedPreference数据库ManagerUtil.PRE_NAME(com.***.android.savepowermanager_preferences)中获取键值为ManagerUtil.ALLOW_ALARM_APP_LIST_KEY中保存的数据,将获取的数据保存到allowPkgs数组列表中;如果没有数据则返回null。

showPkgs:表示要显示在对齐唤醒设置界面的数组应用列表,在数据初始化之前先将该数组清空。对齐唤醒方案优化之前,该数组保存的是listPkgs列表与已安装应用的交集。优化之后,同时还保存了已安装的第三方应用。

[java] view plaincopypublicForbitAlarmLogic(Context ctx) {this.mCtx = ctx;pm = ctx.getPackageManager();xmlAppList = Util.getDefaultDataPath(ctx) + "/app_bin/applist.xml";String xmlFile = Util.getDefaultDataPath(ctx)+"/app_bin/forbitapplist.xml";File f = newFile(xmlFile);if(!f.exists()) {Log.e("forbitapplist not exist!");String[] strs = mCtx.getResources().getStringArray(R.array.security_array_savepower_forbitalarms);for(String str : strs) {listPkgs.add(str);}} else{readFromXmlWithFilename(xmlFile, listPkgs);}readFromXml();Set forbitset = (Set)ManagerUtil.getPreferenceValue(mCtx, ManagerUtil.PRE_NAME,ManagerUtil.FORBIT_ALARM_APP_LIST_KEY, null,4);if(forbitset !=null) {Iterator forbitir = forbitset.iterator();while(forbitir.hasNext()) {String forbit = forbitir.next();forbitPkgs.add(forbit);}}Set allowset = (Set)ManagerUtil.getPreferenceValue(mCtx, ManagerUtil.PRE_NAME,ManagerUtil.ALLOW_ALARM_APP_LIST_KEY, null,4);if(allowset !=null) {Iterator allowir = allowset.iterator();while(allowir.hasNext()) {String allow = allowir.next();allowPkgs.add(allow);}}}[java] view plaincopypublicArrayList getListApps() {if(forbitPkgs.size() ==0) {Set forbitset= (Set)ManagerUtil.getPreferenceValue(mCtx, ManagerUtil.PRE_NAME,ManagerUtil.FORBIT_ALARM_APP_LIST_KEY, null,4);if(forbitset ==null) {readFromXml();HashSet forbitPkgsSet = newHashSet();for(String pkg : forbitPkgs) {forbitPkgsSet.add(pkg);}ManagerUtil.savePreferenceValue(mCtx, ManagerUtil.PRE_NAME,ManagerUtil.FORBIT_ALARM_APP_LIST_KEY, forbitPkgsSet, 4);} else{Iterator forbitir = forbitset.iterator();while(forbitir.hasNext()) {String forbit = forbitir.next();forbitPkgs.add(forbit);}}}showPkgs.clear();ArrayList apps = newArrayList();finalList installed = pm.getInstalledPackages(0);String name = null;for(finalPackageInfo appInfo : installed){String pkg = appInfo.packageName;if(listPkgs.contains(pkg)) {DroidApp app = newDroidApp();name = pm.getApplicationLabel(appInfo.applicationInfo).toString();app.name = name;app.icon = appInfo.applicationInfo.loadIcon(pm);if(forbitPkgs.contains(pkg)) {app.online_switch = true;} elseif(allowPkgs.contains(pkg)) {app.online_switch = false;} else{app.online_switch = true;}app.pkg = pkg;apps.add(app);showPkgs.add(pkg);Log.d("in white list and installed package is : "+pkg);} else{已经安装的第三方应用if((appInfo.applicationInfo.uid >10000)&& (appInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0&& (appInfo.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) == 0) {String pkgName = appInfo.packageName;DroidApp app = newDroidApp();app.name = pm.getApplicationLabel(appInfo.applicationInfo).toString();app.icon = appInfo.applicationInfo.loadIcon(pm);app.online_switch = true;if(forbitPkgs.contains(pkg)) {app.online_switch = true;} elseif(allowPkgs.contains(pkg)) {app.online_switch = false;} else{app.online_switch = true;}app.pkg = pkgName;apps.add(app);showPkgs.add(pkgName);Log.d("not in white list and installed third package is : "+pkgName);}}}returnapps;}

[java] view plaincopyprivateclassGetListDataThreadimplementsRunnable {@Overridepublicvoidrun() {// TODO Auto-generated method stubappList = mFbAmLogic.getListApps();resultList.clear();for(DroidApp app : appList) {Log.d("getListApps appname = "+ app.pkg);if(app.online_switch) {if(app.pkg !=null&& app.pkg.length() >0) {resultList.add(app.pkg);saveList.add(app.pkg);}}}Message msg = Message.obtain();msg.what = MSG_SHOWLIST;handler.sendMessage(msg);}}

ForbitAlarmLogic类的getListApps()方法中重新为forbitPkgs数组赋值如果forbitPkgs为空,即在构造方法中没有获取到数据,重新从上面数据库中获取数据;如果仍然是空,则从/data/data/com.***.android.security/app_bin/applist.xml文件中获取,保存到forbitPkgs数组中。

手机管家中显示的对齐唤醒名单主要有:

(1)、forbitapplist.xml文件与已安装应用的交集应用;

(2)、已安装的第三方应用。

流程图如下:

APK响应机制APK在启动之后,就已经设置好了黑白名单,初始化过程就是加载界面的过程。

响应点击事件界面初始化完毕之后,将处于勾选状态的应用保存到两个数组列表:resultList、saveList。响应点击事件时,将应用移除resultList列表,或添加到resultList列表中。

界面退出机制

在onPause()方法中判断resultList与saveList是否相同,如果不相同则重新保存对齐唤醒名单,并通知AlarmManagerService。

[java] view plaincopypublicvoidonPause() {// TODO Auto-generated method stubsuper.onPause();newThread(newRunnable() {@Overridepublicvoidrun() {// TODO Auto-generated method stubbooleanisSameContent =true;for(inti =0; i  forbitPkgs = newArrayList();ForbitAlarmLogic.readFromXmlWithFilename(xmlAppList, forbitPkgs);if(!forbitPkgs.contains(result)) {Log.i(result + "Not In applist.xml");isSameContent = false;break;}if(!saveList.contains(result)) {Log.i(result + "Not In SaveList");isSameContent = false;break;}}} else{Log.i("saveList Changed");isSameContent = false;}if(!isSameContent) {Log.i("ForbitAlarmSetting save Data");mFbAmLogic.saveAlarmAppMap(resultList);}}}).start();}

(1)、如何重新保存名单?

首先,清空allowPkgs和forbitPkgs,即先清空允许启动的应用列表和禁止启动的应用列表。

其次,将禁止唤醒的应用(即界面上处于勾选状态的应用)添加到forbitPkgs中,并写入/data/data/com.***.android.security/app_bin/applist.xml文件中。同时写入对应键值为ManagerUtil.FORBIT_ALARM_APP_LIST_KEY数据库中。

再次,将允许唤醒的应用(界面上没有勾选的应用)添加到allowPkgs中,并写入对应键值为ManagerUtil.ALLOW_ALARM_APP_LIST_KEY数据库中。

最后,通知AlarmManagerService。

(2)、如何通知AlarmManagerService?

上面数据保存完毕后,发送广播:com.***.android.savepower.forbitalarmapplistchanged,通知AlarmManagerService。

[java] view plaincopypublicstaticvoidnotifyFramework(finalContext ctx) {newThread(){publicvoidrun() {try{Thread.sleep(200);Intent intent = newIntent();intent.setAction(ManagerUtil.INTENT_FORBITALARM_LIST_CHANGED);ctx.sendBroadcast(intent);

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐