Android开发笔记(一百一十七)app省电方略

2019-07-14 01:54发布

电源管理PowerManager

PowerManager是Android的电源管理类,用于管理电源操作如睡眠、唤醒、重启以及调节屏幕亮度等等。
PowerManager的对象从系统服务POWER_SERVICE中获取,它的主要方法如下:
goToSleep : 睡眠,即锁屏。
wakeUp : 唤醒,即解锁。
reboot : 重启。
另有下列几个隐藏的方法:
getMinimumScreenBrightnessSetting : 获取屏幕亮度的最小值。
getMaximumScreenBrightnessSetting : 获取屏幕亮度的最大值。
getDefaultScreenBrightnessSetting : 获取屏幕亮度的默认值。
setBacklightBrightness : 设置屏幕亮度。


但对多数开发者来说,PowerManager在实际开发中毫无用处,因为一旦调用该类的方法,你的app运行时就会崩溃,查看日志报错“java.lang.SecurityException: Neither user 10150 nor current process has android.permission.DEVICE_POWER.”这个错误信息倒是容易看懂,好吧,那我便在AndroidManifest.xml中加上DEVICE_POWER的权限。可是加了权限之后,ADT又提示错误“Permission is only granted to system apps”。这下傻眼了,怎么会说“权限只授予系统应用程序”呢?不过这难不倒我,咱把app工程clean一下,错误提示就不见了,然后重新Run之,结果Console栏出现红 {MOD}文字“Installation error: INSTALL_FAILED_SHARED_USER_INCOMPATIBLE”,还是不行呀。
找了大量的资料,才发现这是因为电源管理的权限,只有系统程序(打了系统签名)才可以获得,用户程序无法获取这个权限。大伙对该问题基本是束手无策,只有Stack Overflow上的大神给了个解决方案,主要做三方面的修改:
1、在AndroidManifest.xml中加上DEVICE_POWER、REBOOT、SHUTDOWN的权限。
2、在AndroidManifest.xml的manifest节点中增加属性说明“android:sharedUserId="android.uid.system"”,这表示使用系统用户的uid。
3、为了能够共享系统用户的uid,你的app得采用系统签名打包,即先找到目标Android系统的platform.pk8和platform.x509.pem密钥文件,然后使用signapk.jar将apk签名到指定密钥。
这个解决方案理论上可行,但就真机来说,每个品牌每个型号的手机,其系统签名都是不一样的。因此,就算你真的搞出来一个系统应用,那也仅适用于该签名版本的Android系统,而不能用于其他签名的Android系统,所以PowerManager只能是手机厂商内部使用了。


下面是PowerManager几个用途的示例代码(一般用不到,仅供参考):
[java] view plain copy  在CODE上查看代码片派生到我的代码片
  1. import java.lang.reflect.Field;  
  2. import java.lang.reflect.Method;  
  3.   
  4. import android.annotation.TargetApi;  
  5. import android.content.Context;  
  6. import android.content.Intent;  
  7. import android.os.Build;  
  8. import android.os.IBinder;  
  9. import android.os.PowerManager;  
  10. import android.os.SystemClock;  
  11. import android.util.Log;  
  12.   
  13. //注意,PowerManager只有系统应用才能操作,普通应用不能操作,所以下面代码仅供参考  
  14. public class PowerUtil {  
  15.       
  16.     private final static String TAG = "PowerUtil";  
  17.       
  18.     private static int getValue(Context ctx, String methodName, int defValue) {  
  19.         int value = defValue;  
  20.         PowerManager pm = (PowerManager) ctx.getSystemService(Context.POWER_SERVICE);  
  21.         try {  
  22.             Class pmClass = Class.forName(pm.getClass().getName());  
  23.             Field field = pmClass.getDeclaredField("mService");  
  24.             field.setAccessible(true);  
  25.             Object iPM = field.get(pm);  
  26.             Class iPMClass = Class.forName(iPM.getClass().getName());  
  27.             Method method = iPMClass.getDeclaredMethod(methodName);  
  28.             method.setAccessible(true);  
  29.             value = (Integer) method.invoke(iPM);  
  30.         } catch (Exception e) {  
  31.             e.printStackTrace();  
  32.         }  
  33.         Log.d(TAG, "methodName="+methodName+", value="+value);  
  34.         return value;  
  35.     }  
  36.   
  37.     public static int getMinLight(Context ctx) {  
  38.         return getValue(ctx, "getMinimumScreenBrightnessSetting"0);  
  39.     }  
  40.   
  41.     public static int getMaxLight(Context ctx) {  
  42.         return getValue(ctx, "getMaximumScreenBrightnessSetting"255);  
  43.     }  
  44.   
  45.     public static int getDefLight(Context ctx) {  
  46.         return getValue(ctx, "getDefaultScreenBrightnessSetting"100);  
  47.     }  
  48.       
  49.     //设置屏幕亮度。light取值0-255  
  50.     public static void setLight(Context ctx, int light) {  
  51.         PowerManager pm = (PowerManager) ctx.getSystemService(Context.POWER_SERVICE);  
  52.         try {  
  53.             Class pmClass = Class.forName(pm.getClass().getName());  
  54.             // 得到PowerManager类中的成员mService(mService为PowerManagerService类型)  
  55.             Field field = pmClass.getDeclaredField("mService");  
  56.             field.setAccessible(true);  
  57.             // 实例化mService  
  58.             Object iPM = field.get(pm);  
  59.             // 得到PowerManagerService对应的Class对象  
  60.             Class iPMClass = Class.forName(iPM.getClass().getName());  
  61.             /* 
  62.              * 得到PowerManagerService的函数setBacklightBrightness对应的Method对象, 
  63.              * PowerManager的函数setBacklightBrightness实现在PowerManagerService中 
  64.              */  
  65.             Method method = iPMClass.getDeclaredMethod("setBacklightBrightness"int.class);  
  66.             method.setAccessible(true);  
  67.             // 调用实现PowerManagerService的setBacklightBrightness  
  68.             method.invoke(iPM, light);  
  69.         } catch (Exception e) {  
  70.             e.printStackTrace();  
  71.         }  
  72.     }  
  73.       
  74.     public static void resetLight(Context ctx, int light) {  
  75.         try {  
  76.             Object power;  
  77.             Class  ServiceManager = Class.forName("android.os.ServiceManager");  
  78.             Class  Stub = Class.forName("android.os.IPowerManager$Stub");  
  79.   
  80.             Method getService = ServiceManager.getMethod("getService"new Class[] {String.class});  
  81.             //Method asInterface = GetStub.getMethod("asInterface", new Class[] {IBinder.class});//of this class?  
  82.             Method asInterface = Stub.getMethod("asInterface"new Class[] {IBinder.class});    //of this class?  
  83.             IBinder iBinder = (IBinder) getService.invoke(nullnew Object[] {Context.POWER_SERVICE});//  
  84.             power = asInterface.invoke(null,iBinder);