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,back1WC;home;recent1WC,right.5W</string>

<string name="config_navBarLayoutQuickstep" translatable="false">back1.7WC;home;contextual1.7WC</string>

<string name="config_navBarLayoutHandle" translatable="false">back70AC;home_handle;ime_switcher70AC</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,back1WC;home;recent1WC,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;

}

```

相关推荐
千里马学框架1 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台1 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone1 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc1 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo1 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077001 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼1 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone1 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen1 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone1 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui