Android13 关于SystemUI更新/Nav Bar add volume button&&other button

对比Android 11, Android 13的SystemUI的源码文件目录,部分文件位置移动了或者删除了,其它的做出了很多改变,变的更加清晰、模块化...

代码里面注解用的频繁了. Dragger2是一个依赖注入框架,在编译期间自动生成代码,负责依赖对象的创建.

[Dragger2](https://blog.csdn.net/qq_28898075/article/details/103145367)

SystemUI初始化

```

frameworks\base\packages\SystemUI\src\com\android\systemui\statusbar\phone\CentralSurfacesImpl.java

@Override

public void start() {

...

//statusBar相关,主要处理和信号有关的icon,比如mobile,wifi,vpn等

mStatusBarSignalPolicy.init();

...

createAndAddWindows(result);//入口,添加view的核心函数

...

//关于壁纸

if (mWallpaperSupported) {

// Make sure we always have the most current wallpaper info.

IntentFilter wallpaperChangedFilter = new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED);

mBroadcastDispatcher.registerReceiver(mWallpaperChangedReceiver, wallpaperChangedFilter,

null /* handler */, UserHandle.ALL);

mWallpaperChangedReceiver.onReceive(mContext, null);

} else if (DEBUG) {

Log.v(TAG, "start(): no wallpaper service ");

}

// Set up the initial notification state. This needs to happen before CommandQueue.disable()

//初始化通知栏状态

setUpPresenter();

...

// Lastly, call to the icon policy to install/update all the icons.

//状态栏上wifi,BT 等状态图标的更新

mIconPolicy.init();

...

}

@Override

public void createAndAddWindows(@Nullable RegisterStatusBarResult result) {

makeStatusBarView(result);

mNotificationShadeWindowController.attach();//添加通知

mStatusBarWindowController.attach();//添加状态栏

}

protected void makeStatusBarView(@Nullable RegisterStatusBarResult result) {

updateDisplaySize(); // populates mDisplayMetrics

updateResources();

updateTheme();

inflateStatusBarWindow();//状态栏初始化

mNotificationShadeWindowView.setOnTouchListener(getStatusBarWindowTouchListener());

mWallpaperController.setRootView(mNotificationShadeWindowView);

...

createNavigationBar(result);//导航栏初始化

...

}

protected void createNavigationBar(@Nullable RegisterStatusBarResult result) {

mNavigationBarController.createNavigationBars(true /* includeDefaultDisplay */, result);

}

```

[NavigationBar详解](https://juejin.cn/post/7223216421199315000)

关于导航栏的创建,系统会判断屏幕大小来决定是否生成NavigationBar.如果屏幕过大导致判定为平板,

就会走Launcher3里面的/quickstep/taskbar 来替代导航栏.

```

frameworks\base\packages\SystemUI\src\com\android\systemui\navigationbar\NavigationBarController.java

private boolean updateNavbarForTaskbar() {

boolean taskbarShown = initializeTaskbarIfNecessary();

if (!taskbarShown && mNavigationBars.get(mContext.getDisplayId()) == null) {

createNavigationBar(mContext.getDisplay(), null, null);

}

return taskbarShown;

}

/** 平板:true */

private boolean initializeTaskbarIfNecessary() {

// Enable for tablet or (phone AND flag is set); assuming phone = !mIsTablet

boolean taskbarEnabled = mIsTablet || mFeatureFlags.isEnabled(Flags.HIDE_NAVBAR_WINDOW);

if (taskbarEnabled) {

//是平板,移除屏幕上的navBar

removeNavigationBar(mContext.getDisplayId());

mTaskbarDelegate.init(mContext.getDisplayId());

} else {

mTaskbarDelegate.destroy();

}

return taskbarEnabled;

}

public void createNavigationBars(final boolean includeDefaultDisplay,

RegisterStatusBarResult result) {

updateAccessibilityButtonModeIfNeeded();

// Don't need to create nav bar on the default display if we initialize TaskBar.

final boolean shouldCreateDefaultNavbar = includeDefaultDisplay

&& !initializeTaskbarIfNecessary();

Display[] displays = mDisplayTracker.getAllDisplays();

for (Display display : displays) {

if (shouldCreateDefaultNavbar

|| display.getDisplayId() != mDisplayTracker.getDefaultDisplayId()) {

createNavigationBar(display, null /* savedState */, result);

}

}

}

@VisibleForTesting

void createNavigationBar(Display display, Bundle savedState, RegisterStatusBarResult result) {

...

//从这里分为两个部分

NavigationBar navBar = component.getNavigationBar();//导航栏实例化,navBar通过注解生成的

navBar.init();//将导航栏添加到屏幕上

mNavigationBars.put(displayId, navBar);

...

}

```

```

<!-- 分号隔开左中右,然后逗号隔开,w表示比重,A表示绝对值,C表示居中

left和right,分别是space和menu_ime

-->

<string name="config_navBarLayout" translatable="false">left[.5W],back[1WC];home;recent[1WC],right[.5W]</string>

<string name="config_navBarLayoutQuickstep" translatable="false">back[1.7WC];home;contextual[1.7WC]</string>

<string name="config_navBarLayoutHandle" translatable="false">back[70AC];home_handle;ime_switcher[70AC]</string>

```

1.config_navBarLayout配置更新

```

frameworks/base/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarInflaterView.java

protected String getDefaultLayout() {

final int defaultResource = QuickStepContract.isGesturalMode(mNavBarMode)

? R.string.config_navBarLayoutHandle

: mOverviewProxyService.shouldShowSwipeUpUI()

? R.string.config_navBarLayoutQuickstep

: R.string.config_navBarLayout;

return getContext().getString(defaultResource);

}

+++ b/frameworks/base/packages/SystemUI/res/values/config.xml

<!-- Nav bar button default ordering/layout -->

  • <string name="config_navBarLayout" translatable="false">left[.5W],back[1WC];home;recent[1WC],right[.5W]</string>
  • <string name="config_navBarLayout" translatable="false">left[.5W];volume_sub,back,home,recent,volume_add;right[.5W]</string>

```

2.准备对应的布局资源文件

```

//要变成减音量,keyCode="25",其余不变; 自定义按键:systemui:keyCode="0",其余不变

/SystemUI/res/layout/volume_add.xml

<com.android.systemui.navigationbar.buttons.KeyButtonView

xmlns:android="http://schemas.android.com/apk/res/android"

xmlns:systemui="http://schemas.android.com/apk/res-auto"

android:id="@+id/volume_add"

android:layout_width="@dimen/navigation_key_width"

android:layout_height="match_parent"

android:layout_weight="0"

systemui:keyCode="24"

android:scaleType="center"

android:contentDescription="@string/accessibility_home"

android:paddingStart="@dimen/navigation_key_padding"

android:paddingEnd="@dimen/navigation_key_padding"

/>

SystemUI/res/drawable/ic_sysbar_volume_add_button.xml

<vector xmlns:android="http://schemas.android.com/apk/res/android"

android:width="24dp"

android:height="24dp"

android:viewportWidth="24.0"

android:viewportHeight="24.0">

<path

android:fillColor="?attr/singleToneColor"

android:pathData="M3,9v6h4l5,5L12,4L7,9L3,9zM16.5,12c0,-1.77 -1.02,-3.29 -2.5,-4.03v8.05c1.48,-0.73 2.5,-2.25 2.5,-4.02zM14,3.23v2.06c2.89,0.86 5,3.54 5,6.71s-2.11,5.85 -5,6.71v2.06c4.01,-0.91 7,-4.49 7,-8.77s-2.99,-7.86 -7,-8.77z"/>

</vector>

SystemUI/res/drawable/ic_sysbar_volume_sub_button.xml

<vector xmlns:android="http://schemas.android.com/apk/res/android"

android:width="28dp"

android:height="28dp"

android:viewportWidth="24.0"

android:viewportHeight="24.0">

<path

android:fillColor="?attr/singleToneColor"

android:pathData="M18.5,12c0,-1.77 -1.02,-3.29 -2.5,-4.03v8.05c1.48,-0.73 2.5,-2.25 2.5,-4.02zM5,9v6h4l5,5V4L9,9H5z"/>

</vector>

```

3.按钮加入Nav Bar

```

+++ b/frameworks/base/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarInflaterView.java

@@ -68,7 +68,10 @@ public class NavigationBarInflaterView extends FrameLayout

public static final String RIGHT = "right";

public static final String CONTEXTUAL = "contextual";

public static final String IME_SWITCHER = "ime_switcher";

  • //add text

  • public static final String VOLUME_ADD = "volume_add";

  • public static final String VOLUME_SUB = "volume_sub";

  • //add text

public static final String GRAVITY_SEPARATOR = ";";

public static final String BUTTON_SEPARATOR = ",";

@@ -387,6 +390,10 @@ public class NavigationBarInflaterView extends FrameLayout

v = inflater.inflate(R.layout.home_handle, parent, false);

} else if (IME_SWITCHER.equals(button)) {

v = inflater.inflate(R.layout.ime_switcher, parent, false);

  • } else if (VOLUME_ADD.equals(button)) {

  • 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 (button.startsWith(KEY)) {

String uri = extractImage(button);

int code = extractKeycode(button);

+++ b/frameworks/base/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java

@@ -119,6 +119,10 @@ public class NavigationBarView extends FrameLayout {

private KeyButtonDrawable mHomeDefaultIcon;

private KeyButtonDrawable mRecentIcon;

private KeyButtonDrawable mDockedIcon;

  • //add add xxx

  • private KeyButtonDrawable mVolumeAddIcon;

  • private KeyButtonDrawable mVolumeSubIcon;

  • //add xxx

private Context mLightContext;

private int mLightIconColor;

private int mDarkIconColor;

@@ -323,6 +327,10 @@ public class NavigationBarView extends FrameLayout {

mButtonDispatchers.put(R.id.ime_switcher, imeSwitcherButton);

mButtonDispatchers.put(R.id.accessibility_button, accessibilityButton);

mButtonDispatchers.put(R.id.menu_container, mContextualButtonGroup);

  • //add add xxx

  • mButtonDispatchers.put(R.id.volume_add, new ButtonDispatcher(R.id.volume_add));

  • mButtonDispatchers.put(R.id.volume_sub, new ButtonDispatcher(R.id.volume_sub));

  • //add add xxx

mDeadZone = new DeadZone(this);

}

@@ -419,6 +427,16 @@ public class NavigationBarView extends FrameLayout {

return mButtonDispatchers.get(R.id.home);

}

  • //add add xxx

  • public ButtonDispatcher getVolumeAddButton() {

  • return mButtonDispatchers.get(R.id.volume_add);

  • }

  • public ButtonDispatcher getVolumeSubButton() {

  • return mButtonDispatchers.get(R.id.volume_sub);

  • }

  • //add xxx

public ButtonDispatcher getImeSwitchButton() {

return mButtonDispatchers.get(R.id.ime_switcher);

}

@@ -471,6 +489,10 @@ public class NavigationBarView extends FrameLayout {

if (orientationChange || densityChange || dirChange) {

mBackIcon = getBackDrawable();

}

  • //add add xxx

  • mVolumeAddIcon = getDrawable(R.drawable.ic_sysbar_volume_add_button);

  • mVolumeSubIcon = getDrawable(R.drawable.ic_sysbar_volume_sub_button);

  • //add xxx

}

/**

@@ -615,7 +637,10 @@ public class NavigationBarView extends FrameLayout {

}

getHomeButton().setImageDrawable(homeIcon);

getBackButton().setImageDrawable(backIcon);

  • //add add xxx

  • getVolumeAddButton().setImageDrawable(mVolumeAddIcon);

  • getVolumeSubButton().setImageDrawable(mVolumeSubIcon);

  • //add xxx

updateRecentsIcon();

// Update IME button visibility, a11y and rotate button always overrides the appearance

@@ -1146,6 +1171,10 @@ public class NavigationBarView extends FrameLayout {

dumpButton(pw, "back", getBackButton());

dumpButton(pw, "home", getHomeButton());

  • //add add xxx

  • dumpButton(pw, "volume_add", getVolumeAddButton());

  • dumpButton(pw, "volume_sub", getVolumeSubButton());

  • //add xxx

dumpButton(pw, "handle", getHomeHandle());

dumpButton(pw, "rcnt", getRecentsButton());

dumpButton(pw, "rota", getRotateSuggestionButton());

```

4.自定义按钮()的监听,无系统定义的keyCode,音量加减不用看这里

hide_nav布局模仿上面的顺序添加就行了.

```

+++ b/frameworks/base/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java

+import android.content.ContentResolver;

+import android.database.ContentObserver;

+import android.os.UserHandle;

+import android.provider.Settings;

  • //add text

  • private ContentResolver mContentResolver;

  • private ContentObserver mHideNavButtonShowObserver;

  • //add text

//模仿这里面的点击操作

private void prepareNavigationBarView() {

mView.reorient();

ButtonDispatcher recentsButton = mView.getRecentsButton();

recentsButton.setOnClickListener(this::onRecentsClick);

recentsButton.setOnTouchListener(this::onRecentsTouch);

  • //add text

  • ButtonDispatcher hideNavButton = mView.getHideNavButton();

  • hideNavButton.setOnClickListener(this::onHideNavClick);

  • boolean isShowNavHideButton = Settings.System.getInt(getContext().getContentResolver(), "hide_xx_status", 0) == 1;

  • if(isShowNavHideButton){

  • hideNavButton.setVisibility(View.VISIBLE);

  • }else{

  • hideNavButton.setVisibility(View.GONE);

  • }

  • //add text

...

ButtonDispatcher accessibilityButton = mView.getAccessibilityButton();

accessibilityButton.setOnClickListener(this::onAccessibilityClick);

accessibilityButton.setOnLongClickListener(this::onAccessibilityLongClick);

...

}

//add text

  • private long mLastClickNavHideTime = 0;

  • private void onHideNavClick(View v){

  • long nowTime = SystemClock.elapsedRealtime();

  • if (nowTime - mLastClickNavHideTime < 2000) {

  • return;

  • }

  • Intent intent = new Intent("action_xx_xxx");

  • getContext().sendBroadcast(intent);

  • mLastClickNavHideTime = nowTime;

  • }

  • //add text

@Override

public void onInit() {

mView.setBarTransitions(mNavigationBarTransitions);

mView.setTouchHandler(mTouchHandler);

...

//add text

mContentResolver = getContext().getContentResolver();

mHideNavButtonShowObserver = new ContentObserver(getContext().getMainThreadHandler()) {

@Override

public void onChange(boolean selfChange) {

boolean isShowNavHideButton = Settings.System.getInt(getContext().getContentResolver(), "hide_xx_status", 0) == 1;

ButtonDispatcher hideNavButton = mView.getHideNavButton();

hideNavButton.setVisibility(isShowNavHideButton ? View.VISIBLE : View.GONE);

}

};

mContentResolver.registerContentObserver(

Settings.System.getUriFor("hide_xx_status"), true,

mHideNavButtonShowObserver, UserHandle.USER_ALL);

//add text

}

@Override

public void onViewDetached() {

mView.setUpdateActiveTouchRegionsCallback(null);

getBarTransitions().destroy();

...

//add text

if(null != mHideNavButtonShowObserver){

mContentResolver.unregisterContentObserver(mHideNavButtonShowObserver);

}

//add text

}

Region getButtonLocations(boolean includeFloatingButtons, boolean inScreenSpace,

boolean useNearestRegion) {

if (useNearestRegion && !inScreenSpace) {

// We currently don't support getting the nearest region in anything but screen space

useNearestRegion = false;

}

Region region = new Region();

Map<View, Rect> touchRegionCache = mView.getButtonTouchRegionCache();

updateButtonLocation(

region, touchRegionCache, mView.getBackButton(), inScreenSpace, useNearestRegion);

...

//add text

updateButtonLocation(region, touchRegionCache, mView.getVolumeAddButton(), inScreenSpace,

useNearestRegion);

updateButtonLocation(region, touchRegionCache, mView.getVolumeSubButton(), inScreenSpace,

useNearestRegion);

//add text

...

return region;

}

```

[Android导航栏音量调节](https://blog.csdn.net/qq_27636049/article/details/103632949)

[Android13系统导航栏添加音量加减键按钮功能](https://blog.csdn.net/wzh048503/article/details/140020452)

[android framework13-SystemUI](https://juejin.cn/post/7223192684126535735)

禁止下拉状态栏菜单

```

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

public boolean panelsEnabled() {

  • final int disabled1 = getDisabled1(mDisplayTracker.getDefaultDisplayId());

  • final int disabled2 = getDisabled2(mDisplayTracker.getDefaultDisplayId());

  • return (disabled1 & StatusBarManager.DISABLE_EXPAND) == 0

  • && (disabled2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) == 0;

  • return false;

}

```

相关推荐
zhangphil1 小时前
Android绘图Path基于LinearGradient线性动画渐变,Kotlin(2)
android·kotlin
watl02 小时前
【Android】unzip aar删除冲突classes再zip
android·linux·运维
键盘上的蚂蚁-2 小时前
PHP爬虫类的并发与多线程处理技巧
android
喜欢猪猪3 小时前
Java技术专家视角解读:SQL优化与批处理在大数据处理中的应用及原理
android·python·adb
JasonYin~4 小时前
HarmonyOS NEXT 实战之元服务:静态案例效果---手机查看电量
android·华为·harmonyos
zhangphil4 小时前
Android adb查看某个进程的总线程数
android·adb
抛空5 小时前
Android14 - SystemServer进程的启动与工作流程分析
android
Gerry_Liang6 小时前
记一次 Android 高内存排查
android·性能优化·内存泄露·mat
天天打码8 小时前
ThinkPHP项目如何关闭runtime下Log日志文件记录
android·java·javascript
爱数学的程序猿10 小时前
Python入门:6.深入解析Python中的序列
android·服务器·python