Android11在导航栏中添加软关机按钮


一、配置文件准备:

1.准备一张power按钮的图片:

  Android11和以往又有不同,不再是用png格式的图片,用的是矢量图。可以阿里巴巴矢量图库里面招图片,再用as转成xml文件,内容如下:

  packages/SystemUI/res/drawable/ic_sysbar_power.xml

<?xml version="1.0" encoding="utf-8"?>

"24dp" android:viewportHeight="1024"
    android:viewportWidth="1024" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
    "#FFFFFF" android:pathData="M705.6,124.9c-5.3,-2.7 -11.6,1.2 -11.6,7.2v64.2c0,5.5 2.9,10.6 7.5,13.6 22.4,14.1 43.2,30.7 62.2,49.8 32.7,32.8 58.4,70.9 76.3,113.3 18.5,43.9 27.9,90.5 27.9,138.7 0,48.1 -9.4,94.8 -27.9,138.7 -17.9,42.4 -43.6,80.5 -76.3,113.3 -32.7,32.8 -70.8,58.5 -113.2,76.4 -43.8,18.6 -90.5,28 -138.5,28s-94.7,-9.4 -138.5,-28c-42.4,-17.9 -80.5,-43.6 -113.2,-76.4 -32.7,-32.8 -58.4,-70.9 -76.3,-113.3 -18.5,-43.9 -27.9,-90.5 -27.9,-138.7 0,-48.1 9.4,-94.8 27.9,-138.7 17.9,-42.4 43.6,-80.5 76.3,-113.3 19,-19 39.8,-35.6 62.2,-49.8 4.7,-2.9 7.5,-8.1 7.5,-13.6V132c0,-6 -6.3,-9.8 -11.6,-7.2C178.5,195.2 82,339.3 80,506.3 77.2,745.1 272.5,943.5 511.2,944c239,0.5 432.8,-193.3 432.8,-432.4 0,-169.2 -97,-315.7 -238.4,-386.7z"/>
    "#FFFFFF" android:pathData="M480,560h64c4.4,0 8,-3.6 8,-8V88c0,-4.4 -3.6,-8 -8,-8h-64c-4.4,0 -8,3.6 -8,8v464c0,4.4 3.6,8 8,8z"/>

2.添加按键布局:

diff --git a/packages/SystemUI/res/layout/power.xml b/packages/SystemUI/res/layout/power.xml
new file mode 100755
index 0000000..013577f
--- /dev/null
+++ b/packages/SystemUI/res/layout/power.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<com.android.systemui.statusbar.policy.KeyButtonView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:systemui="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/power"
+    android:layout_width="@dimen/navigation_key_width"
+    android:layout_height="match_parent"
+    android:layout_weight="0"
+    systemui:keyCode="0"
+    android:scaleType="center"
+    android:contentDescription="@string/accessibility_power"
+    android:paddingStart="@dimen/navigation_key_padding"
+    android:paddingEnd="@dimen/navigation_key_padding"
+    />
+
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
old mode 100644
new mode 100755
index 174f5c7..34c65af
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -302,6 +302,8 @@
     <string name="accessibility_back">Backstring>
     
     <string name="accessibility_home">Homestring>
+    
+    <string name="accessibility_power">Powerstring>
     
     <string name="accessibility_menu">Menustring>
     

3.修改config文件:

diff --git a/packages/SystemUI/res/values-sw400dp/config.xml b/packages/SystemUI/res/values-sw400dp/config.xml
old mode 100644
new mode 100755
index de33fb5..1a70147
--- a/packages/SystemUI/res/values-sw400dp/config.xml
+++ b/packages/SystemUI/res/values-sw400dp/config.xml
@@ -22,6 +22,6 @@
 
 
     
-    <string name="config_navBarLayout" translatable="false">left;volume_sub,back,home,recent,volume_add,screenshot;rightstring>
+    <string name="config_navBarLayout" translatable="false">left;volume_sub,back,home,recent,volume_add,screenshot,power;rightstring>
 
 
diff --git a/packages/SystemUI/res/values-sw600dp/config.xml b/packages/SystemUI/res/values-sw600dp/config.xml
old mode 100644
new mode 100755
index 3c0ee9f..a434084
--- a/packages/SystemUI/res/values-sw600dp/config.xml
+++ b/packages/SystemUI/res/values-sw600dp/config.xml
@@ -27,7 +27,7 @@
     "quick_settings_user_time_settings_tile_span">1
 
     
-    <string name="config_navBarLayout" translatable="false">left;volume_sub,back,home,recent,volume_add,screenshot;rightstring>
+    <string name="config_navBarLayout" translatable="false">left;volume_sub,back,home,recent,volume_add,screenshot,power;rightstring>
 
     
     "long_press_dock_anim_duration">290
