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实现的。

作者:帅得不敢出门

相关推荐
学长毕设15 小时前
基于SpringBoot的实验室资产管理系统
java·spring boot·后端
驰骋工作流16 小时前
流程时效考核的表结构:从待办时限到 WF_CH 考核结果驰骋BPM驰骋低代码低代码工作流引擎
android·低代码·rxjava
zzu123zsw17 小时前
从臃肿的模板调用到声明式契约:深入 UniHttp 动态代理与多渠道生命周期扩展
java·spring boot·microsoft·unihttp
源码集结号17 小时前
云诊所门诊系统源码,基于SpringBoot+Vue.js架构,支持多租户设计与Docker容器化部署
java·spring boot·源码·医院信息系统·门诊系统·诊所系统
传奇开心果编程18 小时前
【Flutter踩坑排雷】第7课:巨型 build 函数坑|全部 UI 写在同一个 build,维护难、隐性异常
android·flutter·ios·移动开发·跨平台·dart·声明式ui
论文复现现场18 小时前
WRF、FEA 能用 L40S 加速吗?求解器检查、断点恢复与长期运行
java·数据库·算法·wrf·有限元分析·gpu计算·断点续算
啃瓜子的松鼠18 小时前
泛微OAe9-后端二开异步调用
java
秋天的怀念_David19 小时前
第二十一夜 · 数字黑洞与西西弗斯的惩罚
java·程序人生·算法
外收内放19 小时前
Python基础语法练习题(73)
java·前端·python
Wang's Blog19 小时前
Java 项目实战: 交友项目 - 环信后台发送消息测试
java·交友