Power按键流程分析

Posted zhenjie_chang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Power按键流程分析相关的知识,希望对你有一定的参考价值。

从InputManagerService分析我们知道,当按下手机的Power键之后,按键事件会传到InputDispatcher 的notifyKey 方法,然后调用到调用了NativeInputManager的interceptKeyBeforeQueueing函数,最终在这个函数中会调用到PhoneWindowManager中的interceptKeyBeforeQueueing函数,以上主要属于InputManagerService的范畴,Power按键流程我们从PhoneWindowManager 的interceptKeyBeforeQueueing 方法开始分析。

方法interceptKeyBeforeQueueing关键步骤:

第一步:初始化关键变量

if (!mSystemBooted) 
            return 0;
        

        final boolean interactive = (policyFlags & FLAG_INTERACTIVE) != 0;
        final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
        final boolean canceled = event.isCanceled();
        final int keyCode = event.getKeyCode();

        final boolean isInjected = (policyFlags & WindowManagerPolicy.FLAG_INJECTED) != 0;

首先判断系统是否启动完成,然后就是初始化一些关键变量

Interactive 表示屏幕是否点亮,这个变量表示PowerManagerService关于屏幕的状态

Down 表示是否是ActionDown事件

Canceled 事件是否取消

keyCode 按键编码

第二步,根据interative的状态的处理一些基本逻辑

if (interactive || (isInjected && !isWakeKey)) 
            //事件传递给用户
            result = ACTION_PASS_TO_USER;
            isWakeKey = false;
         else if (!interactive && shouldDispatchInputWhenNonInteractive()) 
            result = ACTION_PASS_TO_USER;
         else 
            
            result = 0;
            if (isWakeKey && (!down || !isWakeKeyWhenScreenOff(keyCode))) 
                isWakeKey = false;
            
        
        if (isValidGlobalKey(keyCode)
                && mGlobalKeyManager.shouldHandleGlobalKey(keyCode, event)) 
            if (isWakeKey) 
                //直接唤醒系统
                wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey, " android.policy:KEY");
            
            return result;
        

第三步,处理Power按键的事件

case KeyEvent.KEYCODE_POWER: 
                result &= ~ACTION_PASS_TO_USER;
                isWakeKey = false; // wake-up will be handled separately
                if (down) 
                    Power键按下
                    interceptPowerKeyDown(event, interactive);
                 else 
                    Power键释放
                    interceptPowerKeyUp(event, interactive, canceled);
                
                break;
            

首先是Power按键的事件的话,不再分发到应用,如果是ActionDown事件执行InterceptPowerKeyDown()方法,如果是ActionUP事件则执行InterceptPowerKeyUp()方法

下一步继续分析interceptPowerKeyDown方法

private void interceptPowerKeyDown(KeyEvent event, boolean interactive) 
        
        if (!mPowerKeyWakeLock.isHeld()) 
            mPowerKeyWakeLock.acquire();
        

获取Power按键的锁,直到释放Power键

……  

if (interactive && !mScreenshotChordPowerKeyTriggered
                && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) 
            mScreenshotChordPowerKeyTriggered = true;
            mScreenshotChordPowerKeyTime = event.getDownTime();
            interceptScreenshotChord();
        

如果当前是亮屏状态,且满足触发截屏的条件,触发截屏功能

TelecomManager telecomManager = getTelecommService();
        boolean hungUp = false;
        if (telecomManager != null) 
            if (telecomManager.isRinging()) 
             
                telecomManager.silenceRinger();
             else if ((mIncallPowerBehavior
                    & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) != 0
                    && telecomManager.isInCall() && interactive) 
  
                hungUp = telecomManager.endCall();
            
        

如果有电话拨入,且电话铃声响起的话,这个时候按Power键,设置电话响铃静音

如果正在接听电话,且配置了Power键挂断电话的话,按Power按键挂断正在接听的电话

       ……

mPowerKeyHandled = hungUp || mScreenshotChordVolumeDownKeyTriggered
                || mScreenshotChordVolumeUpKeyTriggered || gesturedServiceIntercepted;

如果按Power按键执行了截图功能或者电话静音或者挂断电话等功能后,Power事件不在传递,表示已经消耗掉了Power事件 

if (!mPowerKeyHandled) 

如果未消耗掉Power事件,继续执行此处逻辑

分为两种情况

1, 当前是亮屏状态

2, 当前是灭屏状态

if (interactive) 
                //是否支持长按功能
                if (hasLongPressOnPowerBehavior()) 
                    Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS);
                    msg.setAsynchronous(true);
                    //发送MSG_POWER_LONG_PRESS消息,有Handler来处理
                    mHandler.sendMessageDelayed(msg,
                            ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
                
             else 
                  //当前灭屏状态,此时按Power键,先唤醒系统
                   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;
                    
                
            
        
    

当前亮屏状态

首先判断是否支持长按的行为

先来看看hasLongPressOnPowerBehavior函数

private boolean hasLongPressOnPowerBehavior() 
        return getResolvedLongPressOnPowerBehavior() != LONG_PRESS_POWER_NOTHING;
    

再来看看getResolvedLongPressOnPowerBehavior函数

private int getResolvedLongPressOnPowerBehavior() 
        if (FactoryTest.isLongPressOnPowerOffEnabled()) 
            return LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM;
        
        return mLongPressOnPowerBehavior;

由于systemProperty中的factory.long_press_power_off" 配置为0,所以不支持灭屏长按功能,。因此只要看mLongPressOnPowerBehavior这个变量

mLongPreesOnPowerBehavior 默认配置获取为

mLongPressOnPowerBehavior = mContext.getResources().getInteger(
               com.android.internal.R.integer.config_longPressOnPowerBehavior);

config_longPressOnPowerBehavior 默认值为1,所以 mLongPressOnPowerBehavior  = 1, 最后hasLongPressOnPowerBehavior返回 true


if (hasLongPressOnPowerBehavior()) 
                    Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS);
                    msg.setAsynchronous(true);
                    mHandler.sendMessageDelayed(msg,
                            ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
                

hasLongPressOnPowerBehavior返回true,则发送MSG_POWER_LONG_PRESS的Handler消息,Handler处理消息调用 powerLongPress()方法,接着我们来看下Handler处理消息的逻辑

private void powerLongPress() 
        final int behavior = getResolvedLongPressOnPowerBehavior();
        switch (behavior) 
        case LONG_PRESS_POWER_NOTHING:
            break;
        case LONG_PRESS_POWER_GLOBAL_ACTIONS:
            mPowerKeyHandled = true;
            if (!performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false)) 
                performAuditoryFeedbackForAccessibilityIfNeed();
            
            showGlobalActionsInternal();
            break;
       ……

