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

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

双击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);
    }
}

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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,377评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,390评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,967评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,344评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,441评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,492评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,497评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,274评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,732评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,008评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,184评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,837评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,520评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,156评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,407评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,056评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,074评论 2 352

推荐阅读更多精彩内容