需求简介
设备在息屏的状态下,通过特定的物理按键去启动Camera应用。
分析
设备在息屏状态下(系统处于休眠),直接通过startActivity方法去启动应用是无效的。
所以将需求的实现应该分为两步:
1、点亮屏幕(唤醒系统);
2、通过startActivity方法启动App;
1、点亮屏幕
我对这个需求的实现代码是写在frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java 中的。
PowerManager mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
private void lightScreen(String keyName){
if (!mPowerManager.isScreenOn()) {
mPowerManager.wakeUp(SystemClock.uptimeMillis());
}
}
2、通过startActivity方法启动App
需要判断一下设备是否处于锁屏状态,因为不同状态下启动App所用到的action是不同的。
//CAMERA_PACKAGE_NAME 为camera应用的包名
private final String CAMERA_PACKAGE_NAME = "com.app.camera";
private void launchApp(){
Intent intent;
if (isOnLockScreenPage()) {
intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE)
.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
startActivityAsUser(intent, UserHandle.CURRENT_OR_SELF);
//startActivityAsUser是PhoneWindowManager中的已有方法
} else {
intent = mContext.getPackageManager().getLaunchIntentForPackage(CAMERA_PACKAGE_NAME);
intent.setAction(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
startActivityAsUser(intent, UserHandle.CURRENT_OR_SELF);
}
}
//判断设备是否处于锁屏状态
private boolean isOnLockScreenPage(){
KeyguardManager mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
return mKeyguardManager.inKeyguardRestrictedInputMode();
}
启动失败问题
在设备处于锁屏且息屏的状态下,通过物理按键事件启动Camera App存在概率性失败的bug。
原因
因为在唤醒系统后即刻执行Camera相应组件的初始化操作,耗费的时间比正常状态下要久一些,而系统在frameworks/base/services/core/java/com/android/server/am/ActivityStack.java中对App的响应做了一个时间限制(500ms),超过该时间会认为启动的App是未响应状态,从而取消对该App的启动。
我所用设备从息屏状态下启动的Camera的响应时间估计在500ms上下,所以导致概率性失败的问题。
解决
在ActivityStack.java的schedulePauseTimeout中对从息屏状态下启动Camera的情况,适当的延长了响应超时时间。
/**
* Schedule a pause timeout in case the app doesn't respond. We don't give it much time because
* this directly impacts the responsiveness seen by the user.
*/
private void schedulePauseTimeout(ActivityRecord r) {
final Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
msg.obj = r;
r.pauseTime = SystemClock.uptimeMillis();
//属性persist.sys.camera_prop在息屏状态下启动Camera的时候设置为true
if (SystemProperties.getBoolean("persist.sys.camera_prop", false)) {
mHandler.sendMessageDelayed(msg, 1000);
SystemProperties.set("persist.sys.camera_prop", "0");
} else {
//PAUSE_TIMEOUT = 500
mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
}
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Waiting for pause to complete...");
}