Android6.0关机流程源码分析一

_前段时间盆友问我怎么实现关机功能,于是我就开始捣鼓,第一个想法就是发送关机广播,然而遇到了些问题,一是获取不到关机权限,二是Intent.ACTION_REQUEST_SHUT_DOWN和Intent.SHUTDOWN这两个属性不对上层开放。一条路行不通就换条走吧,既然没对上层提供shutdown()函数,那就用反射的方法来取,结果还是因为没有关机权限而无法调用shutdown()函数。无奈只好决定来看下源码,分析关机流程。这里主要是分析正常的关机流程。画了个简单的调用流程图。
这里写图片描述

接下来一步步分析。我们正常关机一般就是长按关机键,然后系统弹出个关机对话框

这里写图片描述

选择Power Off则开启关机。

长按关机键(KEYCODE_POWER),PhoneWindowManager.java拦截该事件,做出处理

 /** {@inheritDoc} */
@Override
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
    if (!mSystemBooted) {
        // If we have not yet booted, don't let key events do anything.
        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();
    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;
        }

        case KeyEvent.KEYCODE_SLEEP: {
            result &= ~ACTION_PASS_TO_USER;
            isWakeKey = false;
            if (!mPowerManager.isInteractive()) {
                useHapticFeedback = false; // suppress feedback if already non-interactive
            }
            if (down) {
                sleepPress(event.getEventTime());
            } else {
                sleepRelease(event.getEventTime());
            }
            break;
        }

        case KeyEvent.KEYCODE_WAKEUP: {
            result &= ~ACTION_PASS_TO_USER;
            isWakeKey = true;
            break;
        }
    }
}

down事件:

private void interceptPowerKeyDown(KeyEvent event, boolean interactive) {
    //如果电源键尚未处理,则检测是短按,长按,或多按操作中的哪一种,再决定做下一步处理。
    mPowerKeyHandled = hungUp || mScreenshotChordVolumeDownKeyTriggered
            || mScreenshotChordVolumeUpKeyTriggered;
    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.
            //检查是否是长按操作
            //hasLongPressOnPowerBehavior=getResolvedLongPressOnPowerBehavior() != LONG_PRESS_POWER_NOTHING;
            if (hasLongPressOnPowerBehavior()) {
  //true
                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;
                }
            }
        }
    }
}

主线程接收到长按的消息并做出下一步处理

private class PolicyHandler extends Handler {
   
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case MSG_POWER_LONG_PRESS:
                //调用powerPress()函数
                powerLongPress();
            break;
        }
    }
}

那接着来看powerLongPress()函数是如何处理长按事件的

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;
    case LONG_PRESS_POWER_SHUT_OFF:
    case LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM:
        mPowerKeyHandled = true;
        performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
        sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
        mWindowManagerFuncs.shutdown(behavior == LONG_PRESS_POWER_SHUT_OFF);
        break;
    }
}

这里根据长按的行为behavior来分情况处理的。

情况一:LONG_PRESS_POWER_NOTHING:不处理

情况二:LONG_PRESS_POWER_GLOBAL_ACTIONS:正常关机流程

void showGlobalActionsInternal() {
    //请求ActivityManagerNative关闭系统所有窗口
    sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
    if (mGlobalActions == null) {
        //初始化GlobalActions
        mGlobalActions = new GlobalActions(mContext, mWindowManagerFuncs);
    }
    final boolean keyguardShowing = isKeyguardShowingAndNotOccluded();
    //显示关机对话框
    mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned());
    if (keyguardShowing) {
        // since it took two seconds of long press to bring this up,
        // poke the wake lock so they have some time to see the dialog.
        mPowerManager.userActivity(SystemClock.uptimeMillis(), false);
    }
}

(1)sendCloseSystemWindows();//发送请求关闭系统的对话框

void sendCloseSystemWindows(String reason) {
    PhoneWindow.sendCloseSystemWindows(mContext, reason);
}

调用的是PhoneWindow.java的方法,如下:

public static void sendCloseSystemWindows(Context context, String reason) {
    if (ActivityManagerNative.isSystemReady()) {
        try {
            ActivityManagerNative.getDefault().closeSystemDialogs(reason);
        } catch (RemoteException e) {
        }
    }
}

继续调用ActivityManagerNative.java的方法,如下:

public void closeSystemDialogs(String reason) throws RemoteException {
    Parcel data = Parcel.obtain();
    Parcel reply = Parcel.o
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值