Android13 关于SystemUI更新/Nav Bar add volume button&&other button
对比Android 11, Android 13的SystemUI的源码文件目录,部分文件位置移动了或者删除了,其它的做出了很多改变,变的更加清晰、模块化...
代码里面注解用的频繁了. Dragger2是一个依赖注入框架,在编译期间自动生成代码,负责依赖对象的创建.
Dragger2
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详解
关于导航栏的创建,系统会判断屏幕大小来决定是否生成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>
Nav Bar add volume button(+,-)&&other button
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导航栏音量调节
Android13系统导航栏添加音量加减键按钮功能
android framework13-SystemUI
禁止下拉状态栏菜单
/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;
}