Android Framework定制长按电源键关机的窗口

文章目录

长按关机流程

frameworks/base/core/res/res/values/config.xml

这个xml中指定了长按电源键的处理方式

复制代码
    <!-- Control the behavior when the user long presses the power button.
            0 - Nothing
            1 - Global actions menu
            2 - Power off (with confirmation)
            3 - Power off (without confirmation)
            4 - Go to voice assist
            5 - Go to assistant (Settings.Secure.ASSISTANT)
    -->
    <integer name="config_longPressOnPowerBehavior">1</integer>
  1. 什么都不操作
  2. 显示全局操作菜单,菜单中通常包含关机、重启、飞行模式等选项,这是最常见的配置。
  3. 关机,但要确认
  4. 直接关机,不需要确认
    其他值:不同的 Android 设备或定制系统可能会有额外的自定义行为对应其他值。
    若要修改为长按后直接关机,可以通过修改xml来实现。

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

处理关机键按键:

上面函数会调到以下函数showGlobalActionsInternal

java 复制代码
    void showGlobalActionsInternal() {
        if (mGlobalActions == null) {
            mGlobalActions = new GlobalActions(mContext, mWindowManagerFuncs);
        }
        final boolean keyguardShowing = isKeyguardShowingAndNotOccluded();
        mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned());
        // 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);
    }

frameworks/base/services/core/java/com/android/server/policy/GlobalActions.java

java 复制代码
    public void showDialog(boolean keyguardShowing, boolean deviceProvisioned) {
            // 其它省略
         // SystemUI的窗口
        if (mGlobalActionsAvailable) {
            mHandler.postDelayed(mShowTimeout, 5000);
            mGlobalActionsProvider.showGlobalActions();//GlobalActionsProvider
        } else {
            // SysUI isn't alive, show legacy menu.
            // SystemUI未存活时弹这个窗口
            ensureLegacyCreated();
            mLegacyGlobalActions.showDialog(mKeyguardShowing, mDeviceProvisioned);
        }
    }

注意上面代码有两个分支了,

  1. 默认调用的是SystemUI的窗口
  2. 如果其未存活则调用LegacyGlobalActions.java中的showDialog。

如果要自定义关机窗口,可以考虑在showDialog处修改,用自定义的Dialog实现,避免对两个分支都处理。当然也可以分别到两个分支的实现端分别修改处理。

SystemUI实现的关机窗口

mGlobalActionsProvider.showGlobalActions()其通过各种回调,调用到SystemUI下的代码,中间过程省略

frameworks/base/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java

java 复制代码
    @Override
    public void showGlobalActions(GlobalActionsManager manager) {
        if (mDisabled) return;
        // GlobalActionsDialog GlobalActionsDialog.java 在 Android 系统里是一个相当关键的类,它主要负责展示全局操作对话框。
        mGlobalActionsDialog = mGlobalActionsDialogLazy.get();
        mGlobalActionsDialog.showOrHideDialog(mKeyguardStateController.isShowing(),
                mDeviceProvisionedController.isDeviceProvisioned(),
                mWalletPluginProvider.get());
        Dependency.get(KeyguardUpdateMonitor.class).requestFaceAuth();
    }

./frameworks/base/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java

java 复制代码
    @VisibleForTesting
    protected String[] getDefaultActions() {
        return mResources.getStringArray(R.array.config_globalActionsList);
    }

......
        private void initializeLayout() {
            // layout xml
            setContentView(com.android.systemui.R.layout.global_actions_grid_v2);
        }

    @VisibleForTesting
    protected void createActionItems() {
    		String[] defaultActions = getDefaultActions();
            // ......
            // 这里addIfShouldShowAction会把需要的几个控件(比如关机,飞行模式等)加到UI中
            for (int i = 0; i < defaultActions.length; i++) {
            String actionKey = defaultActions[i];
            if (addedKeys.contains(actionKey)) {
                // If we already have added this, don't add it again.
                continue;
            }
            if (GLOBAL_ACTION_KEY_POWER.equals(actionKey)) {
                addIfShouldShowAction(tempActions, shutdownAction);
            } else if (GLOBAL_ACTION_KEY_AIRPLANE.equals(actionKey)) {
                addIfShouldShowAction(tempActions, mAirplaneModeOn);
            } else if (GLOBAL_ACTION_KEY_BUGREPORT.equals(actionKey)) {
               // 像这个bugreport是有条件的
                if (shouldDisplayBugReport(currentUser.get())) {
                    addIfShouldShowAction(tempActions, new BugReportAction());
                }
            }
            // .....
    }

从上面代码可以得到SystemUI关机窗口的layout文件是

frameworks/base/packages/SystemUI/res/layout/global_actions_grid_v2.xml

上面的按钮是通过R.array.config_globalActionsList定义的

frameworks/base/core/res/res/values/config.xml

xml 复制代码
    <!-- Defines the default set of global actions. Actions may still be disabled or hidden based
         on the current state of the device.
         Each item must be one of the following strings:
         "power" = Power off
         "settings" = An action to launch settings
         "airplane" = Airplane mode toggle
         "bugreport" = Take bug report, if available
         "silent" = silent mode
         "users" = list of users
         "restart" = restart device
         "emergency" = Launch emergency dialer
         "lockdown" = Lock down device until the user authenticates
         "logout" =  Logout the current user
         -->
    <string-array translatable="false" name="config_globalActionsList">
        <item>emergency</item>
        <item>lockdown</item>
        <item>power</item>
        <item>restart</item>
        <item>logout</item>
        <item>bugreport</item>
        <item>screenshot</item>
    </string-array>

当前定义的操作项包括:

  • emergency:紧急拨号
  • lockdown:设备锁定(需验证身份才能解锁)
  • power:关机
  • restart:重启设备
  • ogout:当前用户登出
  • bugreport:生成 bug 报告(通常仅开发者模式可见)
  • screenshot:截图
    操作项的可用性受系统状态限制(如 logout 仅多用户模式有效)
    bugreport 通常需要开启开发者模式才会显示。

LegacyGlobalActions实现的关机窗口

简介

LegacyGlobalActions.java 是 Android 系统 Framework 层里的一个关键类,它主要负责管理和展示系统的全局操作菜单。这个菜单一般会在用户长按电源键时弹出,包含诸如关机、重启、飞行模式等操作选项。

功能概述

  1. 操作菜单管理:对全局操作菜单中的各个操作选项进行管理,像添加、删除、更新操作选项等。
  2. 界面显示与交互:负责全局操作菜单的显示,处理用户对操作选项的点击事件。
  3. 系统操作执行:当用户点击某个操作选项时,执行相应的系统操作,例如关机、重启等。

frameworks/base/services/core/java/com/android/server/policy/LegacyGlobalActions.java

java 复制代码
    public void showDialog(boolean keyguardShowing, boolean isDeviceProvisioned) {
        mKeyguardShowing = keyguardShowing;
        mDeviceProvisioned = isDeviceProvisioned;
        if (mDialog != null) {
            mDialog.dismiss();
            mDialog = null;
            // Show delayed, so that the dismiss of the previous dialog completes
            mHandler.sendEmptyMessageDelayed(MESSAGE_SHOW,SHOW_DIALOG_DELAY);//unisoc: fix for bug 1136724
        } else {
            handleShow(); // 这个函数会执行弹可选关机或重启的窗口
        }
    }

    // 显示由此函数实现
    private void handleShow() {
        if(mHandler != null && mHandler.hasMessages(MESSAGE_SHOW)) {
            Log.d(TAG, "delayed show dialog message.");
            return;
        }

        awakenIfNecessary();
        mDialog = createDialog(); // 这里是创建窗口的函数
        prepareDialog();

        // If we only have 1 item and it's a simple press action, just do this action.
        if (mAdapter.getCount() == 1
                && mAdapter.getItem(0) instanceof SinglePressAction
                && !(mAdapter.getItem(0) instanceof LongPressAction)) {
            ((SinglePressAction) mAdapter.getItem(0)).onPress();
        } else {
            if (mDialog != null) {
                WindowManager.LayoutParams attrs = mDialog.getWindow().getAttributes();
                attrs.setTitle("LegacyGlobalActions");
                mDialog.getWindow().setAttributes(attrs);
                mDialog.show();
                mDialog.getWindow().getDecorView().setSystemUiVisibility(
                        View.STATUS_BAR_DISABLE_EXPAND);
            }
        }
    }

// createDialog就是创建了一个ActionsDialog,在 Android 系统中,ActionsDialog.java 通常用于创建和管理包含多个操作选项的对话框,这种对话框一般会在用户进行某些操作时弹出,为用户提供一系列可选择的操作,例如长按电源键弹出的包含关机、重启、飞行模式等选项的对话框。
private ActionsDialog createDialog() {
        // 其它省略
        ActionsDialog dialog = new ActionsDialog(mContext, params);
        dialog.setCanceledOnTouchOutside(false); // Handled by the custom class.

        dialog.getListView().setItemsCanFocus(true);
        dialog.getListView().setLongClickable(true);
        dialog.getListView().setOnItemLongClickListener(
                new AdapterView.OnItemLongClickListener() {
                    @Override
                    public boolean onItemLongClick(AdapterView<?> parent, View view, int position,
                            long id) {
                        final Action action = mAdapter.getItem(position);
                        if (action instanceof LongPressAction) {
                            return ((LongPressAction) action).onLongPress();
                        }
                        return false;
                    }
        });
        dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
        // Don't acquire soft keyboard focus, to avoid destroying state when capturing bugreports
        dialog.getWindow().setFlags(FLAG_ALT_FOCUSABLE_IM, FLAG_ALT_FOCUSABLE_IM);

        dialog.setOnDismissListener(this);

        return dialog;
}

可以看出LegacyGlobalActions的关机窗口是由createDialog函数中创建的ActionsDialog实现的。

作者:帅得不敢出门

相关推荐
天天被压力14 分钟前
【跨市场数据实战 #08】可转债折价机会怎么筛:3个接口抓比价、列表和实时盘口
java·人工智能·python
张某布响丸辣1 小时前
附件下载的安全边界:路径白名单、NAS 哨兵文件与 Redis Lua 一次性令牌
java·redis·redis lua·nas哨兵
传奇开心果编程1 小时前
【Jetpack Compose基础语法学与练】第8课 rememberSaveable,页面旋转/系统重建保留状态
android·学习·ui·kotlin·android jetpack
>Andre<1 小时前
UFS5.0标准中文全译·卷一:范围、术语与架构
android·linux·嵌入式硬件
YatHinLay2 小时前
Spring Boot + Calcite 实现跨库查询
java
酷炫码神2 小时前
MosMos 创意效果与能力边界展示
java
Wang's Blog2 小时前
Java 接入Redis: 使用Jedis操作Redis
java·服务器·redis
事圆则缓2 小时前
Java 8 Lambda、Stream、Optional 与 Android 边界:从回调语法到运行时兼容
android·java
shehuiyuelaiyuehao2 小时前
算法50,分治归并,数组中的逆序对
java·算法
烽学长2 小时前
(附源码)基于Springboot+vue的图书阅读分享系统的设计与实现
java·spring boot·后端