android9.0在设置里添加开关控件去隐藏或显示导航栏

本文详细介绍了在基于高通平台的Android系统中,如何通过广播实现虚拟按键开关的定制功能,包括定义广播内容、动态注册广播、广播接收处理、设置数据库及开关显示等步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言:
基于高通平台定制android系统。在自己每次接触新的技术需求时,总是会出现很多低级或不懂的问题,因为第一次搞欠缺经验,所以只能花费很多时间和各种方法去尝试。例如这次设置里添加虚拟按键开关,就用了一个多星期去解决问题,主要是发送广播不成功问题。话不多说,进入正题:

首先看一下原始界面:
添加开关隐藏/显示虚拟按键

一、广播实现

1.定义广播内容

frameworks/base/core/java/android/content/Intent.java

     public static final String ACTION_SCREEN_ON = "android.intent.action.SCREEN_ON";
+    public static final String ACTION_NAVIGATION_SHOW = "android.intent.action.NAVIGATION_SHOW";
+    public static final String ACTION_NAVIGATION_HIDE = "android.intent.action.NAVIGATION_HIDE";
2.动态注册广播

frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java

      filter.addAction(Intent.ACTION_SCREEN_OFF);
+     filter.addAction(Intent.ACTION_NAVIGATION_SHOW);
+     filter.addAction(Intent.ACTION_NAVIGATION_HIDE);
3.广播接收处理

frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java

@@ -909,7 +910,9 @@ public class StatusBar extends SystemUI implements DemoMode,
             boolean showNav = mWindowManagerService.hasNavigationBar();
             if (DEBUG) Log.v(TAG, "hasNavigationBar=" + showNav);
             if (showNav) {
-                createNavigationBar();
+               if(1==Settings.System.getInt(mContext.getContentResolver(), Settings.System.HIDE_NAVIGATION, 1)){
+                  createNavigationBar();
+               }
             }
         } catch (RemoteException ex) {
             // no window manager? good luck with that
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (DEBUG) Log.v(TAG, "onReceive: " + intent);
            String action = intent.getAction();
            if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
                KeyboardShortcuts.dismiss();
                if (mRemoteInputManager.getController() != null) {
                    mRemoteInputManager.getController().closeRemoteInputs();
                }
                if (mLockscreenUserManager.isCurrentProfile(getSendingUserId())) {
                    int flags = CommandQueue.FLAG_EXCLUDE_NONE;
                    String reason = intent.getStringExtra("reason");
                    if (reason != null && reason.equals(SYSTEM_DIALOG_REASON_RECENT_APPS)) {
                        flags |= CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL;
                    }
                    animateCollapsePanels(flags);
                }
            }
            else if (Intent.ACTION_SCREEN_OFF.equals(action)) {
                finishBarAnimations();
                resetUserExpandedStates();
            }
            else if (DevicePolicyManager.ACTION_SHOW_DEVICE_MONITORING_DIALOG.equals(action)) {
                mQSPanel.showDeviceMonitoringDialog();
            }
            else if (Intent.ACTION_NAVIGATION_HIDE.equals(action)){
                removeBar();
                Settings.System.putInt(mContext.getContentResolver(), Settings.System.HIDE_NAVIGATION, 1);
                Log.d(TAG, "android.intent.action.NAVIGATION_HIDE");
            }
            else if(Intent.ACTION_NAVIGATION_SHOW.equals(action)){
                addBarInside();
                Settings.System.putInt(mContext.getContentResolver(), Settings.System.HIDE_NAVIGATION, 0);
                Log.d(TAG, "android.intent.action.NAVIGATION_SHOW");
            }
        }
    };

二、设置到数据库

1.添加key到数据库中

frameworks/base/core/java/android/provider/Settings.java

         public static final Uri DEFAULT_NOTIFICATION_URI = getUriFor(NOTIFICATION_SOUND);

