Android有個很有趣的現象,公開的API把系統進入suspend的功能移除了,開發者想讓Android機器進入suspend狀態,必須使用reflect機制(這種感覺,極爲類似N多年前有一本書專門介紹Windows未公開的API )。
不明白Google爲什麼這麼做,唯一的猜測,是爲了安全考慮。但是,對於某些應用場景,還是需要程序控制Suspend/resume的。
下面簡單介紹其使用,
1. 如果需要使用suspend/resume功能,需要在AndroidManifest.xml聲明獲得“DEVICE_POWER”權限和系統權限,示例代碼如下,
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.testsuspend"
android:sharedUserId="android.uid.system">
<application
...
</application>
<uses-permission android:name="android.permission.DEVICE_POWER" />
</manifest>
2. 僅僅聲明權限是不夠的,要想擁有system權限,還需要sign,每一款產品的sign key都不一樣,這就造成,即使可以在某一款產品上運行,在其他產品上也是無法運行的(需要使用該產品的sign key重新sign)。
另外,還有一種方法,直接把apk push到文件夾“/system/priv-app/”下,這種方法我沒有嘗試,我一般使用sign key的方式。
adb remount
adb push xxx.apk /system/priv-app/
adb reboot
3. 下面是代碼實現部分,僅供參考,
進入suspend/sleep的代碼段如下,
public static void goToSleep(Context context) {
PowerManager powerManager= (PowerManager)context.getSystemService(Context.POWER_SERVICE);
try {
powerManager.getClass().getMethod("goToSleep", new Class[]{long.class}).invoke(powerManager, SystemClock.uptimeMillis());
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
屏幕喚醒的代碼段如下,
public static void wakeUp(Context context) {
PowerManager powerManager= (PowerManager)context.getSystemService(Context.POWER_SERVICE);
try {
powerManager.getClass().getMethod("wakeUp", new Class[]{long.class}).invoke(powerManager, SystemClock.uptimeMillis());
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
4. 如果不使用上面的reflect方法,還有沒有其他方法?
據我所查,還有一種不是特別好的方法,即降低SDK版本到20以下,需要做如下更改,
4.1 build.gradle中請指定SDK版本爲20以下,參考如下代碼,注意“compileSdkVersion”已經更改爲20,
apply plugin: 'com.android.application'
android {
compileSdkVersion 20
buildToolsVersion "23.0.2"
defaultConfig {
applicationId "com.example.suspendresume"
minSdkVersion 14
targetSdkVersion 17
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
}
}
dependencies {
}
4.2 請在AndroidManifest.xml聲明獲得“DEVICE_POWER”權限和系統權限, 安裝apk前需要sign。
4.3 不使用reflect方式的參考代碼如下,
private static void enterSuspend(Context context){
PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
pm.goToSleep(SystemClock.uptimeMillis());
}
5. 如果有該平臺的BSP代碼,也可以把自己的代碼放到BSP中編譯,然後直接包進system image,會省去reflect和sign的動作,不過debug稍微麻煩。
好了,關於奇怪的goToSleep就分享這麼多,希望能爲有需要的童鞋提供幫助。