百度之后竟然发现“关闭双击 Power 打开 Camera 功能”的相关资料,查了下发现原来android 7.1已经帮你实现了双击power按键的逻辑处理,研究了一下,特将这部分的逻辑处理进行说明。
02-26 14:02:32.115 1965 2066 I ActivityManager: START u0 {act=android.media.action.STILL_IMAGE_CAMERA flg=0x14000000 cmp=com.android.camera/.Camera} from uid 10038 on display 0
当启动camera的时候,ActivityManager的log如下,uid显示10038,那么10038到底是哪个应用呢,我们可以通过拉取packages.list文件进行查看。
adb pull /data/system/packages.list .
拉出packages.list文件后查看发现如下,原来是systemUI里面启动的camera。
com.android.systemui 10038 0 /data/user_de/0/com.android.systemui platform:privapp 3002,1023,1015,3001,3006
这下有了方向了,继续查看SystemUI的代码,在SystemUI里面查看启动camera相关的东西,原来是在PhoneStatusBar.java里面。
PhoneStatusBar.java (base\packages\systemui\src\com\android\systemui\statusbar\phone):
@Override
public void onCameraLaunchGestureDetected(int source) {
mLastCameraLaunchSource = source;
if (mStartedGoingToSleep) {
mLaunchCameraOnFinishedGoingToSleep = true;
return;
}
if (!mNotificationPanel.canCameraGestureBeLaunched(
mStatusBarKeyguardViewManager.isShowing() && mExpandedVisible)) {
return;
}
if (!mDeviceInteractive) {
PowerManager pm = mContext.getSystemService(PowerManager.class);
pm.wakeUp(SystemClock.uptimeMillis(), "com.android.systemui:CAMERA_GESTURE");
mStatusBarKeyguardViewManager.notifyDeviceWakeUpRequested();
}
vibrateForCameraGesture();
if (!mStatusBarKeyguardViewManager.isShowing()) {
startActivity(KeyguardBottomAreaView.INSECURE_CAMERA_INTENT,
true /* dismissShade */);
} else {
if (!mDeviceInteractive) {
// Avoid flickering of the scrim when we instant launch the camera and the bouncer
// comes on.
mScrimController.dontAnimateBouncerChangesUntilNextFrame();
mGestureWakeLock.acquire(LAUNCH_TRANSITION_TIMEOUT_MS + 1000L);
}
if (mScreenTurningOn || mStatusBarKeyguardViewManager.isScreenTurnedOn()) {
mNotificationPanel.launchCamera(mDeviceInteractive /* animate */, source);
} else {
// We need to defer the camera launch until the screen comes on, since otherwise
// we will dismiss us too early since we are waiting on an activity to be drawn and
// incorrectly get notified because of the screen on event (which resumes and pauses
// some activities)
mLaunchCameraOnScreenTurningOn = true;
}
}
}
重点是这句
startActivity(KeyguardBottomAreaView.INSECURE_CAMERA_INTENT,
true /* dismissShade */);
那么哪里调到的onCameraLaunchGestureDetected(int source)呢?
StatusBarManagerService.java (base\services\core\java\com\android\server\statusbar):
@Override
public void onCameraLaunchGestureDetected(int source) {
if (mBar != null) {
try {
mBar.onCameraLaunchGestureDetected(source);
} catch (RemoteException e) {
}
}
}
原来是在这里调用过来的,那么继续跟踪。
GestureLauncherService.java (base\services\core\java\com\android\server):
private boolean handleCameraLaunchGesture(boolean useWakelock, int source) {
boolean userSetupComplete = Settings.Secure.getIntForUser(mContext.getContentResolver(),
Settings.Secure.USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0;
if (!userSetupComplete) {
if (DBG) Slog.d(TAG, String.format(
"userSetupComplete = %s, ignoring camera launch gesture.",
userSetupComplete));
return false;
}
if (DBG) Slog.d(TAG, String.format(
"userSetupComplete = %s, performing camera launch gesture.",
userSetupComplete));
if (useWakelock) {
// Make sure we don't sleep too early
mWakeLock.acquire(500L);
}
StatusBarManagerInternal service = LocalServices.getService(
StatusBarManagerInternal.class);
service.onCameraLaunchGestureDetected(source);
return true;
}
我们跟踪到了GestureLauncherService.java这个类中,这里面会获取StatusBar的系统服务,然后调用onCameraLaunchGestureDetected方法。
PhoneWindowManager.java (base\services\core\java\com\android\server\policy):
private void interceptPowerKeyDown(KeyEvent event, boolean interactive) {
// Hold a wake lock until the power key is released.
if (!mPowerKeyWakeLock.isHeld()) {
mPowerKeyWakeLock.acquire();
}
// Cancel multi-press detection timeout.
if (mPowerKeyPressCounter != 0) {
mHandler.removeMessages(MSG_POWER_DELAYED_PRESS);
}
// Detect user pressing the power button in panic when an application has
// taken over the whole screen.
boolean panic = mImmersiveModeConfirmation.onPowerKeyDown(interactive,
SystemClock.elapsedRealtime(), isImmersiveMode(mLastSystemUiFlags),
isNavBarEmpty(mLastSystemUiFlags));
if (panic) {
mHandler.post(mHiddenNavPanic);
}
// Latch power key state to detect screenshot chord.
if (interactive && !mScreenshotChordPowerKeyTriggered
&& (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
mScreenshotChordPowerKeyTriggered = true;
mScreenshotChordPowerKeyTime = event.getDownTime();
interceptScreenshotChord();
}
// Stop ringing or end call if configured to do so when power is pressed.
TelecomManager telecomManager = getTelecommService();
boolean hungUp = false;
if (telecomManager != null) {
if (telecomManager.isRinging()) {
// Pressing Power while there's a ringing incoming
// call should silence the ringer.
telecomManager.silenceRinger();
} else if ((mIncallPowerBehavior
& Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) != 0
&& telecomManager.isInCall() && interactive) {
// Otherwise, if "Power button ends call" is enabled,
// the Power button will hang up any current active call.
hungUp = telecomManager.endCall();
}
}
GestureLauncherService gestureService = LocalServices.getService(
GestureLauncherService.class);
boolean gesturedServiceIntercepted = false;
if (gestureService != null) {
gesturedServiceIntercepted = gestureService.interceptPowerKeyDown(event, interactive,
mTmpBoolean);
if (mTmpBoolean.value && mGoingToSleep) {
mCameraGestureTriggeredDuringGoingToSleep = true;
}
}
// If the power key has still not yet been handled, then detect short
// press, long press, or multi press and decide what to do.
mPowerKeyHandled = hungUp || mScreenshotChordVolumeDownKeyTriggered
|| mScreenshotChordVolumeUpKeyTriggered || gesturedServiceIntercepted;
if (!mPowerKeyHandled) {
if (interactive) {
// When interactive, we're already awake.
// Wait for a long press or for the button to be released to decide what to do.
if (hasLongPressOnPowerBehavior()) {
Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS);
msg.setAsynchronous(true);
mHandler.sendMessageDelayed(msg,
ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
}
} else {
wakeUpFromPowerKey(event.getDownTime());
if (mSupportLongPressPowerWhenNonInteractive && hasLongPressOnPowerBehavior()) {
Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS);
msg.setAsynchronous(true);
mHandler.sendMessageDelayed(msg,
ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
mBeganFromNonInteractive = true;
} else {
final int maxCount = getMaxMultiPressPowerCount();
if (maxCount <= 1) {
mPowerKeyHandled = true;
} else {
mBeganFromNonInteractive = true;
}
}
}
}
}
gesturedServiceIntercepted = gestureService.interceptPowerKeyDown(event, interactive, mTmpBoolean);
PhoneWindowManager.java (base\services\core\java\com\android\server\policy):
/** {@inheritDoc} */
@Override
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
......
// Handle special keys.
switch (keyCode) {
......
case KeyEvent.KEYCODE_POWER: {
result &= ~ACTION_PASS_TO_USER;
isWakeKey = false; // wake-up will be handled separately
if (down) {
interceptPowerKeyDown(event, interactive);
} else {
interceptPowerKeyUp(event, interactive, canceled);
}
break;
}
......
}
if (useHapticFeedback) {
performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false);
}
if (isWakeKey) {
wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey, "android.policy:KEY");
}
return result;
}
GestureLauncherService.java (base\services\core\java\com\android\server):
public boolean interceptPowerKeyDown(KeyEvent event, boolean interactive,
MutableBoolean outLaunched) {
boolean launched = false;
boolean intercept = false;
long doubleTapInterval;
synchronized (this) {
doubleTapInterval = event.getEventTime() - mLastPowerDown;
if (mIsEmergencyOnPowerKeyTapEnabled) {
//mIsEmergencyOnPowerKeyTapEnabled的值可以用来enable或disable三击的功能
System.arraycopy(mHits, 1, mHits, 0, mHits.length-1);
mHits[mHits.length-1] = SystemClock.uptimeMillis();
for (int i = 0 ; i < mHits.length ; i++) {
Slog.i(TAG, "mHits[" + i + "] = " + mHits[i] + "ms");
}
if (mHits[0] >=
(SystemClock.uptimeMillis()-mDuration)) {
//此处是对三击的时间进行判断,利用一个array来存储每次点击down的时间,然后进行判断是否在mDuration时间之类连续点击了3次。
launched = true;
intercept = interactive;
Arrays.fill(mHits,0);
}
} else if (mCameraDoubleTapPowerEnabled//mCameraDoubleTapPowerEnabled的值可以用来enable或disable双击启动camera的功能
&& doubleTapInterval < CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS) {
launched = true;
intercept = interactive;
}
mLastPowerDown = event.getEventTime();
}
if (launched) {
if (mIsEmergencyOnPowerKeyTapEnabled &&
!TextUtils.isEmpty(mEmergencyNumber)) {
Slog.i(TAG, "Power button Triple tap gesture detected, launching Emergency Call");
Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED,
Uri.fromParts("tel", mEmergencyNumber, null));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
getContext().startActivityAsUser(intent, UserHandle.CURRENT);
} else {
Slog.i(TAG, "Power button double tap gesture detected, launching camera. Interval="
+ doubleTapInterval + "ms");
launched = handleCameraLaunchGesture(false /* useWakelock */,
StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP);
if (launched) {
MetricsLogger.action(mContext,
MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE,
(int) doubleTapInterval);
}
}
}
MetricsLogger.histogram(mContext, "power_double_tap_interval", (int) doubleTapInterval);
outLaunched.value = launched;
return intercept && launched;
}