diff --git a/packages/SystemUI/res/values-sw720dp/config.xml b/packages/SystemUI/res/values-sw720dp/config.xml
old mode 100644
new mode 100755
index b850aef..b28e749
--- a/packages/SystemUI/res/values-sw720dp/config.xml
+++ b/packages/SystemUI/res/values-sw720dp/config.xml
@@ -27,6 +27,6 @@
     "keyguard_max_notification_count">5
 
     
-    <string name="config_navBarLayout" translatable="false">left;volume_sub,back,home,recent,volume_add,screenshot;rightstring>
+    <string name="config_navBarLayout" translatable="false">left;volume_sub,back,home,recent,volume_add,screenshot,power;rightstring>
 
 
diff --git a/packages/SystemUI/res/values-sw900dp/config.xml b/packages/SystemUI/res/values-sw900dp/config.xml
old mode 100644
new mode 100755
index f957d6e..1adb097
--- a/packages/SystemUI/res/values-sw900dp/config.xml
+++ b/packages/SystemUI/res/values-sw900dp/config.xml
@@ -19,6 +19,6 @@
 
 
     
-    <string name="config_navBarLayout" translatable="false">left;volume_sub,back,home,recent,volume_add,screenshot;rightstring>
+    <string name="config_navBarLayout" translatable="false">left;volume_sub,back,home,recent,volume_add,screenshot,power;rightstring>
 
 
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
old mode 100644
new mode 100755
index eedfe31..9c659ae
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -341,7 +341,7 @@
     string-array>
 
     
-    <string name="config_navBarLayout" translatable="false">left[.5W];volume_sub,back,home,recent,volume_add,screenshot;right[.5W]string>
+    <string name="config_navBarLayout" translatable="false">left[.5W];volume_sub,back,home,recent,volume_add,screenshot,power;right[.5W]string>
     <string name="config_navBarLayoutQuickstep" translatable="false">back[1.7WC];home;contextual[1.7WC]string>
     <string name="config_navBarLayoutHandle" translatable="false">back[40AC];home_handle;ime_switcher[40AC]string>

二、java代码实现

  1.添加按钮:

diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
old mode 100644
new mode 100755
index 7014673..94dd1c1
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
@@ -67,6 +67,7 @@ public class NavigationBarInflaterView extends FrameLayout
     public static final String SCREENSHOT = "screenshot";
     public static final String VOLUME_ADD = "volume_add";
     public static final String VOLUME_SUB = "volume_sub";
+    public static final String POWER = "power";
 
     public static final String GRAVITY_SEPARATOR = ";";
     public static final String BUTTON_SEPARATOR = ",";
@@ -405,6 +406,8 @@ public class NavigationBarInflaterView extends FrameLayout
             v = inflater.inflate(R.layout.volume_add, parent, false);
         } else if (VOLUME_SUB.equals(button)) {
             v = inflater.inflate(R.layout.volume_sub, parent, false);
+        } else if (POWER.equals(button)) {
+            v = inflater.inflate(R.layout.power, parent, false);
         } else if (button.startsWith(KEY)) {
             String uri = extractImage(button);
             int code = extractKeycode(button);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
old mode 100644
new mode 100755
index 6b4a157..1679e89
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -125,6 +125,7 @@ public class NavigationBarView extends FrameLayout implements
     private KeyButtonDrawable mVolumeAddIcon;
     private KeyButtonDrawable mVolumeSubIcon;
     private KeyButtonDrawable mScreenshotIcon;
+    private KeyButtonDrawable mPowerIcon;
 
     private EdgeBackGestureHandler mEdgeBackGestureHandler;
     private final DeadZone mDeadZone;
@@ -335,6 +336,7 @@ public class NavigationBarView extends FrameLayout implements
         mButtonDispatchers.put(R.id.screenshot, new ButtonDispatcher(R.id.screenshot));
         mButtonDispatchers.put(R.id.volume_add, new ButtonDispatcher(R.id.volume_add));
         mButtonDispatchers.put(R.id.volume_sub, new ButtonDispatcher(R.id.volume_sub));
+        mButtonDispatchers.put(R.id.power, new ButtonDispatcher(R.id.power));
         mDeadZone = new DeadZone(this);
 
         mNavColorSampleMargin = getResources()
@@ -491,6 +493,10 @@ public class NavigationBarView extends FrameLayout implements
         return mButtonDispatchers.get(R.id.volume_sub);
     }
 
+    public ButtonDispatcher getPowerButton() {
+        return mButtonDispatchers.get(R.id.power);
+    }
+
     public RotationContextButton getRotateSuggestionButton() {
         return (RotationContextButton) mButtonDispatchers.get(R.id.rotate_suggestion);
     }
@@ -539,6 +545,7 @@ public class NavigationBarView extends FrameLayout implements
         mVolumeAddIcon = getDrawable(R.drawable.ic_sysbar_volume_add_button);
         mVolumeSubIcon = getDrawable(R.drawable.ic_sysbar_volume_sub_button);
         mScreenshotIcon = getDrawable(R.drawable.ic_sysbar_capture_button);
