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

作者:帅得不敢出门

相关推荐
2501_915106323 小时前
iOS 26 APP 性能测试实战攻略:多工具组合辅助方案
android·macos·ios·小程序·uni-app·cocoa·iphone
Predestination王瀞潞3 小时前
Java EE开发技术(Servlet整合JDBC银行管理系统-上)
java·servlet·java-ee·jdbc
寻星探路4 小时前
Java EE初阶启程记13---JUC(java.util.concurrent) 的常见类
java·开发语言·java-ee
怪兽20144 小时前
什么是 Redis?
java·数据库·redis·缓存·面试
Gu_yyqx4 小时前
Java 队列
java
落日漫游4 小时前
数据结构笔试核心考点
java·开发语言·算法
疯狂吧小飞牛5 小时前
Lua C API 中的注册表介绍
java·c语言·lua
kyle~5 小时前
C++--- override 关键字 强制编译器验证当前函数是否重写基类的虚函数
java·前端·c++
Hello.Reader5 小时前
Flink 受管状态的自定义序列化原理、实践与可演进设计
java·网络·flink
让我上个超影吧5 小时前
设计模式【工厂模式和策略模式】
java·设计模式·策略模式