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

作者:帅得不敢出门

相关推荐
hyy27952276841 分钟前
企业级WEB应用服务器TOMCAT
java·前端·tomcat
布朗克1684 分钟前
Spring Boot项目通过Feign调用三方接口的详细教程
java·spring boot·feign
Arva .11 分钟前
Spring基于XML的自动装配
xml·java·spring
雨白17 分钟前
加密、签名与编码
android
李新_2 小时前
【Android Bug Fix】UI不响应、异位异常排查
android·程序员
fatfishccc2 小时前
循序渐进学 Spring (上):从 IoC/DI 核心原理到 XML 配置实战
xml·java·数据库·spring·intellij-idea·ioc·di
小厂永远得不到的男人3 小时前
一篇文章搞懂 java 反射
java·后端
勇往直前plus3 小时前
一文学习nacos和openFeign
java·学习·微服务·openfeign
Warren983 小时前
公司项目用户密码加密方案推荐(兼顾安全、可靠与通用性)
java·开发语言·前端·javascript·vue.js·python·安全