From 46e68011e76b0f0dce4f80dbc04490f26ef0e1f3 Mon Sep 17 00:00:00 2001 From: Evan Rosky Date: Fri, 10 Jul 2020 13:56:44 -0700 Subject: Finish supporting floating-IME alpha in split-screen There are a couple situations that cause floating IME: zero-sized frame due to fullscreenIme and the IME itself providing a frame that doesn't generate insets. This CL adds detection for an IME frame that doesn't provide insets and it also allows the subsidiary IME processers (like divider) to disable alpha animation. This is necessary because when divider adjust for ime, there is no content behind the ime, so we can't have it fade in/out; however, if the divider doesn't adjust, we want the fade in/out so it matches the ime behavior when not in split. Bug: 160915523 Test: Use fullscreen IME as well as making gboard floating. Open ime in either top or bottom for both cases. Change-Id: If6fd192c6e7f843a958d98bf40c4d0866d818394 --- .../stackdivider/DividerImeController.java | 13 +++-- .../android/systemui/wm/DisplayImeController.java | 67 +++++++++++++++++----- .../src/com/android/systemui/wm/DisplayLayout.java | 15 +++++ 3 files changed, 77 insertions(+), 18 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java index 9db389eba3d8..5ef6b5f2702a 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java @@ -126,18 +126,20 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor } @Override - public void onImeStartPositioning(int displayId, int hiddenTop, int shownTop, - boolean imeShouldShow, SurfaceControl.Transaction t) { + @ImeAnimationFlags + public int onImeStartPositioning(int displayId, int hiddenTop, int shownTop, + boolean imeShouldShow, boolean imeIsFloating, SurfaceControl.Transaction t) { mHiddenTop = hiddenTop; mShownTop = shownTop; mTargetShown = imeShouldShow; if (!isDividerVisible()) { - return; + return 0; } final boolean splitIsVisible = !getView().isHidden(); mSecondaryHasFocus = getSecondaryHasFocus(displayId); final boolean targetAdjusted = splitIsVisible && imeShouldShow && mSecondaryHasFocus - && !getLayout().mDisplayLayout.isLandscape() && !mSplits.mDivider.isMinimized(); + && !imeIsFloating && !getLayout().mDisplayLayout.isLandscape() + && !mSplits.mDivider.isMinimized(); if (mLastAdjustTop < 0) { mLastAdjustTop = imeShouldShow ? hiddenTop : shownTop; } else if (mLastAdjustTop != (imeShouldShow ? mShownTop : mHiddenTop)) { @@ -155,7 +157,7 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor if (mPaused) { mPausedTargetAdjusted = targetAdjusted; if (DEBUG) Slog.d(TAG, " ime starting but paused " + dumpState()); - return; + return (targetAdjusted || mAdjusted) ? IME_ANIMATION_NO_ALPHA : 0; } mTargetAdjusted = targetAdjusted; updateDimTargets(); @@ -174,6 +176,7 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor } else { mAdjustedWhileHidden = true; } + return (mTargetAdjusted || mAdjusted) ? IME_ANIMATION_NO_ALPHA : 0; } private void updateImeAdjustState() { diff --git a/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java b/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java index 1ce98eb152c8..926f653153ee 100644 --- a/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java +++ b/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java @@ -19,6 +19,7 @@ package com.android.systemui.wm; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; +import android.annotation.IntDef; import android.content.Context; import android.content.res.Configuration; import android.graphics.Point; @@ -136,12 +137,16 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged } } - private void dispatchStartPositioning(int displayId, int hiddenTop, int shownTop, - boolean show, SurfaceControl.Transaction t) { + @ImePositionProcessor.ImeAnimationFlags + private int dispatchStartPositioning(int displayId, int hiddenTop, int shownTop, + boolean show, boolean isFloating, SurfaceControl.Transaction t) { synchronized (mPositionProcessors) { + int flags = 0; for (ImePositionProcessor pp : mPositionProcessors) { - pp.onImeStartPositioning(displayId, hiddenTop, shownTop, show, t); + flags |= pp.onImeStartPositioning( + displayId, hiddenTop, shownTop, show, isFloating, t); } + return flags; } } @@ -184,6 +189,7 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged int mRotation = Surface.ROTATION_0; boolean mImeShowing = false; final Rect mImeFrame = new Rect(); + boolean mAnimateAlpha = true; PerDisplay(int displayId, int initialRotation) { mDisplayId = displayId; @@ -268,15 +274,29 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged return mImeFrame.top + (int) surfaceOffset; } + private boolean calcIsFloating(InsetsSource imeSource) { + final Rect frame = imeSource.getFrame(); + if (frame.height() == 0) { + return true; + } + // Some Floating Input Methods will still report a frame, but the frame is actually + // a nav-bar inset created by WM and not part of the IME (despite being reported as + // an IME inset). For now, we assume that no non-floating IME will be <= this nav bar + // frame height so any reported frame that is <= nav-bar frame height is assumed to + // be floating. + return frame.height() <= mSystemWindows.mDisplayController.getDisplayLayout(mDisplayId) + .navBarFrameHeight(); + } + private void startAnimation(final boolean show, final boolean forceRestart) { final InsetsSource imeSource = mInsetsState.getSource(InsetsState.ITYPE_IME); if (imeSource == null || mImeSourceControl == null) { return; } final Rect newFrame = imeSource.getFrame(); - final boolean isFloating = newFrame.height() == 0 && show; + final boolean isFloating = calcIsFloating(imeSource) && show; if (isFloating) { - // This is likely a "floating" or "expanded" IME, so to get animations, just + // This is a "floating" or "expanded" IME, so to get animations, just // pretend the ime has some size just below the screen. mImeFrame.set(newFrame); final int floatingInset = (int) ( @@ -329,7 +349,8 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged SurfaceControl.Transaction t = mTransactionPool.acquire(); float value = (float) animation.getAnimatedValue(); t.setPosition(mImeSourceControl.getLeash(), x, value); - final float alpha = isFloating ? (value - hiddenY) / (shownY - hiddenY) : 1.f; + final float alpha = (mAnimateAlpha || isFloating) + ? (value - hiddenY) / (shownY - hiddenY) : 1.f; t.setAlpha(mImeSourceControl.getLeash(), alpha); dispatchPositionChanged(mDisplayId, imeTop(value), t); t.apply(); @@ -342,16 +363,18 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged public void onAnimationStart(Animator animation) { SurfaceControl.Transaction t = mTransactionPool.acquire(); t.setPosition(mImeSourceControl.getLeash(), x, startY); - final float alpha = isFloating ? (startY - hiddenY) / (shownY - hiddenY) : 1.f; - t.setAlpha(mImeSourceControl.getLeash(), alpha); if (DEBUG) { Slog.d(TAG, "onAnimationStart d:" + mDisplayId + " top:" + imeTop(hiddenY) + "->" + imeTop(shownY) + " showing:" + (mAnimationDirection == DIRECTION_SHOW)); } - dispatchStartPositioning(mDisplayId, imeTop(hiddenY), - imeTop(shownY), mAnimationDirection == DIRECTION_SHOW, - t); + int flags = dispatchStartPositioning(mDisplayId, imeTop(hiddenY), + imeTop(shownY), mAnimationDirection == DIRECTION_SHOW, isFloating, t); + mAnimateAlpha = (flags & ImePositionProcessor.IME_ANIMATION_NO_ALPHA) == 0; + final float alpha = (mAnimateAlpha || isFloating) + ? (startY - hiddenY) / (shownY - hiddenY) + : 1.f; + t.setAlpha(mImeSourceControl.getLeash(), alpha); if (mAnimationDirection == DIRECTION_SHOW) { t.show(mImeSourceControl.getLeash()); } @@ -413,6 +436,19 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged * Allows other things to synchronize with the ime position */ public interface ImePositionProcessor { + /** + * Indicates that ime shouldn't animate alpha. It will always be opaque. Used when stuff + * behind the IME shouldn't be visible (for example during split-screen adjustment where + * there is nothing behind the ime). + */ + int IME_ANIMATION_NO_ALPHA = 1; + + /** @hide */ + @IntDef(prefix = { "IME_ANIMATION_" }, value = { + IME_ANIMATION_NO_ALPHA, + }) + @interface ImeAnimationFlags {} + /** * Called when the IME position is starting to animate. * @@ -420,9 +456,14 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged * @param shownTop The y position of the top of the IME surface when it is shown. * @param showing {@code true} when we are animating from hidden to shown, {@code false} * when animating from shown to hidden. + * @param isFloating {@code true} when the ime is a floating ime (doesn't inset). + * @return flags that may alter how ime itself is animated (eg. no-alpha). */ - default void onImeStartPositioning(int displayId, int hiddenTop, int shownTop, - boolean showing, SurfaceControl.Transaction t) {} + @ImeAnimationFlags + default int onImeStartPositioning(int displayId, int hiddenTop, int shownTop, + boolean showing, boolean isFloating, SurfaceControl.Transaction t) { + return 0; + } /** * Called when the ime position changed. This is expected to be a synchronous call on the diff --git a/packages/SystemUI/src/com/android/systemui/wm/DisplayLayout.java b/packages/SystemUI/src/com/android/systemui/wm/DisplayLayout.java index cfec1c07ff1d..a341f3050ea6 100644 --- a/packages/SystemUI/src/com/android/systemui/wm/DisplayLayout.java +++ b/packages/SystemUI/src/com/android/systemui/wm/DisplayLayout.java @@ -79,6 +79,7 @@ public class DisplayLayout { private final Rect mStableInsets = new Rect(); private boolean mHasNavigationBar = false; private boolean mHasStatusBar = false; + private int mNavBarFrameHeight = 0; /** * Create empty layout. @@ -146,6 +147,7 @@ public class DisplayLayout { if (mHasStatusBar) { convertNonDecorInsetsToStableInsets(res, mStableInsets, mWidth, mHeight, mHasStatusBar); } + mNavBarFrameHeight = getNavigationBarFrameHeight(res, mWidth > mHeight); } /** @@ -214,6 +216,11 @@ public class DisplayLayout { return mWidth > mHeight; } + /** Get the navbar frame height (used by ime). */ + public int navBarFrameHeight() { + return mNavBarFrameHeight; + } + /** Gets the orientation of this layout */ public int getOrientation() { return (mWidth > mHeight) ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT; @@ -483,6 +490,7 @@ public class DisplayLayout { } else { return res.getDimensionPixelSize(R.dimen.navigation_bar_width_car_mode); } + } else { if (navBarSide == NAV_BAR_BOTTOM) { return res.getDimensionPixelSize(landscape @@ -493,4 +501,11 @@ public class DisplayLayout { } } } + + /** @see com.android.server.wm.DisplayPolicy#getNavigationBarFrameHeight */ + public static int getNavigationBarFrameHeight(Resources res, boolean landscape) { + return res.getDimensionPixelSize(landscape + ? R.dimen.navigation_bar_frame_height_landscape + : R.dimen.navigation_bar_frame_height); + } } -- cgit v1.2.3-59-g8ed1b