最近項目中接觸到需要修改手機(jī)按鍵的需求,整理一下分享給大家
雙擊power鍵大概流程
PhoneWindowManager.java類是 處理各種 power 鍵流程的地方奔浅,路徑如下:
\frameworks\base\services\core\java\com\android\server\policy\PhoneWindowManager.java
關(guān)鍵代碼:
case KeyEvent.KEYCODE_POWER: {
EventLogTags.writeInterceptPower(
KeyEvent.actionToString(event.getAction()),
mPowerKeyHandled ? 1 : 0,
mSingleKeyGestureDetector.getKeyPressCounter(KeyEvent.KEYCODE_POWER));
// Any activity on the power button stops the accessibility shortcut
result &= ~ACTION_PASS_TO_USER;
isWakeKey = false; // wake-up will be handled separately
if (down) {
/*SPRD : add power debug log start*/
Slog.d(TAG, "Receive Input KeyEvent of Powerkey down");
/*SPRD : add power debug log end*/
interceptPowerKeyDown(event, interactiveAndOn);
} else {
/*SPRD : add power debug log start*/
Slog.d(TAG, "Receive Input KeyEvent of Powerkey up");
/*SPRD : add power debug log end*/
interceptPowerKeyUp(event, canceled);
}
break;
}
power鍵按下在interceptPowerKeyDown()執(zhí)行,松開的操作在interceptPowerKeyUp()中執(zhí)行interceptPowerKeyDown()方法中會調(diào)用GestureLauncherService.java的 interceptPowerKeyDown()方法
關(guān)鍵代碼:
// The camera gesture will be detected by GestureLauncherService.
private boolean handleCameraGesture(KeyEvent event, boolean interactive) {
// camera gesture.
if (mGestureLauncherService == null) {
return false;
}
mCameraGestureTriggered = false;
final MutableBoolean outLaunched = new MutableBoolean(false);
final boolean intercept =
mGestureLauncherService.interceptPowerKeyDown(event, interactive, outLaunched);
if (!outLaunched.value) {
// If GestureLauncherService intercepted the power key, but didn't launch camera app,
// we should still return the intercept result. This prevents the single key gesture
// detector from processing the power key later on.
return intercept;
}
mCameraGestureTriggered = true;
if (mRequestedOrSleepingDefaultDisplay) {
mCameraGestureTriggeredDuringGoingToSleep = true;
}
return true;
}
跟蹤看看GestureLauncherService.java 中 執(zhí)行 interceptPowerKeyDown()方法如下
GestureLauncherService.java诗良,路徑如下:
/frameworks/base/services/core/java/com/android/server/GestureLauncherService.java
關(guān)鍵代碼:
public boolean interceptPowerKeyDown(KeyEvent event, boolean interactive,
MutableBoolean outLaunched, boolean isScreenOn) {
if (event.isLongPress()) {
// Long presses are sent as a second key down. If the long press threshold is set lower
// than the double tap of sequence interval thresholds, this could cause false double
// taps or consecutive taps, so we want to ignore the long press event.
return false;
}
boolean launchCamera = false;
boolean launchEmergencyGesture = false;
boolean intercept = false;
long powerTapInterval;
synchronized (this) {
powerTapInterval = event.getEventTime() - mLastPowerDown;
mLastPowerDown = event.getEventTime();
if (powerTapInterval >= POWER_SHORT_TAP_SEQUENCE_MAX_INTERVAL_MS) {
// Tap too slow, reset consecutive tap counts.
mPowerButtonConsecutiveTaps = 1;
mPowerButtonSlowConsecutiveTaps = 1;
} else if (powerTapInterval >= CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS) {
// Tap too slow for shortcuts
mPowerButtonConsecutiveTaps = 1;
mPowerButtonSlowConsecutiveTaps++;
} else {
// Fast consecutive tap
mPowerButtonConsecutiveTaps++;
mPowerButtonSlowConsecutiveTaps++;
}
// Check if we need to launch camera or emergency gesture flows
if (mEmergencyGestureEnabled) {
// Commit to intercepting the powerkey event after the second "quick" tap to avoid
// lockscreen changes between launching camera and the emergency gesture flow.
if (mPowerButtonConsecutiveTaps > 1) {
intercept = interactive;
}
if (mPowerButtonConsecutiveTaps == EMERGENCY_GESTURE_POWER_TAP_COUNT_THRESHOLD) {
launchEmergencyGesture = true;
}
}
if (mCameraDoubleTapPowerEnabled
&& powerTapInterval < CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS
&& mPowerButtonConsecutiveTaps == CAMERA_POWER_TAP_COUNT_THRESHOLD) {
launchCamera = true;
intercept = interactive;
}
}
if (mPowerButtonConsecutiveTaps > 1 || mPowerButtonSlowConsecutiveTaps > 1) {
Slog.i(TAG, Long.valueOf(mPowerButtonConsecutiveTaps)
+ " consecutive power button taps detected, "
+ Long.valueOf(mPowerButtonSlowConsecutiveTaps)
+ " consecutive slow power button taps detected");
}
if (launchCamera) {
Slog.i(TAG, "Power button double tap gesture detected, launching camera. Interval="
+ powerTapInterval + "ms");
// 調(diào)用開啟相機(jī)
launchCamera = handleCameraGesture(false /* useWakelock */,
StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP);
if (launchCamera) {
mMetricsLogger.action(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE,
(int) powerTapInterval);
mUiEventLogger.log(GestureLauncherEvent.GESTURE_CAMERA_DOUBLE_TAP_POWER);
}
} else if (launchEmergencyGesture) {
Slog.i(TAG, "Emergency gesture detected, launching.");
launchEmergencyGesture = handleEmergencyGesture();
mUiEventLogger.log(GestureLauncherEvent.GESTURE_EMERGENCY_TAP_POWER);
}
mMetricsLogger.histogram("power_consecutive_short_tap_count",
mPowerButtonSlowConsecutiveTaps);
mMetricsLogger.histogram("power_double_tap_interval", (int) powerTapInterval);
outLaunched.value = launchCamera || launchEmergencyGesture;
// Intercept power key event if the press is part of a gesture (camera, eGesture) and the
// user has completed setup.
return intercept && isUserSetupComplete();
}
系統(tǒng)會對mCameraDoubleTapPowerEnabled 取值汹桦,核心是通過resources.getBoolean(com.android.internal.R.bool.config_cameraDoubleTapPowerGestureEnabled) 來取,
其實這個值是配置在/frameworks/base/core/res/res/values/config.xml中鉴裹,這里是為true的
<!-- Allow the gesture to double tap the power button twice to start the camera while the device
is non-interactive. -->
<bool name="config_cameraDoubleTapPowerGestureEnabled">true</bool>
接下來會分別對power連續(xù)按2或者1次進(jìn)行判斷舞骆,如果mCameraDoubleTapPowerEnabled = true 會通過比較按鍵的時間powerTapInterval小于系統(tǒng)默認(rèn)時間(CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS=300毫秒),
mPowerButtonConsecutiveTaps計數(shù)加1,說明連續(xù)按power鍵径荔,或者延遲最大500毫秒內(nèi)連續(xù)按鍵督禽,系統(tǒng)預(yù)計用戶接下來可能會執(zhí)行一些操作,計數(shù)也會加1
static final long POWER_SHORT_TAP_SEQUENCE_MAX_INTERVAL_MS = 500;
static final long CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS = 300;
powerTapInterval = event.getEventTime() - mLastPowerDown;
mLastPowerDown = event.getEventTime();
if (mCameraDoubleTapPowerEnabled
&& powerTapInterval < CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS
&& mPowerButtonConsecutiveTaps == CAMERA_POWER_TAP_COUNT_THRESHOLD)
if (powerTapInterval < POWER_SHORT_TAP_SEQUENCE_MAX_INTERVAL_MS)
執(zhí)行完成之后會調(diào)用handleCameraGesture()方法調(diào)用開啟攝像機(jī)总处。
@VisibleForTesting
boolean handleCameraGesture(boolean useWakelock, int source) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "GestureLauncher:handleCameraGesture");
try {
boolean userSetupComplete = isUserSetupComplete();
if (!userSetupComplete) {
if (DBG) {
Slog.d(TAG, String.format(
"userSetupComplete = %s, ignoring camera gesture.",
userSetupComplete));
}
return false;
}
if (DBG) {
Slog.d(TAG, String.format(
"userSetupComplete = %s, performing camera gesture.",
userSetupComplete));
}
if (useWakelock) {
// Make sure we don't sleep too early
mWakeLock.acquire(500L);
}
StatusBarManagerInternal service = LocalServices.getService(
StatusBarManagerInternal.class);
// 啟動相機(jī)
service.onCameraLaunchGestureDetected(source);
return true;
} finally {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
}
原生雙擊啟動相機(jī)流程差不多就是這樣狈惫,有任何問題歡迎留言討論