From 85d202b18ada8dc95f151087ab9778d1a31f7a30 Mon Sep 17 00:00:00 2001 From: Adrian Roos Date: Thu, 2 Jun 2016 16:27:47 -0700 Subject: [PATCH] Seascape Navigation Bar View Allow placing navigation bar on the left side aka seascape. Also deal with fallout from this change in frame calculations, decor view, and all over SystemUI - notably no changes to the navigation bar view. Bug: 28823676 Change-Id: I91187a974a10a940787a858e2609f2e9c5bade78 --- .../policy/BackdropFrameRenderer.java | 6 +- .../android/internal/policy/DecorView.java | 74 ++++++++++--- .../android/systemui/statusbar/ScrimView.java | 21 +++- .../statusbar/phone/ScrimController.java | 4 + .../statusbar/phone/StatusBarWindowView.java | 19 ++-- .../server/policy/PhoneWindowManager.java | 103 ++++++++++++++---- .../SystemGesturesPointerEventListener.java | 10 ++ 7 files changed, 185 insertions(+), 52 deletions(-) diff --git a/core/java/com/android/internal/policy/BackdropFrameRenderer.java b/core/java/com/android/internal/policy/BackdropFrameRenderer.java index 28281b3ce7400..8addffb0ef413 100644 --- a/core/java/com/android/internal/policy/BackdropFrameRenderer.java +++ b/core/java/com/android/internal/policy/BackdropFrameRenderer.java @@ -370,6 +370,8 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame systemInsets.bottom); final int rightInset = DecorView.getColorViewRightInset(stableInsets.right, systemInsets.right); + final int leftInset = DecorView.getColorViewLeftInset(stableInsets.left, + systemInsets.left); if (mStatusBarColor != null) { mStatusBarColor.setBounds(0, 0, left + width, topInset); mStatusBarColor.draw(canvas); @@ -379,9 +381,11 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame // don't want the navigation bar background be moving around when resizing in docked mode. // However, we need it for the transitions into/out of docked mode. if (mNavigationBarColor != null && fullscreen) { - final int size = DecorView.getNavBarSize(bottomInset, rightInset); + final int size = DecorView.getNavBarSize(bottomInset, rightInset, leftInset); if (DecorView.isNavBarToRightEdge(bottomInset, rightInset)) { mNavigationBarColor.setBounds(width - size, 0, width, height); + } else if (DecorView.isNavBarToLeftEdge(bottomInset, rightInset)) { + mNavigationBarColor.setBounds(0, 0, size, height); } else { mNavigationBarColor.setBounds(0, height - size, width, height); } diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java index 7e38d9bc742d1..1099ef756efa3 100644 --- a/core/java/com/android/internal/policy/DecorView.java +++ b/core/java/com/android/internal/policy/DecorView.java @@ -97,7 +97,6 @@ import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACK import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; -import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION; import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; @@ -162,13 +161,13 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind private final ColorViewState mStatusColorViewState = new ColorViewState( SYSTEM_UI_FLAG_FULLSCREEN, FLAG_TRANSLUCENT_STATUS, - Gravity.TOP, Gravity.LEFT, + Gravity.TOP, Gravity.LEFT, Gravity.RIGHT, Window.STATUS_BAR_BACKGROUND_TRANSITION_NAME, com.android.internal.R.id.statusBarBackground, FLAG_FULLSCREEN); private final ColorViewState mNavigationColorViewState = new ColorViewState( SYSTEM_UI_FLAG_HIDE_NAVIGATION, FLAG_TRANSLUCENT_NAVIGATION, - Gravity.BOTTOM, Gravity.RIGHT, + Gravity.BOTTOM, Gravity.RIGHT, Gravity.LEFT, Window.NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME, com.android.internal.R.id.navigationBarBackground, 0 /* hideWindowFlag */); @@ -184,9 +183,11 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind private int mLastTopInset = 0; private int mLastBottomInset = 0; private int mLastRightInset = 0; + private int mLastLeftInset = 0; private boolean mLastHasTopStableInset = false; private boolean mLastHasBottomStableInset = false; private boolean mLastHasRightStableInset = false; + private boolean mLastHasLeftStableInset = false; private int mLastWindowFlags = 0; private boolean mLastShouldAlwaysConsumeNavBar = false; @@ -991,12 +992,21 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind return Math.min(stableRight, systemRight); } + static int getColorViewLeftInset(int stableLeft, int systemLeft) { + return Math.min(stableLeft, systemLeft); + } + static boolean isNavBarToRightEdge(int bottomInset, int rightInset) { return bottomInset == 0 && rightInset > 0; } - static int getNavBarSize(int bottomInset, int rightInset) { - return isNavBarToRightEdge(bottomInset, rightInset) ? rightInset : bottomInset; + static boolean isNavBarToLeftEdge(int bottomInset, int leftInset) { + return bottomInset == 0 && leftInset > 0; + } + + static int getNavBarSize(int bottomInset, int rightInset, int leftInset) { + return isNavBarToRightEdge(bottomInset, rightInset) ? rightInset + : isNavBarToLeftEdge(bottomInset, leftInset) ? leftInset : bottomInset; } WindowInsets updateColorViews(WindowInsets insets, boolean animate) { @@ -1016,6 +1026,8 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind insets.getSystemWindowInsetBottom()); mLastRightInset = getColorViewRightInset(insets.getStableInsetRight(), insets.getSystemWindowInsetRight()); + mLastLeftInset = getColorViewRightInset(insets.getStableInsetLeft(), + insets.getSystemWindowInsetLeft()); // Don't animate if the presence of stable insets has changed, because that // indicates that the window was either just added and received them for the @@ -1031,21 +1043,32 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind boolean hasRightStableInset = insets.getStableInsetRight() != 0; disallowAnimate |= (hasRightStableInset != mLastHasRightStableInset); mLastHasRightStableInset = hasRightStableInset; + + boolean hasLeftStableInset = insets.getStableInsetLeft() != 0; + disallowAnimate |= (hasLeftStableInset != mLastHasLeftStableInset); + mLastHasLeftStableInset = hasLeftStableInset; + mLastShouldAlwaysConsumeNavBar = insets.shouldAlwaysConsumeNavBar(); } boolean navBarToRightEdge = isNavBarToRightEdge(mLastBottomInset, mLastRightInset); - int navBarSize = getNavBarSize(mLastBottomInset, mLastRightInset); + boolean navBarToLeftEdge = isNavBarToLeftEdge(mLastBottomInset, mLastLeftInset); + int navBarSize = getNavBarSize(mLastBottomInset, mLastRightInset, mLastLeftInset); updateColorViewInt(mNavigationColorViewState, sysUiVisibility, - mWindow.mNavigationBarColor, navBarSize, navBarToRightEdge, - 0 /* rightInset */, animate && !disallowAnimate, false /* force */); + mWindow.mNavigationBarColor, navBarSize, navBarToRightEdge || navBarToLeftEdge, + navBarToLeftEdge, + 0 /* sideInset */, animate && !disallowAnimate, false /* force */); boolean statusBarNeedsRightInset = navBarToRightEdge && mNavigationColorViewState.present; - int statusBarRightInset = statusBarNeedsRightInset ? mLastRightInset : 0; + boolean statusBarNeedsLeftInset = navBarToLeftEdge + && mNavigationColorViewState.present; + int statusBarSideInset = statusBarNeedsRightInset ? mLastRightInset + : statusBarNeedsLeftInset ? mLastLeftInset : 0; updateColorViewInt(mStatusColorViewState, sysUiVisibility, calculateStatusBarColor(), mLastTopInset, - false /* matchVertical */, statusBarRightInset, animate && !disallowAnimate, + false /* matchVertical */, statusBarNeedsLeftInset, statusBarSideInset, + animate && !disallowAnimate, mForceWindowDrawsStatusBarBackground); } @@ -1070,15 +1093,17 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind int consumedTop = consumingStatusBar ? mLastTopInset : 0; int consumedRight = consumingNavBar ? mLastRightInset : 0; int consumedBottom = consumingNavBar ? mLastBottomInset : 0; + int consumedLeft = consumingNavBar ? mLastLeftInset : 0; if (mContentRoot != null && mContentRoot.getLayoutParams() instanceof MarginLayoutParams) { MarginLayoutParams lp = (MarginLayoutParams) mContentRoot.getLayoutParams(); if (lp.topMargin != consumedTop || lp.rightMargin != consumedRight - || lp.bottomMargin != consumedBottom) { + || lp.bottomMargin != consumedBottom || lp.leftMargin != consumedLeft) { lp.topMargin = consumedTop; lp.rightMargin = consumedRight; lp.bottomMargin = consumedBottom; + lp.leftMargin = consumedLeft; mContentRoot.setLayoutParams(lp); if (insets == null) { @@ -1089,7 +1114,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind } if (insets != null) { insets = insets.replaceSystemWindowInsets( - insets.getSystemWindowInsetLeft(), + insets.getSystemWindowInsetLeft() - consumedLeft, insets.getSystemWindowInsetTop() - consumedTop, insets.getSystemWindowInsetRight() - consumedRight, insets.getSystemWindowInsetBottom() - consumedBottom); @@ -1126,11 +1151,12 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind * @param size the current size in the non-parent-matching dimension. * @param verticalBar if true the view is attached to a vertical edge, otherwise to a * horizontal edge, - * @param rightMargin rightMargin for the color view. + * @param sideMargin sideMargin for the color view. * @param animate if true, the change will be animated. */ private void updateColorViewInt(final ColorViewState state, int sysUiVis, int color, - int size, boolean verticalBar, int rightMargin, boolean animate, boolean force) { + int size, boolean verticalBar, boolean seascape, int sideMargin, + boolean animate, boolean force) { state.present = (sysUiVis & state.systemUiHideFlag) == 0 && (mWindow.getAttributes().flags & state.hideWindowFlag) == 0 && ((mWindow.getAttributes().flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0 @@ -1145,7 +1171,9 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind int resolvedHeight = verticalBar ? LayoutParams.MATCH_PARENT : size; int resolvedWidth = verticalBar ? size : LayoutParams.MATCH_PARENT; - int resolvedGravity = verticalBar ? state.horizontalGravity : state.verticalGravity; + int resolvedGravity = verticalBar + ? (seascape ? state.seascapeGravity : state.horizontalGravity) + : state.verticalGravity; if (view == null) { if (showView) { @@ -1159,7 +1187,11 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind LayoutParams lp = new LayoutParams(resolvedWidth, resolvedHeight, resolvedGravity); - lp.rightMargin = rightMargin; + if (seascape) { + lp.leftMargin = sideMargin; + } else { + lp.rightMargin = sideMargin; + } addView(view, lp); updateColorViewTranslations(); } @@ -1168,12 +1200,16 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind visibilityChanged = state.targetVisibility != vis; state.targetVisibility = vis; LayoutParams lp = (LayoutParams) view.getLayoutParams(); + int rightMargin = seascape ? 0 : sideMargin; + int leftMargin = seascape ? sideMargin : 0; if (lp.height != resolvedHeight || lp.width != resolvedWidth - || lp.gravity != resolvedGravity || lp.rightMargin != rightMargin) { + || lp.gravity != resolvedGravity || lp.rightMargin != rightMargin + || lp.leftMargin != leftMargin) { lp.height = resolvedHeight; lp.width = resolvedWidth; lp.gravity = resolvedGravity; lp.rightMargin = rightMargin; + lp.leftMargin = leftMargin; view.setLayoutParams(lp); } if (showView) { @@ -2210,17 +2246,19 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind final int translucentFlag; final int verticalGravity; final int horizontalGravity; + final int seascapeGravity; final String transitionName; final int hideWindowFlag; ColorViewState(int systemUiHideFlag, int translucentFlag, int verticalGravity, int horizontalGravity, - String transitionName, int id, int hideWindowFlag) { + int seascapeGravity, String transitionName, int id, int hideWindowFlag) { this.id = id; this.systemUiHideFlag = systemUiHideFlag; this.translucentFlag = translucentFlag; this.verticalGravity = verticalGravity; this.horizontalGravity = horizontalGravity; + this.seascapeGravity = seascapeGravity; this.transitionName = transitionName; this.hideWindowFlag = hideWindowFlag; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java index dba7130793cad..bfa43fde03d0a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java @@ -42,6 +42,7 @@ public class ScrimView extends View private float mViewAlpha = 1.0f; private ValueAnimator mAlphaAnimator; private Rect mExcludedRect = new Rect(); + private int mLeftInset = 0; private boolean mHasExcludedArea; private ValueAnimator.AnimatorUpdateListener mAlphaUpdateListener = new ValueAnimator.AnimatorUpdateListener() { @@ -87,12 +88,12 @@ public class ScrimView extends View if (mExcludedRect.top > 0) { canvas.drawRect(0, 0, getWidth(), mExcludedRect.top, mPaint); } - if (mExcludedRect.left > 0) { - canvas.drawRect(0, mExcludedRect.top, mExcludedRect.left, mExcludedRect.bottom, - mPaint); + if (mExcludedRect.left + mLeftInset > 0) { + canvas.drawRect(0, mExcludedRect.top, mExcludedRect.left + mLeftInset, + mExcludedRect.bottom, mPaint); } - if (mExcludedRect.right < getWidth()) { - canvas.drawRect(mExcludedRect.right, + if (mExcludedRect.right + mLeftInset < getWidth()) { + canvas.drawRect(mExcludedRect.right + mLeftInset, mExcludedRect.top, getWidth(), mExcludedRect.bottom, @@ -183,4 +184,14 @@ public class ScrimView extends View public void setChangeRunnable(Runnable changeRunnable) { mChangeRunnable = changeRunnable; } + + public void setLeftInset(int leftInset) { + if (mLeftInset != leftInset) { + mLeftInset = leftInset; + + if (mHasExcludedArea) { + invalidate(); + } + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java index 9c4480e60efaa..135c294987cf6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java @@ -524,6 +524,10 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, mScrimBehind.setExcludedArea(area); } + public void setLeftInset(int inset) { + mScrimBehind.setLeftInset(inset); + } + public int getScrimBehindColor() { return mScrimBehind.getScrimColorWithAlpha(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java index ebfa0183f8b30..7b22b882abab6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java @@ -70,6 +70,7 @@ public class StatusBarWindowView extends FrameLayout { private View mBrightnessMirror; private int mRightInset = 0; + private int mLeftInset = 0; private PhoneStatusBar mService; private final Paint mTransparentSrcPaint = new Paint(); @@ -93,25 +94,26 @@ public class StatusBarWindowView extends FrameLayout { @Override protected boolean fitSystemWindows(Rect insets) { if (getFitsSystemWindows()) { - boolean paddingChanged = insets.left != getPaddingLeft() - || insets.top != getPaddingTop() + boolean paddingChanged = insets.top != getPaddingTop() || insets.bottom != getPaddingBottom(); // Super-special right inset handling, because scrims and backdrop need to ignore it. - if (insets.right != mRightInset) { + if (insets.right != mRightInset || insets.left != mLeftInset) { mRightInset = insets.right; + mLeftInset = insets.left; applyMargins(); } - // Drop top inset, apply left inset and pass through bottom inset. + // Drop top inset, and pass through bottom inset. if (paddingChanged) { - setPadding(insets.left, 0, 0, 0); + setPadding(0, 0, 0, 0); } insets.left = 0; insets.top = 0; insets.right = 0; } else { - if (mRightInset != 0) { + if (mRightInset != 0 || mLeftInset != 0) { mRightInset = 0; + mLeftInset = 0; applyMargins(); } boolean changed = getPaddingLeft() != 0 @@ -127,13 +129,16 @@ public class StatusBarWindowView extends FrameLayout { } private void applyMargins() { + mService.mScrimController.setLeftInset(mLeftInset); final int N = getChildCount(); for (int i = 0; i < N; i++) { View child = getChildAt(i); if (child.getLayoutParams() instanceof LayoutParams) { LayoutParams lp = (LayoutParams) child.getLayoutParams(); - if (!lp.ignoreRightInset && lp.rightMargin != mRightInset) { + if (!lp.ignoreRightInset + && (lp.rightMargin != mRightInset || lp.leftMargin != mLeftInset)) { lp.rightMargin = mRightInset; + lp.leftMargin = mLeftInset; child.requestLayout(); } } diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 14ed1907b9a04..f9eeda41fab81 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -262,6 +262,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { private static final String SYSUI_SCREENSHOT_ERROR_RECEIVER = "com.android.systemui.screenshot.ScreenshotServiceErrorReceiver"; + private static final int NAV_BAR_BOTTOM = 0; + private static final int NAV_BAR_RIGHT = 1; + private static final int NAV_BAR_LEFT = 2; + /** * Keyguard stuff */ @@ -354,9 +358,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { int mStatusBarHeight; WindowState mNavigationBar = null; boolean mHasNavigationBar = false; - boolean mCanHideNavigationBar = false; boolean mNavigationBarCanMove = false; // can the navigation bar ever move to the side? - boolean mNavigationBarOnBottom = true; // is the navigation bar on the bottom *right now*? + int mNavigationBarPosition = NAV_BAR_BOTTOM; int[] mNavigationBarHeightForRotationDefault = new int[4]; int[] mNavigationBarWidthForRotationDefault = new int[4]; int[] mNavigationBarHeightForRotationInCarMode = new int[4]; @@ -1683,13 +1686,19 @@ public class PhoneWindowManager implements WindowManagerPolicy { } @Override public void onSwipeFromBottom() { - if (mNavigationBar != null && mNavigationBarOnBottom) { + if (mNavigationBar != null && mNavigationBarPosition == NAV_BAR_BOTTOM) { requestTransientBars(mNavigationBar); } } @Override public void onSwipeFromRight() { - if (mNavigationBar != null && !mNavigationBarOnBottom) { + if (mNavigationBar != null && mNavigationBarPosition == NAV_BAR_RIGHT) { + requestTransientBars(mNavigationBar); + } + } + @Override + public void onSwipeFromLeft() { + if (mNavigationBar != null && mNavigationBarPosition == NAV_BAR_LEFT) { requestTransientBars(mNavigationBar); } } @@ -2784,8 +2793,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (win.getAttrs().windowAnimations != 0) { return 0; } - // This can be on either the bottom or the right. - if (mNavigationBarOnBottom) { + // This can be on either the bottom or the right or the left. + if (mNavigationBarPosition == NAV_BAR_BOTTOM) { if (transit == TRANSIT_EXIT || transit == TRANSIT_HIDE) { return R.anim.dock_bottom_exit; @@ -2793,7 +2802,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { || transit == TRANSIT_SHOW) { return R.anim.dock_bottom_enter; } - } else { + } else if (mNavigationBarPosition == NAV_BAR_RIGHT) { if (transit == TRANSIT_EXIT || transit == TRANSIT_HIDE) { return R.anim.dock_right_exit; @@ -2801,6 +2810,14 @@ public class PhoneWindowManager implements WindowManagerPolicy { || transit == TRANSIT_SHOW) { return R.anim.dock_right_enter; } + } else if (mNavigationBarPosition == NAV_BAR_LEFT) { + if (transit == TRANSIT_EXIT + || transit == TRANSIT_HIDE) { + return R.anim.dock_left_exit; + } else if (transit == TRANSIT_ENTER + || transit == TRANSIT_SHOW) { + return R.anim.dock_left_enter; + } } } else if (win.getAttrs().type == TYPE_DOCK_DIVIDER) { return selectDockedDividerAnimationLw(win, transit); @@ -2829,10 +2846,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { // If the divider is behind the navigation bar, don't animate. final Rect frame = win.getFrameLw(); final boolean behindNavBar = mNavigationBar != null - && ((mNavigationBarOnBottom + && ((mNavigationBarPosition == NAV_BAR_BOTTOM && frame.top + insets >= mNavigationBar.getFrameLw().top) - || (!mNavigationBarOnBottom - && frame.left + insets >= mNavigationBar.getFrameLw().left)); + || (mNavigationBarPosition == NAV_BAR_RIGHT + && frame.left + insets >= mNavigationBar.getFrameLw().left) + || (mNavigationBarPosition == NAV_BAR_LEFT + && frame.right - insets <= mNavigationBar.getFrameLw().right)); final boolean landscape = frame.height() > frame.width(); final boolean offscreenLandscape = landscape && (frame.right - insets <= 0 || frame.left + insets >= win.getDisplayFrameLw().right); @@ -4025,7 +4044,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { navVisible |= !canHideNavigationBar(); boolean updateSysUiVisibility = layoutNavigationBar(displayWidth, displayHeight, - displayRotation, uiMode, overscanRight, overscanBottom, dcf, navVisible, navTranslucent, + displayRotation, uiMode, overscanLeft, overscanRight, overscanBottom, dcf, navVisible, navTranslucent, navAllowedHidden, statusBarExpandedNotKeyguard); if (DEBUG_LAYOUT) Slog.i(TAG, String.format("mDock rect: (%d,%d - %d,%d)", mDockLeft, mDockTop, mDockRight, mDockBottom)); @@ -4104,8 +4123,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { } private boolean layoutNavigationBar(int displayWidth, int displayHeight, int displayRotation, - int uiMode, int overscanRight, int overscanBottom, Rect dcf, boolean navVisible, - boolean navTranslucent, boolean navAllowedHidden, + int uiMode, int overscanLeft, int overscanRight, int overscanBottom, Rect dcf, + boolean navVisible, boolean navTranslucent, boolean navAllowedHidden, boolean statusBarExpandedNotKeyguard) { if (mNavigationBar != null) { boolean transientNavBarShowing = mNavigationBarController.isTransientShowing(); @@ -4113,8 +4132,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { // size. We need to do this directly, instead of relying on // it to bubble up from the nav bar, because this needs to // change atomically with screen rotations. - mNavigationBarOnBottom = isNavigationBarOnBottom(displayWidth, displayHeight); - if (mNavigationBarOnBottom) { + mNavigationBarPosition = navigationBarPosition(displayWidth, displayHeight, + displayRotation); + if (mNavigationBarPosition == NAV_BAR_BOTTOM) { // It's a system nav bar or a portrait screen; nav bar goes on bottom. int top = displayHeight - overscanBottom - getNavigationBarHeight(displayRotation, uiMode); @@ -4140,7 +4160,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { // we can tell the app that it is covered by it. mSystemBottom = mTmpNavigationFrame.top; } - } else { + } else if (mNavigationBarPosition == NAV_BAR_RIGHT) { // Landscape screen; nav bar goes to the right. int left = displayWidth - overscanRight - getNavigationBarWidth(displayRotation, uiMode); @@ -4166,6 +4186,33 @@ public class PhoneWindowManager implements WindowManagerPolicy { // we can tell the app that it is covered by it. mSystemRight = mTmpNavigationFrame.left; } + } else if (mNavigationBarPosition == NAV_BAR_LEFT) { + // Seascape screen; nav bar goes to the left. + int right = overscanLeft + getNavigationBarWidth(displayRotation, uiMode); + mTmpNavigationFrame.set(overscanLeft, 0, right, displayHeight); + mStableLeft = mStableFullscreenLeft = mTmpNavigationFrame.right; + if (transientNavBarShowing) { + mNavigationBarController.setBarShowingLw(true); + } else if (navVisible) { + mNavigationBarController.setBarShowingLw(true); + mDockLeft = mTmpNavigationFrame.right; + // TODO: not so sure about those: + mRestrictedScreenLeft = mRestrictedOverscanScreenLeft = mDockLeft; + mRestrictedScreenWidth = mDockRight - mRestrictedScreenLeft; + mRestrictedOverscanScreenWidth = mDockRight - mRestrictedOverscanScreenLeft; + } else { + // We currently want to hide the navigation UI - unless we expanded the status + // bar. + mNavigationBarController.setBarShowingLw(statusBarExpandedNotKeyguard); + } + if (navVisible && !navTranslucent && !navAllowedHidden + && !mNavigationBar.isAnimatingLw() + && !mNavigationBarController.wasRecentlyTranslucent()) { + // If the nav bar is currently requested to be visible, + // and not in the process of animating on or off, then + // we can tell the app that it is covered by it. + mSystemLeft = mTmpNavigationFrame.right; + } } // Make sure the content and current rectangles are updated to // account for the restrictions from the navigation bar. @@ -4186,8 +4233,15 @@ public class PhoneWindowManager implements WindowManagerPolicy { return false; } - private boolean isNavigationBarOnBottom(int displayWidth, int displayHeight) { - return !mNavigationBarCanMove || displayWidth < displayHeight; + private int navigationBarPosition(int displayWidth, int displayHeight, int displayRotation) { + if (mNavigationBarCanMove && displayWidth > displayHeight) { + if (displayRotation == Surface.ROTATION_270) { + return NAV_BAR_LEFT; + } else { + return NAV_BAR_RIGHT; + } + } + return NAV_BAR_BOTTOM; } /** {@inheritDoc} */ @@ -4363,7 +4417,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (mStatusBar != null && mFocusedWindow == mStatusBar && canReceiveInput(mStatusBar)) { // The status bar forces the navigation bar while it's visible. Make sure the IME // avoids the navigation bar in that case. - pf.right = df.right = of.right = cf.right = vf.right = mStableRight; + if (mNavigationBarPosition == NAV_BAR_RIGHT) { + pf.right = df.right = of.right = cf.right = vf.right = mStableRight; + } else if (mNavigationBarPosition == NAV_BAR_LEFT) { + pf.left = df.left = of.left = cf.left = vf.left = mStableLeft; + } } // IM dock windows always go to the bottom of the screen. attrs.gravity = Gravity.BOTTOM; @@ -6464,10 +6522,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { // Only navigation bar if (mNavigationBar != null) { - if (isNavigationBarOnBottom(displayWidth, displayHeight)) { + int position = navigationBarPosition(displayWidth, displayHeight, displayRotation); + if (position == NAV_BAR_BOTTOM) { outInsets.bottom = getNavigationBarHeight(displayRotation, mUiMode); - } else { + } else if (position == NAV_BAR_RIGHT) { outInsets.right = getNavigationBarWidth(displayRotation, mUiMode); + } else if (position == NAV_BAR_LEFT) { + outInsets.left = getNavigationBarWidth(displayRotation, mUiMode); } } } diff --git a/services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java b/services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java index 80e43417f6478..598c58e50e792 100644 --- a/services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java +++ b/services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java @@ -43,6 +43,7 @@ public class SystemGesturesPointerEventListener implements PointerEventListener private static final int SWIPE_FROM_TOP = 1; private static final int SWIPE_FROM_BOTTOM = 2; private static final int SWIPE_FROM_RIGHT = 3; + private static final int SWIPE_FROM_LEFT = 4; private final Context mContext; private final int mSwipeStartThreshold; @@ -127,6 +128,9 @@ public class SystemGesturesPointerEventListener implements PointerEventListener } else if (swipe == SWIPE_FROM_RIGHT) { if (DEBUG) Slog.d(TAG, "Firing onSwipeFromRight"); mCallbacks.onSwipeFromRight(); + } else if (swipe == SWIPE_FROM_LEFT) { + if (DEBUG) Slog.d(TAG, "Firing onSwipeFromLeft"); + mCallbacks.onSwipeFromLeft(); } } break; @@ -229,6 +233,11 @@ public class SystemGesturesPointerEventListener implements PointerEventListener && elapsed < SWIPE_TIMEOUT_MS) { return SWIPE_FROM_RIGHT; } + if (fromX <= mSwipeStartThreshold + && x > fromX + mSwipeDistanceThreshold + && elapsed < SWIPE_TIMEOUT_MS) { + return SWIPE_FROM_LEFT; + } return SWIPE_NONE; } @@ -265,6 +274,7 @@ public class SystemGesturesPointerEventListener implements PointerEventListener void onSwipeFromTop(); void onSwipeFromBottom(); void onSwipeFromRight(); + void onSwipeFromLeft(); void onFling(int durationMs); void onDown(); void onUpOrCancel();