diff options
3 files changed, 77 insertions, 15 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java index eb85589f3781..e0ed111d9cb0 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java @@ -118,6 +118,7 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe private final BubbleTaskStackListener mTaskStackListener; private BubbleStateChangeListener mStateChangeListener; private BubbleExpandListener mExpandListener; + @Nullable private BubbleStackView.SurfaceSynchronizer mSurfaceSynchronizer; private BubbleData mBubbleData; private BubbleStackView mStackView; @@ -178,7 +179,12 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe @Inject public BubbleController(Context context, StatusBarWindowController statusBarWindowController, - BubbleData data) { + BubbleData data) { + this(context, statusBarWindowController, data, null /* synchronizer */); + } + + public BubbleController(Context context, StatusBarWindowController statusBarWindowController, + BubbleData data, @Nullable BubbleStackView.SurfaceSynchronizer synchronizer) { mContext = context; mNotificationEntryManager = Dependency.get(NotificationEntryManager.class); @@ -206,6 +212,7 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe } mBubbleData = data; + mSurfaceSynchronizer = synchronizer; } /** @@ -297,7 +304,7 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe mStackView.updateBubble(notif, updatePosition); } else { if (mStackView == null) { - mStackView = new BubbleStackView(mContext, mBubbleData); + mStackView = new BubbleStackView(mContext, mBubbleData, mSurfaceSynchronizer); ViewGroup sbv = mStatusBarWindowController.getStatusBarView(); // XXX: Bug when you expand the shade on top of expanded bubble, there is no scrim // between bubble and the shade diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java index f3a701e0152f..1cc6b8789872 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java @@ -19,6 +19,7 @@ package com.android.systemui.bubbles; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; +import android.annotation.NonNull; import android.app.Notification; import android.app.PendingIntent; import android.content.Context; @@ -32,6 +33,7 @@ import android.os.Bundle; import android.service.notification.StatusBarNotification; import android.util.Log; import android.util.StatsLog; +import android.view.Choreographer; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; @@ -67,6 +69,43 @@ public class BubbleStackView extends FrameLayout { private static final String TAG = "BubbleStackView"; private static final boolean DEBUG = false; + /** + * Interface to synchronize {@link View} state and the screen. + * + * {@hide} + */ + interface SurfaceSynchronizer { + /** + * Wait until requested change on a {@link View} is reflected on the screen. + * + * @param callback callback to run after the change is reflected on the screen. + */ + void syncSurfaceAndRun(Runnable callback); + } + + private static final SurfaceSynchronizer DEFAULT_SURFACE_SYNCHRONIZER = + new SurfaceSynchronizer() { + @Override + public void syncSurfaceAndRun(Runnable callback) { + Choreographer.getInstance().postFrameCallback(new Choreographer.FrameCallback() { + // Just wait 2 frames. There is no guarantee, but this is usually enough time that + // the requested change is reflected on the screen. + // TODO: Once SurfaceFlinger provide APIs to sync the state of {@code View} and + // surfaces, rewrite this logic with them. + private int mFrameWait = 2; + + @Override + public void doFrame(long frameTimeNanos) { + if (--mFrameWait > 0) { + Choreographer.getInstance().postFrameCallback(this); + } else { + callback.run(); + } + } + }); + } + }; + private Point mDisplaySize; private final SpringAnimation mExpandedViewXAnim; @@ -79,7 +118,6 @@ public class BubbleStackView extends FrameLayout { private FrameLayout mExpandedViewContainer; - private int mBubbleSize; private int mBubblePadding; private int mExpandedAnimateXDistance; @@ -129,7 +167,11 @@ public class BubbleStackView extends FrameLayout { } }; - public BubbleStackView(Context context, BubbleData data) { + @NonNull private final SurfaceSynchronizer mSurfaceSynchronizer; + + + public BubbleStackView(Context context, BubbleData data, + @Nullable SurfaceSynchronizer synchronizer) { super(context); mBubbleData = data; @@ -160,6 +202,7 @@ public class BubbleStackView extends FrameLayout { mStackAnimationController = new StackAnimationController(); mExpandedAnimationController = new ExpandedAnimationController(mDisplaySize); + mSurfaceSynchronizer = synchronizer != null ? synchronizer : DEFAULT_SURFACE_SYNCHRONIZER; mBubbleContainer = new PhysicsAnimationLayout(context); mBubbleContainer.setMaxRenderedChildren( @@ -314,17 +357,28 @@ public class BubbleStackView extends FrameLayout { // If we weren't previously expanded we should animate open. animateExpansion(true /* expand */); logBubbleEvent(mExpandedBubble, StatsLog.BUBBLE_UICHANGED__ACTION__EXPANDED); + mExpandedBubble.entry.setShowInShadeWhenBubble(false); + notifyExpansionChanged(mExpandedBubble.entry, true /* expanded */); } else { - // Otherwise just update the views - // TODO: probably animate / page to expanded one - updateExpandedBubble(); - updatePointerPosition(); - requestUpdate(); - logBubbleEvent(prevBubble, StatsLog.BUBBLE_UICHANGED__ACTION__COLLAPSED); - logBubbleEvent(mExpandedBubble, StatsLog.BUBBLE_UICHANGED__ACTION__EXPANDED); + // Make the container of the expanded view transparent before removing the expanded view + // from it. Otherwise a punch hole created by {@link android.view.SurfaceView} in the + // expanded view becomes visible on the screen. See b/126856255 + mExpandedViewContainer.setAlpha(0.0f); + + mSurfaceSynchronizer.syncSurfaceAndRun(new Runnable() { + @Override + public void run() { + updateExpandedBubble(); + updatePointerPosition(); + requestUpdate(); + logBubbleEvent(prevBubble, StatsLog.BUBBLE_UICHANGED__ACTION__COLLAPSED); + logBubbleEvent(mExpandedBubble, + StatsLog.BUBBLE_UICHANGED__ACTION__EXPANDED); + mExpandedBubble.entry.setShowInShadeWhenBubble(false); + notifyExpansionChanged(mExpandedBubble.entry, true /* expanded */); + } + }); } - mExpandedBubble.entry.setShowInShadeWhenBubble(false); - notifyExpansionChanged(mExpandedBubble.entry, true /* expanded */); } /** @@ -769,6 +823,7 @@ public class BubbleStackView extends FrameLayout { mExpandedViewContainer.addView(mExpandedBubble.expandedView); mExpandedBubble.expandedView.populateExpandedView(); mExpandedViewContainer.setVisibility(mIsExpanded ? VISIBLE : GONE); + mExpandedViewContainer.setAlpha(1.0f); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java index 42c221a91422..4e9d892dd809 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java @@ -329,10 +329,10 @@ public class BubbleControllerTest extends SysuiTestCase { } static class TestableBubbleController extends BubbleController { - + // Let's assume surfaces can be synchronized immediately. TestableBubbleController(Context context, StatusBarWindowController statusBarWindowController, BubbleData data) { - super(context, statusBarWindowController, data); + super(context, statusBarWindowController, data, Runnable::run); } @Override |