美文网首页
Android 12 双击power键启动相机源码解析

Android 12 双击power键启动相机源码解析

作者: 龙之叶 | 来源:发表于2022-09-06 21:55 被阅读0次

    最近项目中接触到需要修改手机按键的需求,整理一下分享给大家

    双击power键大概流程

    PhoneWindowManager.java类是 处理各种 power 键流程的地方,路径如下:

    \frameworks\base\services\core\java\com\android\server\policy\PhoneWindowManager.java
    

    关键代码:

    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()执行,松开的操作在interceptPowerKeyUp()中执行interceptPowerKeyDown()方法中会调用GestureLauncherService.javainterceptPowerKeyDown()方法
    关键代码:

    // 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 中 执行 interceptPowerKeyDown()方法如下
    GestureLauncherService.java,路径如下:

    /frameworks/base/services/core/java/com/android/server/GestureLauncherService.java
    

    关键代码:

    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");
                    // 调用开启相机
                    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();
        }
    

    系统会对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连续按2或者1次进行判断,如果mCameraDoubleTapPowerEnabled = true 会通过比较按键的时间powerTapInterval小于系统默认时间(CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS=300毫秒),
    mPowerButtonConsecutiveTaps计数加1,说明连续按power键,或者延迟最大500毫秒内连续按键,系统预计用户接下来可能会执行一些操作,计数也会加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)
    

    执行完成之后会调用handleCameraGesture()方法调用开启摄像机。

    @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);
            // 启动相机
            service.onCameraLaunchGestureDetected(source);
            return true;
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        }
    }
    

    原生双击启动相机流程差不多就是这样,有任何问题欢迎留言讨论

    相关文章

      网友评论

          本文标题:Android 12 双击power键启动相机源码解析

          本文链接:https://www.haomeiwen.com/subject/seninrtx.html