由以上的分析指导getResolvedLongPressOnPowerBehavior的值为1,所以执行case LONG_PRESS_POWER_GLOBAL_ACTIONS,

mPowerKeyHandled的值设置为true,表示处理了PowerDown事件,showGlobalActionsInternal()方法弹出关机,重启对话框

1. 当屏幕是灭屏状态

首先执行wakeUpFromPowerKey方法,唤醒手机系统,最终调用mPowerManager.wakeUp(wakeTimereason)来唤醒手机

然后mSupportLongPressPowerWhenNonInteractive默认不支持,所以默认执行

final int maxCount = getMaxMultiPressPowerCount();
              if (maxCount <= 1) 
                    mPowerKeyHandled = true;
                else 
                    mBeganFromNonInteractive = true;
               

getMaxMultiPressPowerCount() ==1,默认不支持对此按键,所以将mPowerKeyHandled设置为true,表示处理了PowerDown事件
2,处理PowerUp事件
PowerUp事件也分为两种情况,分别对应PowerDown的亮屏和灭屏两种情况

private void interceptPowerKeyUp(KeyEvent event, boolean interactive, boolean canceled) 
        final boolean handled = canceled || mPowerKeyHandled;
      ……
        if (!handled) 
            mPowerKeyPressCounter += 1;
            final int maxCount = getMaxMultiPressPowerCount();
            final long eventTime = event.getDownTime();
            if (mPowerKeyPressCounter < maxCount) 
                Message msg = mHandler.obtainMessage(MSG_POWER_DELAYED_PRESS,
                        interactive ? 1 : 0, mPowerKeyPressCounter, eventTime);
                msg.setAsynchronous(true);
                mHandler.sendMessageDelayed(msg, ViewConfiguration.getDoubleTapTimeout());
                return;
            
            powerPress(eventTime, interactive, mPowerKeyPressCounter);
        
        finishPowerKeyPress();
    

在灭屏的时候,和亮屏长按的时候mPowerKeyHandled最后设置为true,即handle为true,直接执行finishPowerKeyPress方法,释放mPowerKeyWakeLock

在亮屏短按的时候,handled为false,由以上分析,手机默认不支持多次按键所以maxCount为1,mPowerKeyPressCounter=1,所以直接执行powerPress方法

private void powerPress(long eventTime, boolean interactive, int count) 
		
        if (count == 2) 
            powerMultiPressAction(eventTime, interactive,mDoublePressOnPowerBehavior);
         else if (count == 3) 
            powerMultiPressAction(eventTime, interactive, mTriplePressOnPowerBehavior);
         else if (interactive && !mBeganFromNonInteractive) 
            switch (mShortPressOnPowerBehavior) 
                case SHORT_PRESS_POWER_NOTHING:
                    break;
                case SHORT_PRESS_POWER_GO_TO_SLEEP:
                    mPowerManager.goToSleep(eventTime,
                            PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0);
                    break;
                case SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP:
                    mPowerManager.goToSleep(eventTime,
                            PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON,
                            PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);
                    break;
                case SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP_AND_GO_HOME:
                    mPowerManager.goToSleep(eventTime,
                            PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON,
                            PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);
                    launchHomeFromHotKey();
                    break;
                case SHORT_PRESS_POWER_GO_HOME:
                    launchHomeFromHotKey(true /* awakenFromDreams */, false 
                    break;
            
        
    

由于mPowerKeyPressCounter 为1,所以执行case  SHORT_PRESS_POWER_GO_TO_SLEEP,调用mPowerManager.goToSleep休眠系统

 

Power按键流程总结

Power按键

1.亮屏 down 

           长按 弹出关闭重启对话框

           短按 不做处理

   亮屏 up 

       长按 不做处理

        短按 调用goToSleep休眠系统

2. 灭屏 down

            调用wakeup 唤醒系统

     灭屏 up

            不做处理


以上是关于Power按键流程分析的主要内容,如果未能解决你的问题,请参考以下文章

使用 AVAudioSessionCategoryPlayAndRecord 启用响铃/静音开关

Android 7.0 Power 按键处理流程

如何在配置文件处于振动模式时使手机振动或在配置文件处于静音模式时从不响铃并在响铃模式下响铃

iOS - 如何在应用程序中使 iPhone 静音/响铃

Xamarin.iOS - >当用户在 iPhone 上从响铃/静音模式切换时是不是有要监听的事件?

深入了解PowerManagerService之Android 11.0 Power 键亮屏灭屏流程分析