+        mPowerIcon = getDrawable(R.drawable.ic_sysbar_power);
     }
 
     public KeyButtonDrawable getBackDrawable() {
@@ -695,6 +702,7 @@ public class NavigationBarView extends FrameLayout implements
         getVolumeAddButton().setImageDrawable(mVolumeAddIcon);
         getVolumeSubButton().setImageDrawable(mVolumeSubIcon);
         getScreenshotButton().setImageDrawable(mScreenshotIcon);
+        getPowerButton().setImageDrawable(mPowerIcon);
 
         updateRecentsIcon();

2.点击按键时动作处理:

diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/
android/systemui/statusbar/phone/NavigationBarFragment.java
old mode 100644
new mode 100755
index 95a9eda..3ef4c3a
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -1049,6 +1049,24 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
             volumeAddButton.setVisibility(View.GONE);
             volumeSubButton.setVisibility(View.GONE);
         }
+
+        ButtonDispatcher powerButton = mNavigationBarView.getPowerButton();
+        powerButton.setOnClickListener(this:: powerClick);
+        powerButton.setOnTouchListener(this:: powerTouch);
+
+    }
+
+    private boolean powerTouch(View v, MotionEvent event) {
+        if (event.getAction() == MotionEvent.ACTION_UP) {
+            Intent intent=new Intent("com.xzy.systemui.poweroff");
+            getContext().sendBroadcast(intent);
+        }
+        return false;
+    }
+
+    private void powerClick(View v) {
+            Intent intent=new Intent("com.xzy.systemui.poweroff");
+            getContext().sendBroadcast(intent);
     }
 
     private boolean onHomeTouch(View v, MotionEvent event) {

点击按钮,发出关机消息的广播。

3.关机弹框的实现:

  注册广播,接受到广播后弹出关机重启选择的弹框

diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index d966f36..4671c2f 100755
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -2020,6 +2020,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
         filter = new IntentFilter();
         filter.addAction(Intent.ACTION_DREAMING_STARTED);
         filter.addAction(Intent.ACTION_DREAMING_STOPPED);
+        filter.addAction("com.xzy.systemui.poweroff"); 
         context.registerReceiver(mDreamReceiver, filter);
 
         // register for multiuser-relevant broadcasts
@@ -4494,6 +4495,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                 if (mKeyguardDelegate != null) {
                     mKeyguardDelegate.onDreamingStopped();
                 }
+            } else if("com.xzy.systemui.poweroff".equals(intent.getAction())) {
+                               
+                Slog.v(TAG, "wmc...Receive a soft poweroff broadcast.");
+                showGlobalActionsInternal();                 
             }
         }
     };
showGlobalActionsInternal这个方法是调出关机弹框的。
但此时发现弹框是这样的:

经过了解,发现Android 原生的关机界面有两种,一种是LegacyGlobalActions(以上图片)中的dialog,另一种是SystemUI中的GlobalActionsDialog。

继续看弹框的代码流程:

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);
    }
showGlobalActionsInternal->mGlobalActions.showDialog
services/core/java/com/android/server/policy/GlobalActions.java
public void showDialog(boolean keyguardShowing, boolean deviceProvisioned) {
        if (DEBUG) Slog.d(TAG, "showDialog " + keyguardShowing + " " + deviceProvisioned);
        if (mGlobalActionsProvider != null && mGlobalActionsProvider.isGlobalActionsDisabled()) {
            return;
        }
        mKeyguardShowing = keyguardShowing;
        mDeviceProvisioned = deviceProvisioned;
        mShowing = true;
        if (mGlobalActionsAvailable && !"box".equals(SystemProperties.get("ro.target.product","unkonw"))) {
            mHandler.postDelayed(mShowTimeout, 5000);
            mGlobalActionsProvider.showGlobalActions();
        } else {
            // SysUI isn't alive, show legacy menu.
            ensureLegacyCreated();
            mLegacyGlobalActions.showDialog(mKeyguardShowing, mDeviceProvisioned);
        }
    }

在这里就能找到原因了,编译的系统ro.target.product不是box的,所以流程走的是mLegacyGlobalActions.showDialog,即前面调出的图片。

这样修改一下即可:

index ecd1eab..31250a9 100755
--- a/services/core/java/com/android/server/policy/GlobalActions.java
+++ b/services/core/java/com/android/server/policy/GlobalActions.java
@@ -65,7 +65,7 @@ class GlobalActions implements GlobalActionsProvider.GlobalActionsListener {
         mKeyguardShowing = keyguardShowing;
         mDeviceProvisioned = deviceProvisioned;
         mShowing = true;
-        if (mGlobalActionsAvailable && !"box".equals(SystemProperties.get("ro.target.product","unkonw"))) {
+        if (mGlobalActionsAvailable && !"tablet".equals(SystemProperties.get("ro.target.product","unkonw"))) {
             mHandler.postDelayed(mShowTimeout, 5000);
             mGlobalActionsProvider.showGlobalActions();
         } else {

此时弹框图片:

 参考:https://blog.csdn.net/An_Times/article/details/122043152