diff options
Diffstat (limited to 'libs')
5 files changed, 98 insertions, 50 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java index c19da2ef0a02..eb3a3a276727 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java @@ -171,7 +171,7 @@ public class BubbleController implements Bubbles { ShellTaskOrganizer organizer) { BubbleLogger logger = new BubbleLogger(uiEventLogger); BubblePositioner positioner = new BubblePositioner(context, windowManager); - BubbleData data = new BubbleData(context, logger); + BubbleData data = new BubbleData(context, logger, positioner); return new BubbleController(context, data, synchronizer, floatingContentCoordinator, new BubbleDataRepository(context, launcherApps), statusBarService, windowManager, windowManagerShellWrapper, launcherApps, @@ -382,7 +382,6 @@ public class BubbleController implements Bubbles { if (mStackView == null) { mStackView = new BubbleStackView( mContext, this, mBubbleData, mSurfaceSynchronizer, mFloatingContentCoordinator); - mStackView.addView(mBubbleScrim); mStackView.onOrientationChanged(); if (mExpandListener != null) { mStackView.setExpandListener(mExpandListener); @@ -422,6 +421,8 @@ public class BubbleController implements Bubbles { try { mAddedToWindowManager = true; + mBubbleData.getOverflow().initialize(this); + mStackView.addView(mBubbleScrim); mWindowManager.addView(mStackView, mWmLayoutParams); // Position info is dependent on us being attached to a window mBubblePositioner.update(mOrientation); @@ -446,7 +447,7 @@ public class BubbleController implements Bubbles { if (mStackView != null) { mWindowManager.removeView(mStackView); mStackView.removeView(mBubbleScrim); - mStackView = null; + mBubbleData.getOverflow().cleanUpExpandedState(); } else { Log.w(TAG, "StackView added to WindowManager, but was null when removing!"); } @@ -578,7 +579,7 @@ public class BubbleController implements Bubbles { if (mStackView == null) { return false; } - return mBubbleData.hasBubbles(); + return mBubbleData.hasBubbles() || mBubbleData.isShowingOverflow(); } @Override diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java index b6a97e251009..e24ff063b661 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java @@ -69,7 +69,7 @@ public class BubbleData { boolean selectionChanged; boolean orderChanged; boolean expanded; - @Nullable Bubble selectedBubble; + @Nullable BubbleViewProvider selectedBubble; @Nullable Bubble addedBubble; @Nullable Bubble updatedBubble; @Nullable Bubble addedOverflowBubble; @@ -116,13 +116,15 @@ public class BubbleData { } private final Context mContext; + private final BubblePositioner mPositioner; /** Bubbles that are actively in the stack. */ private final List<Bubble> mBubbles; /** Bubbles that aged out to overflow. */ private final List<Bubble> mOverflowBubbles; /** Bubbles that are being loaded but haven't been added to the stack just yet. */ private final HashMap<String, Bubble> mPendingBubbles; - private Bubble mSelectedBubble; + private BubbleViewProvider mSelectedBubble; + private final BubbleOverflow mOverflow; private boolean mShowingOverflow; private boolean mExpanded; private final int mMaxBubbles; @@ -153,9 +155,11 @@ public class BubbleData { */ private HashMap<String, String> mSuppressedGroupKeys = new HashMap<>(); - public BubbleData(Context context, BubbleLogger bubbleLogger) { + public BubbleData(Context context, BubbleLogger bubbleLogger, BubblePositioner positioner) { mContext = context; mLogger = bubbleLogger; + mPositioner = positioner; + mOverflow = new BubbleOverflow(context, positioner); mBubbles = new ArrayList<>(); mOverflowBubbles = new ArrayList<>(); mPendingBubbles = new HashMap<>(); @@ -178,6 +182,10 @@ public class BubbleData { return !mBubbles.isEmpty(); } + public boolean hasOverflowBubbles() { + return !mOverflowBubbles.isEmpty(); + } + public boolean isExpanded() { return mExpanded; } @@ -195,10 +203,14 @@ public class BubbleData { } @Nullable - public Bubble getSelectedBubble() { + public BubbleViewProvider getSelectedBubble() { return mSelectedBubble; } + public BubbleOverflow getOverflow() { + return mOverflow; + } + /** Return a read-only current active bubble lists. */ public List<Bubble> getActiveBubbles() { return Collections.unmodifiableList(mBubbles); @@ -212,7 +224,7 @@ public class BubbleData { dispatchPendingChanges(); } - public void setSelectedBubble(Bubble bubble) { + public void setSelectedBubble(BubbleViewProvider bubble) { if (DEBUG_BUBBLE_DATA) { Log.d(TAG, "setSelectedBubble: " + bubble); } @@ -224,6 +236,10 @@ public class BubbleData { mShowingOverflow = showingOverflow; } + boolean isShowingOverflow() { + return mShowingOverflow && (isExpanded() || mPositioner.showingInTaskbar()); + } + /** * Constructs a new bubble or returns an existing one. Does not add new bubbles to * bubble data, must go through {@link #notificationEntryUpdated(Bubble, boolean, boolean)} @@ -264,8 +280,8 @@ public class BubbleData { /** * When this method is called it is expected that all info in the bubble has completed loading. - * @see Bubble#inflate(BubbleViewInfoTask.Callback, Context, - * BubbleStackView, BubbleIconFactory, boolean). + * @see Bubble#inflate(BubbleViewInfoTask.Callback, Context, BubbleController, BubbleStackView, + * BubbleIconFactory, boolean) */ void notificationEntryUpdated(Bubble bubble, boolean suppressFlyout, boolean showInShade) { if (DEBUG_BUBBLE_DATA) { @@ -484,10 +500,17 @@ public class BubbleData { Bubble bubbleToRemove = mBubbles.get(indexToRemove); bubbleToRemove.stopInflation(); if (mBubbles.size() == 1) { - // Going to become empty, handle specially. - setExpandedInternal(false); - // Don't use setSelectedBubbleInternal because we don't want to trigger an applyUpdate - mSelectedBubble = null; + if (hasOverflowBubbles() && (mPositioner.showingInTaskbar() || isExpanded())) { + // No more active bubbles but we have stuff in the overflow -- select that view + // if we're already expanded or always showing. + setShowingOverflow(true); + setSelectedBubbleInternal(mOverflow); + } else { + setExpandedInternal(false); + // Don't use setSelectedBubbleInternal because we don't want to trigger an + // applyUpdate + mSelectedBubble = null; + } } if (indexToRemove < mBubbles.size() - 1) { // Removing anything but the last bubble means positions will change. @@ -505,7 +528,7 @@ public class BubbleData { if (Objects.equals(mSelectedBubble, bubbleToRemove)) { // Move selection to the new bubble at the same position. int newIndex = Math.min(indexToRemove, mBubbles.size() - 1); - Bubble newSelected = mBubbles.get(newIndex); + BubbleViewProvider newSelected = mBubbles.get(newIndex); setSelectedBubbleInternal(newSelected); } maybeSendDeleteIntent(reason, bubbleToRemove); @@ -564,7 +587,7 @@ public class BubbleData { * * @param bubble the new selected bubble */ - private void setSelectedBubbleInternal(@Nullable Bubble bubble) { + private void setSelectedBubbleInternal(@Nullable BubbleViewProvider bubble) { if (DEBUG_BUBBLE_DATA) { Log.d(TAG, "setSelectedBubbleInternal: " + bubble); } @@ -572,14 +595,17 @@ public class BubbleData { return; } // Otherwise, if we are showing the overflow menu, return to the previously selected bubble. - - if (bubble != null && !mBubbles.contains(bubble) && !mOverflowBubbles.contains(bubble)) { + boolean isOverflow = bubble != null && BubbleOverflow.KEY.equals(bubble.getKey()); + if (bubble != null + && !mBubbles.contains(bubble) + && !mOverflowBubbles.contains(bubble) + && !isOverflow) { Log.e(TAG, "Cannot select bubble which doesn't exist!" + " (" + bubble + ") bubbles=" + mBubbles); return; } - if (mExpanded && bubble != null) { - bubble.markAsAccessedAt(mTimeSource.currentTimeMillis()); + if (mExpanded && bubble != null && !isOverflow) { + ((Bubble) bubble).markAsAccessedAt(mTimeSource.currentTimeMillis()); } mSelectedBubble = bubble; mStateChange.selectedBubble = bubble; @@ -629,7 +655,7 @@ public class BubbleData { return; } if (shouldExpand) { - if (mBubbles.isEmpty()) { + if (mBubbles.isEmpty() && !mShowingOverflow) { Log.e(TAG, "Attempt to expand stack when empty!"); return; } @@ -637,7 +663,9 @@ public class BubbleData { Log.e(TAG, "Attempt to expand stack without selected bubble!"); return; } - mSelectedBubble.markAsAccessedAt(mTimeSource.currentTimeMillis()); + if (mSelectedBubble instanceof Bubble) { + ((Bubble) mSelectedBubble).markAsAccessedAt(mTimeSource.currentTimeMillis()); + } mStateChange.orderChanged |= repackAll(); } else if (!mBubbles.isEmpty()) { // Apply ordering and grouping rules from expanded -> collapsed, then save @@ -647,14 +675,18 @@ public class BubbleData { if (mShowingOverflow) { // Show previously selected bubble instead of overflow menu on next expansion. - setSelectedBubbleInternal(mSelectedBubble); + if (!mSelectedBubble.getKey().equals(mOverflow.getKey())) { + setSelectedBubbleInternal(mSelectedBubble); + } else { + setSelectedBubbleInternal(mBubbles.get(0)); + } } if (mBubbles.indexOf(mSelectedBubble) > 0) { // Move the selected bubble to the top while collapsed. int index = mBubbles.indexOf(mSelectedBubble); if (index != 0) { - mBubbles.remove(mSelectedBubble); - mBubbles.add(0, mSelectedBubble); + mBubbles.remove((Bubble) mSelectedBubble); + mBubbles.add(0, (Bubble) mSelectedBubble); mStateChange.orderChanged = true; } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt index 95085d0f1a85..8ab2f6325d2b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt @@ -63,11 +63,17 @@ class BubbleOverflow( overflowBtn = null } + /** Call before use and again if cleanUpExpandedState was called. */ fun initialize(controller: BubbleController) { getExpandedView()?.initialize(controller, controller.stackView) getExpandedView()?.setOverflow(true) } + fun cleanUpExpandedState() { + expandedView?.cleanUpExpandedState() + expandedView = null + } + fun update() { updateResources() getExpandedView()?.applyThemeAttrs() @@ -132,11 +138,6 @@ class BubbleOverflow( overflowBtn?.updateDotVisibility(true /* animate */) } - fun cleanUpExpandedState() { - expandedView?.cleanUpExpandedState() - expandedView = null - } - override fun getExpandedView(): BubbleExpandedView? { if (expandedView == null) { expandedView = inflater.inflate(R.layout.bubble_expanded_view, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java index 38fcd2f06003..cbe98458df86 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java @@ -227,7 +227,7 @@ public class BubbleStackView extends FrameLayout * once it collapses. */ @Nullable - private Bubble mBubbleToExpandAfterFlyoutCollapse = null; + private BubbleViewProvider mBubbleToExpandAfterFlyoutCollapse = null; /** Layout change listener that moves the stack to the nearest valid position on rotation. */ private OnLayoutChangeListener mOrientationChangedListener; @@ -571,6 +571,16 @@ public class BubbleStackView extends FrameLayout mBubbleContainer.setActiveController(mStackAnimationController); hideFlyoutImmediate(); + if (!mPositioner.showingInTaskbar()) { + // Also, save the magnetized stack so we can dispatch touch events to it. + mMagnetizedObject = mStackAnimationController.getMagnetizedStack( + mMagneticTarget); + mMagnetizedObject.setMagnetListener(mStackMagnetListener); + } else { + // In taskbar, the stack isn't draggable so we shouldn't dispatch touch events. + mMagnetizedObject = null; + } + // Also, save the magnetized stack so we can dispatch touch events to it. mMagnetizedObject = mStackAnimationController.getMagnetizedStack(mMagneticTarget); mMagnetizedObject.setMagnetListener(mStackMagnetListener); @@ -592,7 +602,9 @@ public class BubbleStackView extends FrameLayout public void onMove(@NonNull View v, @NonNull MotionEvent ev, float viewInitialX, float viewInitialY, float dx, float dy) { // If we're expanding or collapsing, ignore all touch events. - if (mIsExpansionAnimating) { + if (mIsExpansionAnimating + // Also ignore events if we shouldn't be draggable. + || (mPositioner.showingInTaskbar() && !mIsExpanded)) { return; } @@ -602,7 +614,7 @@ public class BubbleStackView extends FrameLayout // First, see if the magnetized object consumes the event - if so, we shouldn't move the // bubble since it's stuck to the target. if (!passEventToMagnetizedObject(ev)) { - if (mBubbleData.isExpanded()) { + if (mBubbleData.isExpanded() || mPositioner.showingInTaskbar()) { mExpandedAnimationController.dragBubbleOut( v, viewInitialX + dx, viewInitialY + dy); } else { @@ -743,7 +755,7 @@ public class BubbleStackView extends FrameLayout ta.recycle(); final Runnable onBubbleAnimatedOut = () -> { - if (getBubbleCount() == 0) { + if (getBubbleCount() == 0 && !mBubbleData.isShowingOverflow()) { mBubbleController.onAllBubblesAnimatedOut(); } }; @@ -816,16 +828,16 @@ public class BubbleStackView extends FrameLayout setFocusable(true); mBubbleContainer.bringToFront(); - mBubbleOverflow = new BubbleOverflow(getContext(), mPositioner); - mBubbleOverflow.initialize(mBubbleController); + mBubbleOverflow = mBubbleData.getOverflow(); mBubbleContainer.addView(mBubbleOverflow.getIconView(), mBubbleContainer.getChildCount() /* index */, new FrameLayout.LayoutParams(mPositioner.getBubbleSize(), mPositioner.getBubbleSize())); updateOverflow(); mBubbleOverflow.getIconView().setOnClickListener((View v) -> { - setSelectedBubble(mBubbleOverflow); - showManageMenu(false); + mBubbleData.setShowingOverflow(true); + mBubbleData.setSelectedBubble(mBubbleOverflow); + mBubbleData.setExpanded(true); }); setOnApplyWindowInsetsListener((View view, WindowInsets insets) -> { @@ -996,11 +1008,12 @@ public class BubbleStackView extends FrameLayout mManageMenu.findViewById(R.id.bubble_manage_menu_settings_container).setOnClickListener( view -> { showManageMenu(false /* show */); - final Bubble bubble = mBubbleData.getSelectedBubble(); + final BubbleViewProvider bubble = mBubbleData.getSelectedBubble(); if (bubble != null && mBubbleData.hasBubbleInStackWithKey(bubble.getKey())) { - final Intent intent = bubble.getSettingsIntent(mContext); + // If it's in the stack it's a proper Bubble. + final Intent intent = ((Bubble) bubble).getSettingsIntent(mContext); mBubbleData.setExpanded(false); - mContext.startActivityAsUser(intent, bubble.getUser()); + mContext.startActivityAsUser(intent, ((Bubble) bubble).getUser()); logBubbleEvent(bubble, FrameworkStatsLog.BUBBLE_UICHANGED__ACTION__HEADER_GO_TO_SETTINGS); } @@ -1443,10 +1456,9 @@ public class BubbleStackView extends FrameLayout } private void updateOverflowVisibility() { - if (mBubbleOverflow == null) { - return; - } - mBubbleOverflow.setVisible(mIsExpanded ? VISIBLE : GONE); + mBubbleOverflow.setVisible((mIsExpanded || mBubbleData.isShowingOverflow()) + ? VISIBLE + : GONE); } // via BubbleData.Listener @@ -2128,7 +2140,7 @@ public class BubbleStackView extends FrameLayout } } - private void dismissBubbleIfExists(@Nullable Bubble bubble) { + private void dismissBubbleIfExists(@Nullable BubbleViewProvider bubble) { if (bubble != null && mBubbleData.hasBubbleInStackWithKey(bubble.getKey())) { mBubbleData.dismissBubbleWithKey(bubble.getKey(), Bubbles.DISMISS_USER_GESTURE); } @@ -2337,7 +2349,7 @@ public class BubbleStackView extends FrameLayout } if (!mIsExpanded) { - if (getBubbleCount() > 0) { + if (getBubbleCount() > 0 || mBubbleData.isShowingOverflow()) { mBubbleContainer.getChildAt(0).getBoundsOnScreen(outRect); // Increase the touch target size of the bubble outRect.top -= mBubbleTouchPadding; diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java index 7adc4112fa90..7c9b9c37c2c4 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java @@ -35,6 +35,7 @@ import android.service.notification.StatusBarNotification; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.util.Pair; +import android.view.WindowManager; import androidx.test.filters.SmallTest; @@ -135,8 +136,9 @@ public class BubbleDataTest extends ShellTestCase { mBubbleB2 = new Bubble(mEntryB2, mSuppressionListener, mPendingIntentCanceledListener); mBubbleB3 = new Bubble(mEntryB3, mSuppressionListener, mPendingIntentCanceledListener); mBubbleC1 = new Bubble(mEntryC1, mSuppressionListener, mPendingIntentCanceledListener); - - mBubbleData = new BubbleData(getContext(), mBubbleLogger); + TestableBubblePositioner positioner = new TestableBubblePositioner(mContext, + mock(WindowManager.class)); + mBubbleData = new BubbleData(getContext(), mBubbleLogger, positioner); // Used by BubbleData to set lastAccessedTime when(mTimeSource.currentTimeMillis()).thenReturn(1000L); |