diff --git a/libs/WindowManager/Shell/res/layout/bubble_menu_view.xml b/libs/WindowManager/Shell/res/layout/bubble_menu_view.xml index 0c1d1a54507a4..d19b65394cd89 100644 --- a/libs/WindowManager/Shell/res/layout/bubble_menu_view.xml +++ b/libs/WindowManager/Shell/res/layout/bubble_menu_view.xml @@ -16,14 +16,16 @@ --> + android:id="@+id/bubble_menu_container" + tools:ignore="MissingClass"> diff --git a/libs/WindowManager/Shell/res/layout/bubble_overflow_button.xml b/libs/WindowManager/Shell/res/layout/bubble_overflow_button.xml index 61000fe19d2cc..e392cdc26c60b 100644 --- a/libs/WindowManager/Shell/res/layout/bubble_overflow_button.xml +++ b/libs/WindowManager/Shell/res/layout/bubble_overflow_button.xml @@ -17,6 +17,6 @@ diff --git a/libs/WindowManager/Shell/res/layout/bubble_view.xml b/libs/WindowManager/Shell/res/layout/bubble_view.xml index a28bd678c9ab6..2b4b9e9042c98 100644 --- a/libs/WindowManager/Shell/res/layout/bubble_view.xml +++ b/libs/WindowManager/Shell/res/layout/bubble_view.xml @@ -17,5 +17,5 @@ + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml index 8a60aafcd13d1..25d034c51f461 100644 --- a/libs/WindowManager/Shell/res/values/dimen.xml +++ b/libs/WindowManager/Shell/res/values/dimen.xml @@ -99,12 +99,12 @@ 6dp 16dp + + 16dp 60dp 52dp - - 24dp 12dp @@ -136,6 +136,8 @@ 16dp 48dp + + 60dp 144dp diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java index 4d06c039551b0..32c6e368583d9 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java @@ -31,7 +31,6 @@ import android.util.PathParser; import android.widget.ImageView; import com.android.launcher3.icons.DotRenderer; -import com.android.wm.shell.R; import com.android.wm.shell.animation.Interpolators; import java.util.EnumSet; @@ -75,9 +74,8 @@ public class BadgedImageView extends ImageView { private boolean mDotIsAnimating = false; private BubbleViewProvider mBubble; + private BubblePositioner mPositioner; - private int mBubbleBitmapSize; - private int mBubbleSize; private DotRenderer mDotRenderer; private DotRenderer.DrawParams mDrawParams; private boolean mOnLeft; @@ -101,18 +99,21 @@ public class BadgedImageView extends ImageView { public BadgedImageView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); - mBubbleBitmapSize = getResources().getDimensionPixelSize(R.dimen.bubble_bitmap_size); - mBubbleSize = getResources().getDimensionPixelSize(R.dimen.individual_bubble_size); mDrawParams = new DotRenderer.DrawParams(); - Path iconPath = PathParser.createPathFromPathData( - getResources().getString(com.android.internal.R.string.config_icon_mask)); - mDotRenderer = new DotRenderer(mBubbleBitmapSize, iconPath, DEFAULT_PATH_SIZE); - setFocusable(true); setClickable(true); } + public void initialize(BubblePositioner positioner) { + mPositioner = positioner; + + Path iconPath = PathParser.createPathFromPathData( + getResources().getString(com.android.internal.R.string.config_icon_mask)); + mDotRenderer = new DotRenderer(mPositioner.getBubbleBitmapSize(), + iconPath, DEFAULT_PATH_SIZE); + } + public void showDotAndBadge(boolean onLeft) { removeDotSuppressionFlag(BadgedImageView.SuppressionFlag.BEHIND_STACK); animateDotBadgePositions(onLeft); @@ -186,7 +187,8 @@ public class BadgedImageView extends ImageView { * @param iconPath The new icon path to use when calculating dot position. */ void drawDot(Path iconPath) { - mDotRenderer = new DotRenderer(mBubbleBitmapSize, iconPath, DEFAULT_PATH_SIZE); + mDotRenderer = new DotRenderer(mPositioner.getBubbleBitmapSize(), + iconPath, DEFAULT_PATH_SIZE); invalidate(); } @@ -310,13 +312,13 @@ public class BadgedImageView extends ImageView { bubbleCanvas.setDrawFilter(new PaintFlagsDrawFilter(DITHER_FLAG, FILTER_BITMAP_FLAG)); bubbleCanvas.setBitmap(bubble); - - final int badgeSize = (int) (ICON_BADGE_SCALE * mBubbleSize); + final int bubbleSize = bubble.getWidth(); + final int badgeSize = (int) (ICON_BADGE_SCALE * bubbleSize); if (mOnLeft) { - badge.setBounds(0, mBubbleSize - badgeSize, badgeSize, mBubbleSize); + badge.setBounds(0, bubbleSize - badgeSize, badgeSize, bubbleSize); } else { - badge.setBounds(mBubbleSize - badgeSize, mBubbleSize - badgeSize, - mBubbleSize, mBubbleSize); + badge.setBounds(bubbleSize - badgeSize, bubbleSize - badgeSize, + bubbleSize, bubbleSize); } badge.draw(bubbleCanvas); bubbleCanvas.setBitmap(null); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java index 93ed3959776b3..122f91720bbd2 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java @@ -310,7 +310,7 @@ public class Bubble implements BubbleViewProvider { * * @param callback the callback to notify one the bubble is ready to be displayed. * @param context the context for the bubble. - * @param controller + * @param controller the bubble controller. * @param stackView the stackView the bubble is eventually added to. * @param iconFactory the iconfactory use to create badged images for the bubble. */ 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 05acb552a8d91..c19da2ef0a024 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 @@ -95,12 +95,6 @@ public class BubbleController implements Bubbles { private BubblePositioner mBubblePositioner; private SysuiProxy mSysuiProxy; - /** - * The relative position of the stack when we removed it and nulled it out. If the stack is - * re-created, it will re-appear at this position. - */ - @Nullable private BubbleStackView.RelativeStackPosition mPositionFromRemovedStack; - // Tracks the id of the current (foreground) user. private int mCurrentUserId; // Saves notification keys of active bubbles when users are switched. @@ -176,12 +170,12 @@ public class BubbleController implements Bubbles { Handler mainHandler, ShellTaskOrganizer organizer) { BubbleLogger logger = new BubbleLogger(uiEventLogger); - return new BubbleController(context, - new BubbleData(context, logger), synchronizer, - floatingContentCoordinator, new BubbleDataRepository(context, launcherApps), - statusBarService, windowManager, - windowManagerShellWrapper, launcherApps, logger, mainHandler, organizer, - new BubblePositioner(context, windowManager)); + BubblePositioner positioner = new BubblePositioner(context, windowManager); + BubbleData data = new BubbleData(context, logger); + return new BubbleController(context, data, synchronizer, floatingContentCoordinator, + new BubbleDataRepository(context, launcherApps), + statusBarService, windowManager, windowManagerShellWrapper, launcherApps, + logger, mainHandler, organizer, positioner); } /** @@ -207,6 +201,7 @@ public class BubbleController implements Bubbles { mLogger = bubbleLogger; mMainHandler = mainHandler; + mBubblePositioner = positioner; mBubbleData = data; mBubbleData.setListener(mBubbleDataListener); mBubbleData.setSuppressionChangedListener(bubble -> { @@ -249,7 +244,6 @@ public class BubbleController implements Bubbles { mBubbleIconFactory = new BubbleIconFactory(context); mTaskOrganizer = organizer; - mBubblePositioner = positioner; launcherApps.registerCallback(new LauncherApps.Callback() { @Override @@ -388,7 +382,6 @@ public class BubbleController implements Bubbles { if (mStackView == null) { mStackView = new BubbleStackView( mContext, this, mBubbleData, mSurfaceSynchronizer, mFloatingContentCoordinator); - mStackView.setStackStartPosition(mPositionFromRemovedStack); mStackView.addView(mBubbleScrim); mStackView.onOrientationChanged(); if (mExpandListener != null) { @@ -430,6 +423,8 @@ public class BubbleController implements Bubbles { try { mAddedToWindowManager = true; mWindowManager.addView(mStackView, mWmLayoutParams); + // Position info is dependent on us being attached to a window + mBubblePositioner.update(mOrientation); } catch (IllegalStateException e) { // This means the stack has already been added. This shouldn't happen... e.printStackTrace(); @@ -449,7 +444,6 @@ public class BubbleController implements Bubbles { try { mAddedToWindowManager = false; if (mStackView != null) { - mPositionFromRemovedStack = mStackView.getRelativeStackPosition(); mWindowManager.removeView(mStackView); mStackView.removeView(mBubbleScrim); mStackView = null; @@ -544,7 +538,7 @@ public class BubbleController implements Bubbles { } if (newConfig.fontScale != mFontScale) { mFontScale = newConfig.fontScale; - mStackView.updateFlyout(mFontScale); + mStackView.updateFontScale(mFontScale); } if (newConfig.getLayoutDirection() != mLayoutDirection) { mLayoutDirection = newConfig.getLayoutDirection(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDebugConfig.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDebugConfig.java index 53f4e87b04959..dc2ace949f0ce 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDebugConfig.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDebugConfig.java @@ -45,6 +45,7 @@ public class BubbleDebugConfig { static final boolean DEBUG_EXPERIMENTS = true; static final boolean DEBUG_OVERFLOW = false; static final boolean DEBUG_USER_EDUCATION = false; + static final boolean DEBUG_POSITIONER = false; private static final boolean FORCE_SHOW_USER_EDUCATION = false; private static final String FORCE_SHOW_USER_EDUCATION_SETTING = diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java index 74521c761d109..646e75a67867b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java @@ -639,7 +639,9 @@ public class BubbleExpandedView extends LinearLayout { } /** - * Cleans up anything related to the task and TaskView. + * Cleans up anything related to the task and TaskView. If this view should be reused after this + * method is called, then {@link #initialize(BubbleController, BubbleStackView)} must be invoked + * first. */ public void cleanUpExpandedState() { if (DEBUG_BUBBLE_EXPANDED_VIEW) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleFlyoutView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleFlyoutView.java index 460e0e798bdb1..19c3cf9c462a3 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleFlyoutView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleFlyoutView.java @@ -68,9 +68,8 @@ public class BubbleFlyoutView extends FrameLayout { private final int mFlyoutPadding; private final int mFlyoutSpaceFromBubble; private final int mPointerSize; - private final int mBubbleSize; - private final int mBubbleBitmapSize; - private final float mBubbleIconTopPadding; + private int mBubbleSize; + private int mBubbleBitmapSize; private final int mFlyoutElevation; private final int mBubbleElevation; @@ -83,9 +82,9 @@ public class BubbleFlyoutView extends FrameLayout { private final TextView mMessageText; /** Values related to the 'new' dot which we use to figure out where to collapse the flyout. */ - private final float mNewDotRadius; - private final float mNewDotSize; - private final float mOriginalDotSize; + private float mNewDotRadius; + private float mNewDotSize; + private float mOriginalDotSize; /** * The paint used to draw the background, whose color changes as the flyout transitions to the @@ -169,17 +168,9 @@ public class BubbleFlyoutView extends FrameLayout { mFlyoutSpaceFromBubble = res.getDimensionPixelSize(R.dimen.bubble_flyout_space_from_bubble); mPointerSize = res.getDimensionPixelSize(R.dimen.bubble_flyout_pointer_size); - mBubbleSize = res.getDimensionPixelSize(R.dimen.individual_bubble_size); - mBubbleBitmapSize = res.getDimensionPixelSize(R.dimen.bubble_bitmap_size); - mBubbleIconTopPadding = (mBubbleSize - mBubbleBitmapSize) / 2f; - mBubbleElevation = res.getDimensionPixelSize(R.dimen.bubble_elevation); mFlyoutElevation = res.getDimensionPixelSize(R.dimen.bubble_flyout_elevation); - mOriginalDotSize = SIZE_PERCENTAGE * mBubbleBitmapSize; - mNewDotRadius = (DOT_SCALE * mOriginalDotSize) / 2f; - mNewDotSize = mNewDotRadius * 2f; - final TypedArray ta = mContext.obtainStyledAttributes( new int[] { android.R.attr.colorBackgroundFloating, @@ -306,7 +297,15 @@ public class BubbleFlyoutView extends FrameLayout { @Nullable Runnable onLayoutComplete, @Nullable Runnable onHide, float[] dotCenter, - boolean hideDot) { + boolean hideDot, + BubblePositioner positioner) { + + mBubbleBitmapSize = positioner.getBubbleBitmapSize(); + mBubbleSize = positioner.getBubbleSize(); + + mOriginalDotSize = SIZE_PERCENTAGE * mBubbleBitmapSize; + mNewDotRadius = (DOT_SCALE * mOriginalDotSize) / 2f; + mNewDotSize = mNewDotRadius * 2f; updateFlyoutMessage(flyoutMessage, parentWidth); 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 686d2d4e1d9f6..95085d0f1a854 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 @@ -29,14 +29,18 @@ import android.graphics.drawable.InsetDrawable import android.util.PathParser import android.util.TypedValue import android.view.LayoutInflater -import android.view.View import android.widget.FrameLayout import com.android.wm.shell.R +/** + * The icon in the bubble overflow is scaled down, this is the percent of the normal bubble bitmap + * size to use. + */ +const val ICON_BITMAP_SIZE_PERCENT = 0.46f + class BubbleOverflow( private val context: Context, - private val controller: BubbleController, - private val stack: BubbleStackView + private val positioner: BubblePositioner ) : BubbleViewProvider { private lateinit var bitmap: Bitmap @@ -48,41 +52,36 @@ class BubbleOverflow( private var showDot = false private val inflater: LayoutInflater = LayoutInflater.from(context) - private val expandedView: BubbleExpandedView = inflater - .inflate(R.layout.bubble_expanded_view, null /* root */, false /* attachToRoot */) - as BubbleExpandedView - private val overflowBtn: BadgedImageView = inflater - .inflate(R.layout.bubble_overflow_button, null /* root */, false /* attachToRoot */) - as BadgedImageView + private var expandedView: BubbleExpandedView? + private var overflowBtn: BadgedImageView? + init { updateResources() - with(expandedView) { - initialize(controller, stack) - setOverflow(true) - applyThemeAttrs() - } - with(overflowBtn) { - setContentDescription(context.resources.getString( - R.string.bubble_overflow_button_content_description)) - updateBtnTheme() - } + bitmapSize = positioner.bubbleBitmapSize + iconBitmapSize = (bitmapSize * ICON_BITMAP_SIZE_PERCENT).toInt() + expandedView = null + overflowBtn = null + } + + fun initialize(controller: BubbleController) { + getExpandedView()?.initialize(controller, controller.stackView) + getExpandedView()?.setOverflow(true) } fun update() { updateResources() - expandedView.applyThemeAttrs() + getExpandedView()?.applyThemeAttrs() // Apply inset and new style to fresh icon drawable. - overflowBtn.setImageResource(R.drawable.bubble_ic_overflow_button) + getIconView()?.setImageResource(R.drawable.bubble_ic_overflow_button) updateBtnTheme() } fun updateResources() { - bitmapSize = context.resources.getDimensionPixelSize(R.dimen.bubble_bitmap_size) - iconBitmapSize = context.resources.getDimensionPixelSize( - R.dimen.bubble_overflow_icon_bitmap_size) - val bubbleSize = context.resources.getDimensionPixelSize(R.dimen.individual_bubble_size) - overflowBtn.setLayoutParams(FrameLayout.LayoutParams(bubbleSize, bubbleSize)) - expandedView.updateDimensions() + bitmapSize = positioner.bubbleBitmapSize + iconBitmapSize = (bitmapSize * 0.46f).toInt() + val bubbleSize = positioner.bubbleSize + overflowBtn?.setLayoutParams(FrameLayout.LayoutParams(bubbleSize, bubbleSize)) + expandedView?.updateDimensions() } private fun updateBtnTheme() { @@ -92,7 +91,7 @@ class BubbleOverflow( val typedValue = TypedValue() context.theme.resolveAttribute(android.R.attr.colorAccent, typedValue, true) val colorAccent = res.getColor(typedValue.resourceId) - overflowBtn.drawable?.setTint(colorAccent) + overflowBtn?.drawable?.setTint(colorAccent) dotColor = colorAccent val iconFactory = BubbleIconFactory(context) @@ -103,7 +102,7 @@ class BubbleOverflow( val bg = ColorDrawable(res.getColor( if (nightMode) R.color.bubbles_dark else R.color.bubbles_light)) - val fg = InsetDrawable(overflowBtn.drawable, + val fg = InsetDrawable(overflowBtn?.drawable, bitmapSize - iconBitmapSize /* inset */) bitmap = iconFactory.createBadgedIconBitmap(AdaptiveIconDrawable(bg, fg), null /* user */, true /* shrinkNonAdaptiveIcons */).icon @@ -111,7 +110,7 @@ class BubbleOverflow( // Update dot path dotPath = PathParser.createPathFromPathData( res.getString(com.android.internal.R.string.config_icon_mask)) - val scale = iconFactory.normalizer.getScale(overflowBtn.getDrawable(), + val scale = iconFactory.normalizer.getScale(getIconView()!!.getDrawable(), null /* outBounds */, null /* path */, null /* outMaskShape */) val radius = BadgedImageView.DEFAULT_PATH_SIZE / 2f val matrix = Matrix() @@ -120,20 +119,31 @@ class BubbleOverflow( dotPath.transform(matrix) // Attach BubbleOverflow to BadgedImageView - overflowBtn.setRenderedBubble(this) - overflowBtn.removeDotSuppressionFlag(BadgedImageView.SuppressionFlag.FLYOUT_VISIBLE) + overflowBtn?.setRenderedBubble(this) + overflowBtn?.removeDotSuppressionFlag(BadgedImageView.SuppressionFlag.FLYOUT_VISIBLE) } fun setVisible(visible: Int) { - overflowBtn.visibility = visible + overflowBtn?.visibility = visible } fun setShowDot(show: Boolean) { showDot = show - overflowBtn.updateDotVisibility(true /* animate */) + 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, + null /* root */, false /* attachToRoot */) as BubbleExpandedView + expandedView?.applyThemeAttrs() + updateResources() + } return expandedView } @@ -158,10 +168,20 @@ class BubbleOverflow( } override fun setContentVisibility(visible: Boolean) { - expandedView.setContentVisibility(visible) + expandedView?.setContentVisibility(visible) } - override fun getIconView(): View? { + override fun getIconView(): BadgedImageView? { + if (overflowBtn == null) { + overflowBtn = inflater.inflate(R.layout.bubble_overflow_button, + null /* root */, false /* attachToRoot */) as BadgedImageView + overflowBtn?.initialize(positioner) + overflowBtn?.setContentDescription(context.resources.getString( + R.string.bubble_overflow_button_content_description)) + val bubbleSize = positioner.bubbleSize + overflowBtn?.setLayoutParams(FrameLayout.LayoutParams(bubbleSize, bubbleSize)) + updateBtnTheme() + } return overflowBtn } @@ -170,7 +190,7 @@ class BubbleOverflow( } override fun getTaskId(): Int { - return if (expandedView != null) expandedView.getTaskId() else INVALID_TASK_ID + return if (expandedView != null) expandedView!!.getTaskId() else INVALID_TASK_ID } companion object { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowActivity.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowActivity.java index 2759b590bfadb..cfd0066e0fc3b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowActivity.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowActivity.java @@ -111,11 +111,11 @@ public class BubbleOverflowActivity extends Activity { IBinder binder = intent.getExtras().getBinder(EXTRA_BUBBLE_CONTROLLER); if (binder instanceof ObjectWrapper) { mController = ((ObjectWrapper) binder).get(); + updateOverflow(); } } else { Log.w(TAG, "Bubble overflow activity created without bubble controller!"); } - updateOverflow(); } void updateOverflow() { @@ -138,7 +138,9 @@ public class BubbleOverflowActivity extends Activity { final int viewHeight = recyclerViewHeight / rows; mAdapter = new BubbleOverflowAdapter(getApplicationContext(), mOverflowBubbles, - mController::promoteBubbleFromOverflow, viewWidth, viewHeight); + mController::promoteBubbleFromOverflow, + mController.getPositioner(), + viewWidth, viewHeight); mRecyclerView.setAdapter(mAdapter); mOverflowBubbles.clear(); @@ -257,15 +259,20 @@ class BubbleOverflowAdapter extends RecyclerView.Adapter mPromoteBubbleFromOverflow; + private BubblePositioner mPositioner; private List mBubbles; private int mWidth; private int mHeight; - public BubbleOverflowAdapter(Context context, List list, Consumer promoteBubble, + BubbleOverflowAdapter(Context context, + List list, + Consumer promoteBubble, + BubblePositioner positioner, int width, int height) { mContext = context; mBubbles = list; mPromoteBubbleFromOverflow = promoteBubble; + mPositioner = positioner; mWidth = width; mHeight = height; } @@ -295,7 +302,7 @@ class BubbleOverflowAdapter extends RecyclerView.Adapter 0) + ? mTaskbarIconSize + : mBubbleSize; + return bsize; + } + + /** Size of the bitmap within the bubble */ + public int getBubbleBitmapSize() { + float size = (mShowingInTaskbar && mTaskbarIconSize > 0) + ? (mTaskbarIconSize * BUBBLE_BITMAP_SIZE_PERCENT) + : mBubbleBitmapSize; + return (int) size; + } + + /** + * Sets the stack's most recent position along the edge of the screen. This is saved when the + * last bubble is removed, so that the stack can be restored in its previous position. + */ + public void setRestingPosition(PointF position) { + if (mRestingStackPosition == null) { + mRestingStackPosition = new PointF(position); + } else { + mRestingStackPosition.set(position); + } + } + + /** The position the bubble stack should rest at when collapsed. */ + public PointF getRestingPosition() { + if (mPinLocation != null) { + return mPinLocation; + } + if (mRestingStackPosition == null) { + return getDefaultStartPosition(); + } + return mRestingStackPosition; + } + + /** + * @return the stack position to use if we don't have a saved location or if user education + * is being shown. + */ + public PointF getDefaultStartPosition() { + // Start on the left if we're in LTR, right otherwise. + final boolean startOnLeft = + mContext.getResources().getConfiguration().getLayoutDirection() + != View.LAYOUT_DIRECTION_RTL; + final float startingVerticalOffset = mContext.getResources().getDimensionPixelOffset( + R.dimen.bubble_stack_starting_offset_y); + // TODO: placement bug here because mPositionRect doesn't handle the overhanging edge + return new BubbleStackView.RelativeStackPosition( + startOnLeft, + startingVerticalOffset / mPositionRect.height()) + .getAbsolutePositionInRegion(new RectF(mPositionRect)); + } + + /** + * @return whether the bubble stack is pinned to the taskbar. + */ + public boolean showingInTaskbar() { + return mShowingInTaskbar; + } + + /** + * In some situations bubbles will be pinned to a specific onscreen location. This sets the + * location to anchor the stack to. + */ + public void setPinnedLocation(PointF point) { + mPinLocation = point; + } } 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 155f3427f3d4d..38fcd2f06003a 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 @@ -30,7 +30,6 @@ import android.annotation.SuppressLint; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; -import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.ColorMatrix; @@ -701,7 +700,6 @@ public class BubbleStackView extends FrameLayout } }; - @Nullable private BubbleOverflow mBubbleOverflow; private StackEducationView mStackEduView; private ManageEducationView mManageEduView; @@ -818,11 +816,12 @@ public class BubbleStackView extends FrameLayout setFocusable(true); mBubbleContainer.bringToFront(); - mBubbleOverflow = new BubbleOverflow(getContext(), bubbleController, this); + mBubbleOverflow = new BubbleOverflow(getContext(), mPositioner); + mBubbleOverflow.initialize(mBubbleController); mBubbleContainer.addView(mBubbleOverflow.getIconView(), mBubbleContainer.getChildCount() /* index */, - new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, - ViewGroup.LayoutParams.WRAP_CONTENT)); + new FrameLayout.LayoutParams(mPositioner.getBubbleSize(), + mPositioner.getBubbleSize())); updateOverflow(); mBubbleOverflow.getIconView().setOnClickListener((View v) -> { setSelectedBubble(mBubbleOverflow); @@ -1067,7 +1066,7 @@ public class BubbleStackView extends FrameLayout mStackEduView = new StackEducationView(mContext); addView(mStackEduView); } - return mStackEduView.show(mStackAnimationController.getStartPosition()); + return mStackEduView.show(mPositioner.getDefaultStartPosition()); } private void updateUserEdu() { @@ -1093,7 +1092,7 @@ public class BubbleStackView extends FrameLayout addView(mFlyout, new FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT)); } - void updateFlyout(float fontScale) { + void updateFontScale(float fontScale) { mFlyout.updateFontSize(fontScale); } @@ -1130,7 +1129,9 @@ public class BubbleStackView extends FrameLayout Resources res = getContext().getResources(); mBubblePaddingTop = res.getDimensionPixelSize(R.dimen.bubble_padding_top); - mRelativeStackPositionBeforeRotation = mStackAnimationController.getRelativeStackPosition(); + mRelativeStackPositionBeforeRotation = new RelativeStackPosition( + mPositioner.getRestingPosition(), + mStackAnimationController.getAllowableStackPositionRegion()); mManageMenu.setVisibility(View.INVISIBLE); mShowingManage = false; @@ -1157,7 +1158,7 @@ public class BubbleStackView extends FrameLayout Resources res = getContext().getResources(); mBubblePaddingTop = res.getDimensionPixelSize(R.dimen.bubble_padding_top); - mBubbleSize = getResources().getDimensionPixelSize(R.dimen.individual_bubble_size); + mBubbleSize = mPositioner.getBubbleSize(); for (Bubble b : mBubbleData.getBubbles()) { if (b.getIconView() == null) { Log.d(TAG, "Display size changed. Icon null: " + b); @@ -1165,6 +1166,7 @@ public class BubbleStackView extends FrameLayout } b.getIconView().setLayoutParams(new LayoutParams(mBubbleSize, mBubbleSize)); } + mBubbleOverflow.getIconView().setLayoutParams(new LayoutParams(mBubbleSize, mBubbleSize)); mExpandedAnimationController.updateResources(); mStackAnimationController.updateResources(); mDismissView.updateResources(); @@ -1199,8 +1201,8 @@ public class BubbleStackView extends FrameLayout super.onDetachedFromWindow(); getViewTreeObserver().removeOnPreDrawListener(mViewUpdater); getViewTreeObserver().removeOnComputeInternalInsetsListener(this); - if (mBubbleOverflow != null && mBubbleOverflow.getExpandedView() != null) { - mBubbleOverflow.getExpandedView().cleanUpExpandedState(); + if (mBubbleOverflow != null) { + mBubbleOverflow.cleanUpExpandedState(); } } @@ -1390,8 +1392,7 @@ public class BubbleStackView extends FrameLayout if (getBubbleCount() == 0 && shouldShowStackEdu()) { // Override the default stack position if we're showing user education. - mStackAnimationController.setStackPosition( - mStackAnimationController.getStartPosition()); + mStackAnimationController.setStackPosition(mPositioner.getDefaultStartPosition()); } if (getBubbleCount() == 0) { @@ -1410,7 +1411,8 @@ public class BubbleStackView extends FrameLayout bubble.getIconView().setOnTouchListener(mBubbleTouchListener); mBubbleContainer.addView(bubble.getIconView(), 0, - new FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT)); + new FrameLayout.LayoutParams(mPositioner.getBubbleSize(), + mPositioner.getBubbleSize())); animateInFlyoutForBubble(bubble); requestUpdate(); logBubbleEvent(bubble, FrameworkStatsLog.BUBBLE_UICHANGED__ACTION__POSTED); @@ -1614,6 +1616,11 @@ public class BubbleStackView extends FrameLayout mBubbleController.hideCurrentInputMethod(); } + /** Set the stack position to whatever the positioner says. */ + void updateStackPosition() { + mStackAnimationController.setStackPosition(mPositioner.getRestingPosition()); + } + private void beforeExpandedViewAnimation() { mIsExpansionAnimating = true; hideFlyoutImmediate(); @@ -1629,8 +1636,7 @@ public class BubbleStackView extends FrameLayout private void animateExpansion() { cancelDelayedExpandCollapseSwitchAnimations(); - final boolean isLandscape = - mPositioner.getOrientation() == Configuration.ORIENTATION_LANDSCAPE; + final boolean showVertically = mPositioner.showBubblesVertically(); mIsExpanded = true; if (mStackEduView != null) { mStackEduView.hide(true /* fromExpansion */); @@ -1650,14 +1656,19 @@ public class BubbleStackView extends FrameLayout mExpandedViewContainer.setTranslationY(getExpandedViewY()); mExpandedViewContainer.setAlpha(1f); - // X-value of the bubble we're expanding, once it's settled in its row. + int index; + if (mExpandedBubble != null && BubbleOverflow.KEY.equals(mExpandedBubble.getKey())) { + index = mBubbleData.getBubbles().size(); + } else { + index = getBubbleIndex(mExpandedBubble); + } + // Position of the bubble we're expanding, once it's settled in its row. final float bubbleWillBeAt = - mExpandedAnimationController.getBubbleXOrYForOrientation( - mBubbleData.getBubbles().indexOf(mExpandedBubble)); + mExpandedAnimationController.getBubbleXOrYForOrientation(index); // How far horizontally the bubble will be animating. We'll wait a bit longer for bubbles // that are animating farther, so that the expanded view doesn't move as much. - final float relevantStackPosition = isLandscape + final float relevantStackPosition = showVertically ? mStackAnimationController.getStackPosition().y : mStackAnimationController.getStackPosition().x; final float distanceAnimated = Math.abs(bubbleWillBeAt - relevantStackPosition); @@ -1674,7 +1685,7 @@ public class BubbleStackView extends FrameLayout } // Set the pivot point for the scale, so the expanded view animates out from the bubble. - if (isLandscape) { + if (showVertically) { float pivotX; float pivotY = bubbleWillBeAt + mBubbleSize / 2f; if (mStackOnLeftOrWillBe) { @@ -1709,7 +1720,7 @@ public class BubbleStackView extends FrameLayout if (mExpandedBubble == null || mExpandedBubble.getIconView() == null) { return; } - float translation = isLandscape + float translation = showVertically ? mExpandedBubble.getIconView().getTranslationY() : mExpandedBubble.getIconView().getTranslationX(); mExpandedViewContainerMatrix.postTranslate( @@ -1761,13 +1772,17 @@ public class BubbleStackView extends FrameLayout // We want to visually collapse into this bubble during the animation. final View expandingFromBubble = mExpandedBubble.getIconView(); + int index; + if (mExpandedBubble != null && BubbleOverflow.KEY.equals(mExpandedBubble.getKey())) { + index = mBubbleData.getBubbles().size(); + } else { + index = mBubbleData.getBubbles().indexOf(mExpandedBubble); + } // Value the bubble is animating from (back into the stack). final float expandingFromBubbleAt = - mExpandedAnimationController.getBubbleXOrYForOrientation( - mBubbleData.getBubbles().indexOf(mExpandedBubble)); - final boolean isLandscape = - mPositioner.getOrientation() == Configuration.ORIENTATION_LANDSCAPE; - if (isLandscape) { + mExpandedAnimationController.getBubbleXOrYForOrientation(index); + final boolean showVertically = mPositioner.showBubblesVertically(); + if (mPositioner.showBubblesVertically()) { float pivotX; float pivotY = expandingFromBubbleAt + mBubbleSize / 2f; if (mStackOnLeftOrWillBe) { @@ -1792,7 +1807,7 @@ public class BubbleStackView extends FrameLayout .addUpdateListener((target, values) -> { if (expandingFromBubble != null) { // Follow the bubble as it translates! - if (isLandscape) { + if (showVertically) { mExpandedViewContainerMatrix.postTranslate( 0f, expandingFromBubble.getTranslationY() - expandingFromBubbleAt); @@ -1849,7 +1864,7 @@ public class BubbleStackView extends FrameLayout .spring(DynamicAnimation.SCALE_Y, 0f, mScaleOutSpringConfig) .withEndActions(this::releaseAnimatingOutBubbleBuffer); - if (mPositioner.getOrientation() == Configuration.ORIENTATION_LANDSCAPE) { + if (mPositioner.showBubblesVertically()) { float translationX = mStackAnimationController.isStackOnLeftSide() ? mAnimatingOutSurfaceContainer.getTranslationX() + mBubbleSize * 2 : mAnimatingOutSurfaceContainer.getTranslationX(); @@ -1874,7 +1889,7 @@ public class BubbleStackView extends FrameLayout mExpandedViewContainer.setAlpha(1f); mExpandedViewContainer.setVisibility(View.VISIBLE); - if (mPositioner.getOrientation() == Configuration.ORIENTATION_LANDSCAPE) { + if (mPositioner.showBubblesVertically()) { float pivotX; float pivotY = expandingFromBubbleDestination + mBubbleSize / 2f; if (mStackOnLeftOrWillBe) { @@ -2180,7 +2195,7 @@ public class BubbleStackView extends FrameLayout */ float getExpandedViewY() { final int top = mPositioner.getAvailableRect().top; - if (mPositioner.getOrientation() == Configuration.ORIENTATION_LANDSCAPE) { + if (mPositioner.showBubblesVertically()) { return top + mExpandedViewPadding; } else { return top + mBubbleSize + mBubblePaddingTop; @@ -2278,7 +2293,8 @@ public class BubbleStackView extends FrameLayout expandFlyoutAfterDelay /* onLayoutComplete */, mAfterFlyoutHidden, bubble.getIconView().getDotCenter(), - !bubble.showDot()); + !bubble.showDot(), + mPositioner); } mFlyout.bringToFront(); }); @@ -2550,7 +2566,7 @@ public class BubbleStackView extends FrameLayout Insets insets = mPositioner.getInsets(); int leftPadding = insets.left + mExpandedViewPadding; int rightPadding = insets.right + mExpandedViewPadding; - if (mPositioner.getOrientation() == Configuration.ORIENTATION_LANDSCAPE) { + if (mPositioner.showBubblesVertically()) { if (!mStackAnimationController.isStackOnLeftSide()) { rightPadding += mPointerHeight + mBubbleSize; } else { @@ -2581,7 +2597,9 @@ public class BubbleStackView extends FrameLayout bv.setZ((mMaxBubbles * mBubbleElevation) - i); if (mIsExpanded) { - bv.showDotAndBadge(false /* onLeft */); + // If we're not displaying vertically, we always show the badge on the left. + boolean onLeft = mPositioner.showBubblesVertically() && !mStackOnLeftOrWillBe; + bv.showDotAndBadge(onLeft); } else if (i == 0) { bv.showDotAndBadge(!mStackOnLeftOrWillBe); } else { @@ -2599,7 +2617,7 @@ public class BubbleStackView extends FrameLayout return; } float bubblePosition = mExpandedAnimationController.getBubbleXOrYForOrientation(index); - if (mPositioner.getOrientation() == Configuration.ORIENTATION_LANDSCAPE) { + if (mPositioner.showBubblesVertically()) { float x = mStackOnLeftOrWillBe ? mPositioner.getAvailableRect().left : mPositioner.getAvailableRect().right @@ -2661,21 +2679,11 @@ public class BubbleStackView extends FrameLayout .floatValue(); } - /** Set the start position of the bubble stack. */ - public void setStackStartPosition(RelativeStackPosition position) { - mStackAnimationController.setStackStartPosition(position); - } - /** @return the position of the bubble stack. */ public PointF getStackPosition() { return mStackAnimationController.getStackPosition(); } - /** @return the relative position of the bubble stack. */ - public RelativeStackPosition getRelativeStackPosition() { - return mStackAnimationController.getRelativeStackPosition(); - } - /** * Logs the bubble UI event. * diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java index 0b683067c45bf..e21ba6392e95b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java @@ -134,6 +134,7 @@ public class BubbleViewInfoTask extends AsyncTask { if (!canceled) { - mRestingStackPosition.set(mStackPosition); + mPositioner.setRestingPosition(mStackPosition); springFirstBubbleWithStackFollowing(property, spring, endVelocity, finalPosition != null @@ -679,7 +676,7 @@ public class StackAnimationController extends // resting position - the touch location is not a valid resting // position. We'll set this when the stack springs to the left or // right side of the screen after the touch gesture ends. - mRestingStackPosition.set(mStackPosition); + mPositioner.setRestingPosition(mStackPosition); } if (after != null) { @@ -772,10 +769,9 @@ public class StackAnimationController extends if (getBubbleCount() > 0) { animationForChildAtIndex(0).translationX(mStackPosition.x).start(); } else { + // TODO: still needed with positioner? // When all children are removed ensure stack position is sane - setStackPosition(mRestingStackPosition == null - ? getStartPosition() - : mRestingStackPosition); + mPositioner.setRestingPosition(mPositioner.getRestingPosition()); // Remove the stack from the coordinator since we don't have any bubbles and aren't // visible. @@ -848,8 +844,8 @@ public class StackAnimationController extends mSwapAnimationOffset = res.getDimensionPixelSize(R.dimen.bubble_swap_animation_offset); mMaxBubbles = res.getInteger(R.integer.bubbles_max_rendered); mElevation = res.getDimensionPixelSize(R.dimen.bubble_elevation); - mBubbleSize = res.getDimensionPixelSize(R.dimen.individual_bubble_size); - mBubbleBitmapSize = res.getDimensionPixelSize(R.dimen.bubble_bitmap_size); + mBubbleSize = mPositioner.getBubbleSize(); + mBubbleBitmapSize = mPositioner.getBubbleBitmapSize(); mBubblePaddingTop = res.getDimensionPixelSize(R.dimen.bubble_padding_top); mBubbleOffscreen = res.getDimensionPixelSize(R.dimen.bubble_stack_offscreen); } @@ -873,9 +869,8 @@ public class StackAnimationController extends // Post to ensure that the layout's width and height have been calculated. mLayout.setVisibility(View.INVISIBLE); mLayout.post(() -> { - setStackPosition(mRestingStackPosition == null - ? getStartPosition() - : mRestingStackPosition); + setStackPosition(mPositioner.getRestingPosition()); + mStackMovedToStartPosition = true; mLayout.setVisibility(View.VISIBLE); @@ -919,11 +914,7 @@ public class StackAnimationController extends Log.d(TAG, String.format("Setting position to (%f, %f).", pos.x, pos.y)); mStackPosition.set(pos.x, pos.y); - if (mRestingStackPosition == null) { - mRestingStackPosition = new PointF(); - } - - mRestingStackPosition.set(mStackPosition); + mPositioner.setRestingPosition(mStackPosition); // If we're not the active controller, we don't want to physically move the bubble views. if (isActiveController()) { diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleFlyoutViewTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleFlyoutViewTest.java index 5b77e4a0b72fa..69d5244e5ac27 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleFlyoutViewTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleFlyoutViewTest.java @@ -19,7 +19,9 @@ package com.android.wm.shell.bubbles; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertNotSame; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.graphics.Color; import android.graphics.PointF; @@ -36,7 +38,7 @@ import com.android.wm.shell.ShellTestCase; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.Mockito; +import org.mockito.Mock; import org.mockito.MockitoAnnotations; @SmallTest @@ -48,11 +50,16 @@ public class BubbleFlyoutViewTest extends ShellTestCase { private TextView mSenderName; private float[] mDotCenter = new float[2]; private Bubble.FlyoutMessage mFlyoutMessage; + @Mock + private BubblePositioner mPositioner; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); + when(mPositioner.getBubbleBitmapSize()).thenReturn(40); + when(mPositioner.getBubbleSize()).thenReturn(60); + mFlyoutMessage = new Bubble.FlyoutMessage(); mFlyoutMessage.senderName = "Josh"; mFlyoutMessage.message = "Hello"; @@ -70,7 +77,8 @@ public class BubbleFlyoutViewTest extends ShellTestCase { mFlyout.setupFlyoutStartingAsDot( mFlyoutMessage, new PointF(100, 100), 500, true, Color.WHITE, null, null, mDotCenter, - false); + false, + mPositioner); mFlyout.setVisibility(View.VISIBLE); assertEquals("Hello", mFlyoutText.getText()); @@ -80,10 +88,11 @@ public class BubbleFlyoutViewTest extends ShellTestCase { @Test public void testFlyoutHide_runsCallback() { - Runnable after = Mockito.mock(Runnable.class); + Runnable after = mock(Runnable.class); mFlyout.setupFlyoutStartingAsDot(mFlyoutMessage, new PointF(100, 100), 500, true, Color.WHITE, null, after, mDotCenter, - false); + false, + mPositioner); mFlyout.hideFlyout(); verify(after).run(); @@ -93,7 +102,8 @@ public class BubbleFlyoutViewTest extends ShellTestCase { public void testSetCollapsePercent() { mFlyout.setupFlyoutStartingAsDot(mFlyoutMessage, new PointF(100, 100), 500, true, Color.WHITE, null, null, mDotCenter, - false); + false, + mPositioner); mFlyout.setVisibility(View.VISIBLE); mFlyout.setCollapsePercent(1f); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/TestableBubblePositioner.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/TestableBubblePositioner.java new file mode 100644 index 0000000000000..96bc5335a32cb --- /dev/null +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/TestableBubblePositioner.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.bubbles; + +import android.content.Context; +import android.content.res.Configuration; +import android.graphics.Insets; +import android.graphics.Rect; +import android.view.WindowManager; + +public class TestableBubblePositioner extends BubblePositioner { + + public TestableBubblePositioner(Context context, + WindowManager windowManager) { + super(context, windowManager); + + updateInternal(Configuration.ORIENTATION_PORTRAIT, + Insets.of(0, 0, 0, 0), + new Rect(0, 0, 500, 1000)); + } +} diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationControllerTest.java index 9c4f341bdfd5b..1eba3c266358e 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationControllerTest.java @@ -64,7 +64,7 @@ public class ExpandedAnimationControllerTest extends PhysicsAnimationLayoutTestC super.setUp(); BubblePositioner positioner = new BubblePositioner(getContext(), mock(WindowManager.class)); - positioner.update(Configuration.ORIENTATION_PORTRAIT, + positioner.updateInternal(Configuration.ORIENTATION_PORTRAIT, Insets.of(0, 0, 0, 0), new Rect(0, 0, mDisplayWidth, mDisplayHeight)); mExpandedController = new ExpandedAnimationController(positioner, mExpandedViewPadding, diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/StackAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/StackAnimationControllerTest.java index 6b01462afd8d3..f36dcbe7bf4b6 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/StackAnimationControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/StackAnimationControllerTest.java @@ -27,6 +27,7 @@ import static org.mockito.Mockito.verify; import android.graphics.PointF; import android.testing.AndroidTestingRunner; import android.view.View; +import android.view.WindowManager; import android.widget.FrameLayout; import androidx.dynamicanimation.animation.DynamicAnimation; @@ -34,7 +35,7 @@ import androidx.dynamicanimation.animation.SpringForce; import androidx.test.filters.SmallTest; import com.android.wm.shell.R; -import com.android.wm.shell.bubbles.BubblePositioner; +import com.android.wm.shell.bubbles.TestableBubblePositioner; import com.android.wm.shell.common.FloatingContentCoordinator; import org.junit.Before; @@ -310,7 +311,7 @@ public class StackAnimationControllerTest extends PhysicsAnimationLayoutTestCase super(floatingContentCoordinator, bubbleCountSupplier, onBubbleAnimatedOutAction, - mock(BubblePositioner.class)); + new TestableBubblePositioner(mContext, mock(WindowManager.class))); } @Override diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java index a46e563a7c57f..ede8b64b129a8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java @@ -45,9 +45,6 @@ import android.app.INotificationManager; import android.app.Notification; import android.app.PendingIntent; import android.content.pm.LauncherApps; -import android.content.res.Configuration; -import android.graphics.Insets; -import android.graphics.Rect; import android.hardware.display.AmbientDisplayConfiguration; import android.hardware.face.FaceManager; import android.os.Handler; @@ -99,7 +96,6 @@ import com.android.wm.shell.bubbles.BubbleData; import com.android.wm.shell.bubbles.BubbleDataRepository; import com.android.wm.shell.bubbles.BubbleEntry; import com.android.wm.shell.bubbles.BubbleLogger; -import com.android.wm.shell.bubbles.BubblePositioner; import com.android.wm.shell.bubbles.BubbleStackView; import com.android.wm.shell.bubbles.Bubbles; import com.android.wm.shell.common.FloatingContentCoordinator; @@ -206,8 +202,8 @@ public class BubblesTest extends SysuiTestCase { private WindowManagerShellWrapper mWindowManagerShellWrapper; @Mock private BubbleLogger mBubbleLogger; - @Mock - private BubblePositioner mPositioner; + + private TestableBubblePositioner mPositioner; private BubbleData mBubbleData; @@ -257,10 +253,7 @@ public class BubblesTest extends SysuiTestCase { mBubbleData = new BubbleData(mContext, mBubbleLogger); - Rect availableRect = new Rect(0, 0, 1000, 5000); - when(mPositioner.getAvailableRect()).thenReturn(availableRect); - when(mPositioner.getOrientation()).thenReturn(Configuration.ORIENTATION_PORTRAIT); - when(mPositioner.getInsets()).thenReturn(Insets.of(0, 0, 0, 0)); + mPositioner = new TestableBubblePositioner(mContext, mWindowManager); TestableNotificationInterruptStateProviderImpl interruptionStateProvider = new TestableNotificationInterruptStateProviderImpl(mContext.getContentResolver(), diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java index d8033dbdd281e..9bba2f459172b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java @@ -42,9 +42,6 @@ import android.app.INotificationManager; import android.app.Notification; import android.app.PendingIntent; import android.content.pm.LauncherApps; -import android.content.res.Configuration; -import android.graphics.Insets; -import android.graphics.Rect; import android.hardware.display.AmbientDisplayConfiguration; import android.os.Handler; import android.os.PowerManager; @@ -92,7 +89,6 @@ import com.android.wm.shell.bubbles.BubbleData; import com.android.wm.shell.bubbles.BubbleDataRepository; import com.android.wm.shell.bubbles.BubbleEntry; import com.android.wm.shell.bubbles.BubbleLogger; -import com.android.wm.shell.bubbles.BubblePositioner; import com.android.wm.shell.bubbles.BubbleStackView; import com.android.wm.shell.bubbles.Bubbles; import com.android.wm.shell.common.FloatingContentCoordinator; @@ -188,8 +184,8 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase { private WindowManagerShellWrapper mWindowManagerShellWrapper; @Mock private BubbleLogger mBubbleLogger; - @Mock - private BubblePositioner mPositioner; + + private TestableBubblePositioner mPositioner; private BubbleData mBubbleData; @@ -226,10 +222,7 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase { mBubbleData = new BubbleData(mContext, mBubbleLogger); - Rect availableRect = new Rect(0, 0, 1000, 5000); - when(mPositioner.getAvailableRect()).thenReturn(availableRect); - when(mPositioner.getOrientation()).thenReturn(Configuration.ORIENTATION_PORTRAIT); - when(mPositioner.getInsets()).thenReturn(Insets.of(0, 0, 0, 0)); + mPositioner = new TestableBubblePositioner(mContext, mWindowManager); TestableNotificationInterruptStateProviderImpl interruptionStateProvider = new TestableNotificationInterruptStateProviderImpl(mContext.getContentResolver(), diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubblePositioner.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubblePositioner.java new file mode 100644 index 0000000000000..24a7cd5c89ac4 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubblePositioner.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.wmshell; + +import android.content.Context; +import android.content.res.Configuration; +import android.graphics.Insets; +import android.graphics.Rect; +import android.view.WindowManager; + +import com.android.wm.shell.bubbles.BubblePositioner; + +public class TestableBubblePositioner extends BubblePositioner { + + public TestableBubblePositioner(Context context, + WindowManager windowManager) { + super(context, windowManager); + + updateInternal(Configuration.ORIENTATION_PORTRAIT, + Insets.of(0, 0, 0, 0), + new Rect(0, 0, 500, 1000)); + } +}