导航栏添加一个虚拟按钮
按钮功能:显示隐藏导航栏
1.frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/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);
}
//R.string.config_navBarLayout,构成底部按钮的文件
2.frameworks/base/packages/SystemUI/res/values/config.xml,nav_hide,就是新增按钮的名称
<string name="config_navBarLayout" translatable="false">left[.5W];volume_sub,back,home,recent,volume_add,nav_hide,screenshot;right[.5W]</string>
//sw是smallwidth的意思,当屏幕的最小边像素大于900 就会使用values-sw900dp,根据 config_navBarLayout_right 的值 来计算每个图标的宽度 如果为 W或WC 则表示为weight 如果为AC 则表示是像素值
3.给新添加的button 创建layout布局, 默认放在layout文件夹下
<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/nav_hide"
android:layout_width="@dimen/navigation_key_width"
android:layout_height="match_parent"
android:layout_weight="0"
systemui:keyCode="101"
android:scaleType="center"
android:contentDescription="hide"
android:paddingStart="@dimen/navigation_key_padding"
android:paddingEnd="@dimen/navigation_key_padding"
/>
4.将按钮布局,添加进入导航栏布局中.
/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
private View createView(String buttonSpec, ViewGroup parent, LayoutInflater inflater) {
...
} else if (VOLUME_SUB.equals(button)) {
v = inflater.inflate(R.layout.volume_sub, parent, false);
} else if (NAV_HIDE.equals(button)) {
v = inflater.inflate(R.layout.nav_hide, parent, false);//add
}
...
}
5.为按钮添加图片和点击事件
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
//仿照系统原有的按钮比如home或Screenshot(截屏)做就行了
@@ -125,6 +125,7 @@ public class NavigationBarView extends FrameLayout implements
private KeyButtonDrawable mVolumeAddIcon;
private KeyButtonDrawable mVolumeSubIcon;
private KeyButtonDrawable mScreenshotIcon;
+ private KeyButtonDrawable mNavHideIcon;//add hide nav
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.nav_hide, new ButtonDispatcher(R.id.nav_hide));//add hide nav
mDeadZone = new DeadZone(this);
mNavColorSampleMargin = getResources()
@@ -483,6 +485,12 @@ public class NavigationBarView extends FrameLayout implements
return mButtonDispatchers.get(R.id.screenshot);
}
+ //add hide nav
+ public ButtonDispatcher getNavHideButton(){
+ return mButtonDispatchers.get(R.id.nav_hide);
+ }
+ //add hide nav
+
public ButtonDispatcher getVolumeAddButton() {
return mButtonDispatchers.get(R.id.volume_add);
}
@@ -539,6 +547,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);
+ mNavHideIcon = getDrawable(R.drawable.ic_sysbar_hide);//add hide nav
}
public KeyButtonDrawable getBackDrawable() {
@@ -695,7 +704,7 @@ public class NavigationBarView extends FrameLayout implements
getVolumeAddButton().setImageDrawable(mVolumeAddIcon);
getVolumeSubButton().setImageDrawable(mVolumeSubIcon);
getScreenshotButton().setImageDrawable(mScreenshotIcon);
-
+ getNavHideButton().setImageDrawable(mNavHideIcon);//add hide nav
updateRecentsIcon();
// Update IME button visibility, a11y and rotate button always overrides the appearance
@@ -745,6 +754,7 @@ public class NavigationBarView extends FrameLayout implements
getHomeButton().setVisibility(disableHome ? View.INVISIBLE : View.VISIBLE);
getRecentsButton().setVisibility(disableRecent ? View.INVISIBLE : View.VISIBLE);
getHomeHandle().setVisibility(disableHomeHandle ? View.INVISIBLE : View.VISIBLE);
+ getNavHideButton().setVisibility(View.VISIBLE);//add hide nav
notifyActiveTouchRegions();
}
6.最重要一步,点击事件响应,之前布局的keyCode
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
case MotionEvent.ACTION_UP:
final boolean doIt = isPressed() && !mLongClicked;
setPressed(false);
final boolean doHapticFeedback = (SystemClock.uptimeMillis() - mDownTime) > 150;
if (showSwipeUI) {
if (doIt) {
// Apply haptic feedback on touch up since there is none on touch down
performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
playSoundEffect(SoundEffectConstants.CLICK);
}
} else if (doHapticFeedback && !mLongClicked) {
// Always send a release ourselves because it doesn't seem to be sent elsewhere
// and it feels weird to sometimes get a release haptic and other times not.
performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY_RELEASE);
}
if (mCode != KEYCODE_UNKNOWN) {
if(mCode == 101){
//do it
}else if(mCode == 102){
....
}
if (doIt) {
sendEvent(KeyEvent.ACTION_UP, 0);
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
} else {
sendEvent(KeyEvent.ACTION_UP, KeyEvent.FLAG_CANCELED);
}
} else {
// no key code, just a regular ImageView
if (doIt && mOnClickListener != null) {
mOnClickListener.onClick(this);
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
}
}
removeCallbacks(mCheckLongPress);
break;
}
7.系统的手势监听,隐藏之后上滑发送显示广播xxx
frameworks/base/services/core/java/com/android/server/wm/DisplayPolicy.java
mSystemGestures = new SystemGesturesPointerEventListener(mContext, mHandler,
new SystemGesturesPointerEventListener.Callbacks() {
@Override
public void onSwipeFromTop() {
synchronized (mLock) {
if (mStatusBar != null) {
requestTransientBars(mStatusBar);
}
checkAltBarSwipeForTransientBars(ALT_BAR_TOP);
//do it 下滑 add
}
}
@Override
public void onSwipeFromBottom() {
synchronized (mLock) {
if (mNavigationBar != null
&& mNavigationBarPosition == NAV_BAR_BOTTOM) {
requestTransientBars(mNavigationBar);
}
checkAltBarSwipeForTransientBars(ALT_BAR_BOTTOM);
//do it 上滑 add
}
}
@Override
public void onSwipeFromRight() {
final Region excludedRegion = Region.obtain();
synchronized (mLock) {
mDisplayContent.calculateSystemGestureExclusion(
excludedRegion, null /* outUnrestricted */);
final boolean sideAllowed = mNavigationBarAlwaysShowOnSideGesture
|| mNavigationBarPosition == NAV_BAR_RIGHT;
if (mNavigationBar != null && sideAllowed
&& !mSystemGestures.currentGestureStartedInRegion(
excludedRegion)) {
requestTransientBars(mNavigationBar);
}
checkAltBarSwipeForTransientBars(ALT_BAR_RIGHT);
}
excludedRegion.recycle();
}
@Override
public void onSwipeFromLeft() {
final Region excludedRegion = Region.obtain();
synchronized (mLock) {
mDisplayContent.calculateSystemGestureExclusion(
excludedRegion, null /* outUnrestricted */);
final boolean sideAllowed = mNavigationBarAlwaysShowOnSideGesture
|| mNavigationBarPosition == NAV_BAR_LEFT;
if (mNavigationBar != null && sideAllowed
&& !mSystemGestures.currentGestureStartedInRegion(
excludedRegion)) {
requestTransientBars(mNavigationBar);
}
checkAltBarSwipeForTransientBars(ALT_BAR_LEFT);
}
excludedRegion.recycle();
}
@Override
public void onFling(int duration) {
if (mService.mPowerManagerInternal != null) {
mService.mPowerManagerInternal.powerHint(
PowerHint.INTERACTION, duration);
}
}
@Override
public void onDebug() {
// no-op
}
private WindowOrientationListener getOrientationListener() {
final DisplayRotation rotation = mDisplayContent.getDisplayRotation();
return rotation != null ? rotation.getOrientationListener() : null;
}
@Override
public void onDown() {
final WindowOrientationListener listener = getOrientationListener();
if (listener != null) {
listener.onTouchStart();
}
}
@Override
public void onUpOrCancel() {
final WindowOrientationListener listener = getOrientationListener();
if (listener != null) {
listener.onTouchEnd();
}
}
@Override
public void onm ouseHoverAtTop() {
mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS);
msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS;
mHandler.sendMessageDelayed(msg, 500 /* delayMillis */);
}
@Override
public void onm ouseHoverAtBottom() {
mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS);
msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION;
mHandler.sendMessageDelayed(msg, 500 /* delayMillis */);
}
@Override
public void onm ouseLeaveFromEdge() {
mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
}
});
8.创造导航栏和移除导航栏方法
/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
@@ -164,7 +164,7 @@ public class NavigationBarController implements Callbacks {
});
}
public void createNavigationBars(final boolean includeDefaultDisplay,
RegisterStatusBarResult result) {...
//隐藏导航栏方法变为public 方便调用
- private void removeNavigationBar(int displayId) {
+ public void removeNavigationBar(int displayId) {
NavigationBarFragment navBar = mNavigationBars.get(displayId);
if (navBar != null) {
View navigationWindow = navBar.getView().getRootView();
....
//或者自己建立一个类似removeNavigationBar add
public void reomveNavigationBar_2() {
Display[] displays = mDisplayManager.getDisplays();
for (Display display : displays) {
removeNavigationBar(display.getDisplayId());
}
}
9.具体使用
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
private void HideStatusBar() {
if (all_hide_bar == 1) return;
if (mPhoneStatusBarWindow.getVisibility() == View.VISIBLE) {
mPhoneStatusBarWindow.setVisibility(View.GONE);
}
}
private void ShowStatusBar() {
if (all_hide_bar == 1) return;
if (mPhoneStatusBarWindow.getVisibility() == View.GONE) {
mPhoneStatusBarWindow.setVisibility(View.VISIBLE);
}
}
private boolean flag = true;
private void HideNavigationBar() {
if (flag) {
NavigationBarView mNavigationBarView = mNavigationBarController.getDefaultNavigationBarView();
if (mNavigationBarView != null) {
mNavigationBarController.removeNavigationBar_2();
}
flag = false;
}
}
private void ShowNavigationBar() {
//flag 设备重启默认是true,在初始化的时候,已经添加了导航栏,它的作用是防止systemUI初始化时,二次添加导致异常
if (!flag) {
NavigationBarView mNavigationBarView = mNavigationBarController.getDefaultNavigationBarView();
if (mNavigationBarView == null) {
mNavigationBarController.createNavigationBars(true, null);
}
flag = true;
}
}
Android 12 自定义底部导航栏 - xiaowang_lj - 博客园 (cnblogs.com)
Android12 隐藏状态栏导航栏 - simple雨 - 博客园 (cnblogs.com)
Android 11 关于系统应用发送广播 Sending non-protected broadcast 警告
1.带android:sharedUserId=“android.uid.system” 发送广播时,会出现 Sending non-protected broadcast
2.如果是非系统应用,想要发送一样的广播,也会报错 SecurityException: Permission Denial: not allowed to send broadcast XXX
如何修改:
/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
@Override
public boolean isProtectedBroadcast(String actionName) {
// allow instant applications
synchronized (mProtectedBroadcasts) {
if (mProtectedBroadcasts.contains(actionName)) {
return true;
} else if (actionName != null) {
// TODO: remove these terrible hacks
if (actionName.startsWith("android.net.netmon.lingerExpired")
|| actionName.startsWith("com.android.server.sip.SipWakeupTimer")
|| actionName.startsWith("com.android.internal.telephony.data-reconnect")
|| actionName.startsWith("android.net.netmon.launchCaptivePortalApp")) {
//在上面的函数上添加你需要过滤的广播名字
return true;
}
}
}
return false;
}
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
private void checkBroadcastFromSystem(Intent intent, ProcessRecord callerApp,
String callerPackage, int callingUid, boolean isProtectedBroadcast, List receivers) {
if ((intent.getFlags() & Intent.FLAG_RECEIVER_FROM_SHELL) != 0) {
// Don't yell about broadcasts sent via shell
return;
}
final String action = intent.getAction();
if (isProtectedBroadcast
|| Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)
|| Intent.ACTION_DISMISS_KEYBOARD_SHORTCUTS.equals(action)
|| Intent.ACTION_MEDIA_BUTTON.equals(action)
|| Intent.ACTION_MEDIA_SCANNER_SCAN_FILE.equals(action)
|| Intent.ACTION_SHOW_KEYBOARD_SHORTCUTS.equals(action)
|| Intent.ACTION_MASTER_CLEAR.equals(action)
|| Intent.ACTION_FACTORY_RESET.equals(action)
|| AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(action)
|| AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)
|| LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION.equals(action)
|| TelephonyManager.ACTION_REQUEST_OMADM_CONFIGURATION_UPDATE.equals(action)
|| SuggestionSpan.ACTION_SUGGESTION_PICKED.equals(action)
|| AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION.equals(action)
|| AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION.equals(action)) {
// Broadcast is either protected, or it's a public action that
// we've relaxed, so it's fine for system internals to send.
android.util.Log.d("tag","relax");
return;
}
//add
if(xxx){
// we've relaxed, so it's fine for system internals to send.
return;
}
//end
...
// The vast majority of broadcasts sent from system internals
// should be protected to avoid security holes, so yell loudly
// to ensure we examine these cases.
if (callerApp != null) {
Log.wtf(TAG, "Sending non-protected broadcast " + action
+ " from system " + callerApp.toShortString() + " pkg " + callerPackage,
new Throwable());
} else {
Log.wtf(TAG, "Sending non-protected broadcast " + action
+ " from system uid " + UserHandle.formatUid(callingUid)
+ " pkg " + callerPackage,
new Throwable());
}
}
标签:11,--,void,ACTION,add,action,Android,null,public
From: https://www.cnblogs.com/kato-T/p/18133234