+       /**
+        * add by wuxb
+        * Whether hide navigation
+        * 0 = no
+        * 1 = yes
+        */
+       public static final String HIDE_NAVIGATION = "hide_navigation";
+       public static final Uri HIDE_NAVIGATION_URI = getUriFor(HIDE_NAVIGATION);
+       private static final Validator HIDE_NAVIGATION_VALIDATOR = URI_VALIDATOR;
@@ -4163,6 +4173,7 @@ public final class Settings {
             RINGTONE,
             LOCK_TO_APP_ENABLED,
             NOTIFICATION_SOUND,
+           HIDE_NAVIGATION,
             ACCELEROMETER_ROTATION,
             SHOW_BATTERY_PERCENT,
             NOTIFICATION_VIBRATION_INTENSITY,
@@ -4218,6 +4229,7 @@ public final class Settings {
             PUBLIC_SETTINGS.add(VOLUME_BLUETOOTH_SCO);
             PUBLIC_SETTINGS.add(RINGTONE);
             PUBLIC_SETTINGS.add(NOTIFICATION_SOUND);
+           PUBLIC_SETTINGS.add(HIDE_NAVIGATION);
             PUBLIC_SETTINGS.add(ALARM_ALERT);
             PUBLIC_SETTINGS.add(TEXT_AUTO_REPLACE);
             PUBLIC_SETTINGS.add(TEXT_AUTO_CAPS);
@@ -4315,6 +4327,7 @@ public final class Settings {
             VALIDATORS.put(HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_VALIDATOR);
             VALIDATORS.put(RINGTONE, RINGTONE_VALIDATOR);
             VALIDATORS.put(NOTIFICATION_SOUND, NOTIFICATION_SOUND_VALIDATOR);
+           VALIDATORS.put(HIDE_NAVIGATION,HIDE_NAVIGATION_VALIDATOR);
             VALIDATORS.put(ALARM_ALERT, ALARM_ALERT_VALIDATOR);
             VALIDATORS.put(TEXT_AUTO_REPLACE, TEXT_AUTO_REPLACE_VALIDATOR);
             VALIDATORS.put(TEXT_AUTO_CAPS, TEXT_AUTO_CAPS_VALIDATOR);
2.设置默认值

frameworks/base/packages/SettingsProvider/res/values/defaults.xml

+    <!-- hide navigation -->
+    <integer name="def_hide_navigation">1</integer>
     <bool name="def_bluetooth_on">false</bool>
3.将默认值添加到数据库

frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java

   //set hide navigation
   loadIntegerSetting(stmt, Settings.System.HIDE_NAVIGATION,
                  R.integer.def_hide_navigation);

三、设置开关显示

1.支持中英文标题

packages/apps/Settings/res/values-zh-rCN/strings.xml

 <string name="navigation_settings_title">"虚拟按键"</string>

packages/apps/Settings/res/values/strings.xml

<string name="navigation_settings_title">Navigation settings</string>
2.开关布局UI显示

packages/apps/Settings/res/xml/display_settings.xml

<SwitchPreference
       android:key="navigation"
       android:title="@string/navigation_settings_title"
       android:persistent="false"
       settings:controller="com.android.settings.display.OperateNavigationPreferenceController" />

由于qualcomm平台不同mtk平台,并不是把代码都直接加在DisplaySettings.java文件里的,而是单独写一个实现类的方法
1.packages/apps/Settings/src/com/android/settings/display$ vim OperateNavigationPreferenceController.java

@Override
    public boolean onPreferenceChange(Preference preference, Object newValue) {
        try {
            boolean isOpen = (boolean)newValue;
            if (isOpen) {
                mContext.sendBroadcast(new Intent(Intent.ACTION_NAVIGATION_SHOW));
            }else {
                mContext.sendBroadcast(new Intent(Intent.ACTION_NAVIGATION_HIDE));
            }
            Log.i(TAG, "onPreferenceChange isOpen="+isOpen);
        } catch (Exception e) {
            Log.e(TAG, "could not persist night mode setting", e);
            return false;
        }
        return true;
    }

第一次编译烧写后,发现点击开关没有反应,然后验证自己的广播是否有问题,adb发送广播是没有问题,因为 这个问题,尝试了很多方法,以为是哪个地方没有添加到,然后没有编译到这个文件,因为看log都没有信息。或者是不是系统权限问题,或是packages目录下的广播发送在frameworks目录下接收不到;陆续编译了十几次都是失败的,之前走的弯路都是错误的;最后找到问题所在:对于不同的版本,API的接口是有差异的(难怪一开始仿照系统其它开关控件不行,因为系统调节音量、亮度都有专门的API);如下图所示:
在这里插入图片描述
解决方法:

@Override
    public boolean isChecked() {
        return Settings.System.getInt(mContext.getContentResolver(), HIDE_NAVIGATION, 1) == 1;
    }

    @Override
    public boolean setChecked(boolean isChecked) {
        Log.i(TAG, "onPreferenceChange isChecked="+isChecked);
       if (isChecked) {
            mContext.sendBroadcast(new Intent(Intent.ACTION_NAVIGATION_SHOW));
        }else {
            mContext.sendBroadcast(new Intent(Intent.ACTION_NAVIGATION_HIDE));
        }
        Settings.System.putInt(mContext.getContentResolver(), HIDE_NAVIGATION, isChecked ? 1 : 0);
        return true;
    }

调试过程中还有一个有趣问题,就是开关实现广播发送时却出现只有一半的作用,即能开显示不能关隐藏或者能关隐藏不能开显示,但是按下面操作就没有问题:

sendBroadcast要发Intent.ACTION_NAVIGATION_HIDE不发android.intent.action.NAVIGATION_HIDE

adb发广播要发android.intent.action.NAVIGATION_HIDE不发android.intent.action.NAVIGATION_HIDE

最终实现的效果:

2020-07-30 Navigation

<think>好的,我现在需要回答用户关于Android 9.0隐藏下拉状态栏电池图标的源码修改位置的问题。首先,我得回忆一下Android系统UI的相关组件结构。状态栏的图标管理通常是在SystemUI模块中,具体来说,电池图标可能在StatusBar模块的某个类。 用户提到的是下拉状态栏,也就是通知栏的快捷设置部分,这可能属于QuickSettings类似的布局文件。不过电池状态显示通常是在状态栏的右侧,包括电池百分比和图标。在Android源码中,电池图标的管理可能由BatteryMeterView者BatteryController来处理。 接下来,我需要确认具体的类和方法。在AOSP的SystemUI项目中,BatteryMeterView是负责绘制电池图标的视图类,位于com.android.systemui.BatteryMeterView。而控制其显示与否的可能是在StatusBarIconController者相关的布局文件中。 另外,隐藏图标可能需要修改SystemUI的布局文件,比如status_bar.xml类似的布局文件,将对应的BatteryMeterView的可见性设置为GONE。者,在代码中通过findViewById获取该视图并设置Visibility为View.GONE。 还需要考虑系统设置中的相关标志位,比如是否有配置项控制电池图标的显示,可能需要在config.xml中修改默认值。不过用户的需求是直接修改源码隐藏,所以可能需要直接注释掉相关的布局代码逻辑。 要确保修改的是正确的版本,Android 9.0对应的分支是android-9.0.0_rXX,需要确认代码路径是否正确。例如,SystemUI的代码路径通常是packages/apps/SystemUI/src/com/android/systemui/。 可能的步骤包括: 1. 找到StatusBar的布局文件,如status_bar.xml,检查是否有BatteryMeterView。 2. 如果布局中有该视图,设置android:visibility="gone"。 3. 者在代码中,如StatusBarPhone类中,找到初始化电池图标的部分并隐藏。 4. 另外,检查BatteryController类,看是否有控制显示的逻辑,修改相关方法。 需要注意的是,直接修改布局文件可能更直接,但不同厂商的定制ROM可能会有所不同,这假设是原生AOSP的情况。同时,修改后需要重新编译SystemUI模块并推送生效。 总结可能的修改位置: - SystemUI的res/layout/status_bar.xml - BatteryMeterView的初始化代码 - BatteryController中的状态更新逻辑</think>要隐藏Android 9.0下拉状态栏的电池显示,需要修改SystemUI模块的源码。以下是具体步骤和关键位置: ### 核心修改位置 1. **布局文件修改** ```xml <!-- 文件路径:SystemUI/res/layout/status_bar.xml --> <com.android.systemui.BatteryMeterView android:id="@+id/battery" android:layout_width="wrap_content" android:layout_height="wrap_content" android:visibility="gone" /> <!-- 添加此属性隐藏电池图标 --> ``` 2. **控制逻辑修改(可选)** ```java // 文件路径:SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java protected void createStatusBarWindow() { ... mBatteryView = mStatusBarView.findViewById(R.id.battery); mBatteryView.setVisibility(View.GONE); // 强制隐藏电池视图 } ``` ### 详细操作步骤 1. **修改布局文件** - 找到`status_bar.xml`布局文件 - 给`BatteryMeterView`添加`android:visibility="gone"`属性 2. **重新编译SystemUI** ```bash make SystemUI && adb push out/target/product/{device}/system/priv-app/SystemUI/SystemUI.apk /system/priv-app/SystemUI/ ``` 3. **清除旧数据** ```bash adb shell pm clear com.android.systemui ``` ### 注意事项 1. 不同厂商ROM可能自定义了状态栏布局(如`quick_status_bar.xml`) 2. 若需保留电量百分比文字显示,需单独处理`BatteryPercentTextView` 3. Android 10+版本需修改`status_bar.xml`中的`battery_container`布局 > 完整实现需要同步修改`BatteryController`相关逻辑,防止系统异常调用隐藏的电池组件。建议通过`config.xml`添加开关控制更符合开发规范: > ```xml > <!-- SystemUI/res/values/config.xml --> > <bool name="config_showBatteryIndicator">false</bool> > ```
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值