背景
最近项目集成了三方锁屏应用,系统针对这个应用也需要做相应的特殊处理,比如禁用NavigationBar全部功能
google提供了隐藏NavigationBar的API,但这个API只能在隐藏并不能完全禁止NavigationBar,如果自己从底部还是可以将NavigationBar滑出来的
View decorView = getWindow().getDecorView();
int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | View.SYSTEM_UI_FLAG_FULLSCREEN;
decorView.setSystemUiVisibility(uiOptions);
修改方法
所以我们需要从framework层完全禁止SystemUI将NavigationBar滑出来
/frameworks/base/services/core/java/com/android/server/wm/DisplayPolicy.java
mSystemGestures = new SystemGesturesPointerEventListener(mContext, mHandler,
new SystemGesturesPointerEventListener.Callbacks() {
@Override
public void onSwipeFromTop() {
if (mStatusBar != null) {
requestTransientBars(mStatusBar);
}
}
@Override
public void onSwipeFromBottom() {
if (mNavigationBar != null && mNavigationBarPosition == NAV_BAR_BOTTOM) {
requestTransientBars(mNavigationBar);
}
}
@Override
public void onSwipeFromRight() {
final Region excludedRegion;
synchronized (mLock) {
excludedRegion = mDisplayContent.calculateSystemGestureExclusion();
}
final boolean sideAllowed = mNavigationBarAlwaysShowOnSideGesture
|| mNavigationBarPosition == NAV_BAR_RIGHT;
if (mNavigationBar != null && sideAllowed
&& !mSystemGestures.currentGestureStartedInRegion(excludedRegion)) {
requestTransientBars(mNavigationBar);
}
}
@Override
public void onSwipeFromLeft() {
final Region excludedRegion;
synchronized (mLock) {
excludedRegion = mDisplayContent.calculateSystemGestureExclusion();
}
final boolean sideAllowed = mNavigationBarAlwaysShowOnSideGesture
|| mNavigationBarPosition == NAV_BAR_LEFT;
if (mNavigationBar != null && sideAllowed
&& !mSystemGestures.currentGestureStartedInRegion(excludedRegion)) {
requestTransientBars(mNavigationBar);
}
}
@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 onMouseHoverAtTop() {
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 onMouseHoverAtBottom() {
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 onMouseLeaveFromEdge() {
mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
}
/* add by cheng.luo for MMITest on 2019-07-15 - BEGIN */
private boolean isGestureIsolated() {
WindowState win = mFocusedWindow != null
? mFocusedWindow : mTopFullscreenOpaqueWindowState;
return isMMITestTop(win);
/* add by cheng.luo for MMITest on 2019-07-15 - BEGIN */
}
});
这是关于手势操作的一些回调比如onSwipeFromTop,onSwipeFromBottom,onSwipeFromLeft,onSwipeFromRight等等,分别对于从上往下滑,从下往上滑,从左往右滑,从右往左滑等,核心都是调用requestTransientBars
requestTransientBars
此方法最终会到SystemUI去控制StatusBar和NavigationBar的动作
private void requestTransientBars(WindowState swipeTarget) {
synchronized (mLock) {
if (!mService.mPolicy.isUserSetupComplete()) {
// Swipe-up for navigation bar is disabled during setup
return;
}
//检查是否满足滑动StatusBar的条件
boolean sb = mStatusBarController.checkShowTransientBarLw();
//检查是否满足滑动NavigationBar的条件
boolean nb = mNavigationBarController.checkShowTransientBarLw()
&& !isNavBarEmpty(mLastSystemUiFlags);
if (sb || nb) {
// Don't show status bar when swiping on already visible navigation bar
if (!nb && swipeTarget == mNavigationBar) {
if (DEBUG) Slog.d(TAG, "Not showing transient bar, wrong swipe target");
return;
}
if (sb) mStatusBarController.showTransient();
if (nb) mNavigationBarController.showTransient();
if (!SystemProperties.getBoolean("ro.vendor.tct.mmitest", false)){
mImmersiveModeConfirmation.confirmCurrentPrompt();
}
updateSystemUiVisibilityLw();
}
}
}
所以我们想完全禁用NavigationBar或者StatusBar就可以在上面回调中做相应判断,此方法中能够获取当前窗口的windowState,有了windowState就能够做足够判断了,比如我的需求是在三方锁屏的界面用户不可以通过底部上滑出Navigation,我就在onSwipeFromBottom里面判断当前窗口为三方锁屏则直接return