Merge "Translate bubbles with IME"
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index e8b346e..49beae6 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -94,6 +94,9 @@
private boolean mActivityViewReady = false;
private PendingIntent mBubbleIntent;
+ private boolean mKeyboardVisible;
+ private boolean mNeedsNewHeight;
+
private int mMinHeight;
private int mHeaderHeight;
private int mBubbleHeight;
@@ -227,21 +230,15 @@
true /* singleTaskInstance */);
addView(mActivityView);
- mActivityView.setOnApplyWindowInsetsListener((View view, WindowInsets insets) -> {
- ActivityView activityView = (ActivityView) view;
- // Here we assume that the position of the ActivityView on the screen
- // remains regardless of IME status. When we move ActivityView, the
- // forwardedInsets should be computed not against the current location
- // and size, but against the post-moved location and size.
- Point displaySize = new Point();
- view.getContext().getDisplay().getSize(displaySize);
- int[] windowLocation = view.getLocationOnScreen();
- final int windowBottom = windowLocation[1] + view.getHeight();
+ setOnApplyWindowInsetsListener((View view, WindowInsets insets) -> {
+ // Keep track of IME displaying because we should not make any adjustments that might
+ // cause a config change while the IME is displayed otherwise it'll loose focus.
final int keyboardHeight = insets.getSystemWindowInsetBottom()
- insets.getStableInsetBottom();
- final int insetsBottom = Math.max(0,
- windowBottom + keyboardHeight - displaySize.y);
- activityView.setForwardedInsets(Insets.of(0, 0, 0, insetsBottom));
+ mKeyboardVisible = keyboardHeight != 0;
+ if (!mKeyboardVisible && mNeedsNewHeight) {
+ updateHeight();
+ }
return view.onApplyWindowInsets(insets);
});
@@ -258,6 +255,34 @@
}
}
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ mKeyboardVisible = false;
+ mNeedsNewHeight = false;
+ if (mActivityView != null) {
+ mActivityView.setForwardedInsets(Insets.of(0, 0, 0, 0));
+ }
+ }
+
+ /**
+ * Called by {@link BubbleStackView} when the insets for the expanded state should be updated.
+ * This should be done post-move and post-animation.
+ */
+ void updateInsets(WindowInsets insets) {
+ if (usingActivityView()) {
+ Point displaySize = new Point();
+ mActivityView.getContext().getDisplay().getSize(displaySize);
+ int[] windowLocation = mActivityView.getLocationOnScreen();
+ final int windowBottom = windowLocation[1] + mActivityView.getHeight();
+ final int keyboardHeight = insets.getSystemWindowInsetBottom()
+ - insets.getStableInsetBottom();
+ final int insetsBottom = Math.max(0,
+ windowBottom + keyboardHeight - displaySize.y);
+ mActivityView.setForwardedInsets(Insets.of(0, 0, 0, insetsBottom));
+ }
+ }
+
/**
* Creates a background with corners rounded based on how the view is configured to display
*/
@@ -448,9 +473,15 @@
int height = Math.min(desiredHeight, max);
height = Math.max(height, mMinHeight);
LayoutParams lp = (LayoutParams) mActivityView.getLayoutParams();
- lp.height = height;
- mBubbleHeight = height;
- mActivityView.setLayoutParams(lp);
+ mNeedsNewHeight = lp.height != height;
+ if (!mKeyboardVisible) {
+ // If the keyboard is visible... don't adjust the height because that will cause
+ // a configuration change and the keyboard will be lost.
+ lp.height = height;
+ mBubbleHeight = height;
+ mActivityView.setLayoutParams(lp);
+ mNeedsNewHeight = false;
+ }
} else {
mBubbleHeight = mNotifRow != null ? mNotifRow.getIntrinsicHeight() : mMinHeight;
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index 461e79c..580acb8 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -128,6 +128,7 @@
private Bubble mExpandedBubble;
private boolean mIsExpanded;
+ private boolean mImeVisible;
private BubbleTouchHandler mTouchHandler;
private BubbleController.BubbleExpandListener mExpandListener;
@@ -236,6 +237,28 @@
setClipChildren(false);
setFocusable(true);
mBubbleContainer.bringToFront();
+
+ setOnApplyWindowInsetsListener((View view, WindowInsets insets) -> {
+ final int keyboardHeight = insets.getSystemWindowInsetBottom()
+ - insets.getStableInsetBottom();
+ if (!mIsExpanded) {
+ return view.onApplyWindowInsets(insets);
+ }
+ mImeVisible = keyboardHeight != 0;
+
+ float newY = getYPositionForExpandedView();
+ if (newY < 0) {
+ // TODO: This means our expanded content is too big to fit on screen. Right now
+ // we'll let it translate off but we should be clipping it & pushing the header
+ // down so that it always remains visible.
+ }
+ mExpandedViewYAnim.animateToFinalPosition(newY);
+ mExpandedAnimationController.updateYPosition(
+ // Update the insets after we're done translating otherwise position
+ // calculation for them won't be correct.
+ () -> mExpandedBubble.expandedView.updateInsets(insets));
+ return view.onApplyWindowInsets(insets);
+ });
}
/**
@@ -646,15 +669,6 @@
}
}
- /**
- * The width of the collapsed stack of bubbles.
- */
- public int getStackWidth() {
- return mBubblePadding * (mBubbleContainer.getChildCount() - 1)
- + mBubbleSize + mBubbleContainer.getPaddingEnd()
- + mBubbleContainer.getPaddingStart();
- }
-
private void notifyExpansionChanged(NotificationEntry entry, boolean expanded) {
if (mExpandListener != null) {
mExpandListener.onBubbleExpandChanged(expanded, entry != null ? entry.key : null);
@@ -843,8 +857,13 @@
// calculation is correct)
mExpandedBubble.expandedView.updateView();
final float y = getYPositionForExpandedView();
- mExpandedViewContainer.setTranslationY(y);
- // Then update the view so that ActivityView knows we translated
+ if (!mExpandedViewYAnim.isRunning()) {
+ // We're not animating so set the value
+ mExpandedViewContainer.setTranslationY(y);
+ } else {
+ // We are animating so update the value
+ mExpandedViewYAnim.animateToFinalPosition(y);
+ }
mExpandedBubble.expandedView.updateView();
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
index 1f29883..40e08be 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
@@ -198,6 +198,19 @@
}
/**
+ * Animates the bubbles to {@link #getExpandedY()} position. Used in response to IME showing.
+ */
+ public void updateYPosition(Runnable after) {
+ if (mLayout == null) return;
+
+ for (int i = 0; i < mLayout.getChildCount(); i++) {
+ boolean isLast = i == mLayout.getChildCount() - 1;
+ mLayout.animateValueForChildAtIndex(DynamicAnimation.TRANSLATION_Y, i,
+ getExpandedY(), isLast ? after : null);
+ }
+ }
+
+ /**
* Animates the bubbles, starting at the given index, to the left or right by the given number
* of bubble widths. Passing zero for numBubbleWidths will animate the bubbles to their normal
* positions.
@@ -213,18 +226,25 @@
/** The Y value of the row of expanded bubbles. */
public float getExpandedY() {
- boolean showOnTop = mLayout != null
- && BubbleController.showBubblesAtTop(mLayout.getContext());
- final WindowInsets insets = mLayout != null ? mLayout.getRootWindowInsets() : null;
- if (showOnTop && insets != null) {
+ if (mLayout == null || mLayout.getRootWindowInsets() == null) {
+ return 0;
+ }
+ final boolean showOnTop = BubbleController.showBubblesAtTop(mLayout.getContext());
+ final WindowInsets insets = mLayout.getRootWindowInsets();
+ if (showOnTop) {
return mBubblePaddingPx + Math.max(
mStatusBarHeight,
insets.getDisplayCutout() != null
? insets.getDisplayCutout().getSafeInsetTop()
: 0);
} else {
- int bottomInset = insets != null ? insets.getSystemWindowInsetBottom() : 0;
- return mDisplaySize.y - mBubbleSizePx - (mPipDismissHeight - bottomInset);
+ int keyboardHeight = insets.getSystemWindowInsetBottom()
+ - insets.getStableInsetBottom();
+ float bottomInset = keyboardHeight > 0
+ ? keyboardHeight
+ : (mPipDismissHeight - insets.getStableInsetBottom());
+ // Stable insets are excluded from display size, so we must subtract it
+ return mDisplaySize.y - mBubbleSizePx - mBubblePaddingPx - bottomInset;
}
}