diff options
| author | 2023-11-14 17:49:14 +0000 | |
|---|---|---|
| committer | 2023-11-14 17:49:14 +0000 | |
| commit | 4c722acbb2204872e563fe7412d6fee0a151fea9 (patch) | |
| tree | daaf059dd50f97b70e4f6e202d0b8294fc38a043 | |
| parent | 32a0d2ff6a0a8bb17c82a07fe0643bc6b40598cb (diff) | |
| parent | c9aae16bfedf64d93e87484fb0ab486b920b93d0 (diff) | |
Merge changes from topic "b302520752-user-education-position" into main
* changes:
Fix bubble user education if bubble is on the right (part 2)
Fix bubble user education if bubble is on the right (part 1)
7 files changed, 203 insertions, 86 deletions
diff --git a/libs/WindowManager/Shell/res/layout/bubble_stack_user_education.xml b/libs/WindowManager/Shell/res/layout/bubble_stack_user_education.xml index 5c8c84cbb85b..ed00a87b0fa5 100644 --- a/libs/WindowManager/Shell/res/layout/bubble_stack_user_education.xml +++ b/libs/WindowManager/Shell/res/layout/bubble_stack_user_education.xml @@ -21,8 +21,8 @@ android:layout_width="wrap_content" android:paddingTop="48dp" android:paddingBottom="48dp" - android:paddingEnd="@dimen/bubble_user_education_padding_end" - android:layout_marginEnd="@dimen/bubble_user_education_margin_end" + android:paddingHorizontal="@dimen/bubble_user_education_padding_horizontal" + android:layout_marginEnd="@dimen/bubble_user_education_margin_horizontal" android:orientation="vertical" android:background="@drawable/bubble_stack_user_education_bg" > diff --git a/libs/WindowManager/Shell/res/layout/bubbles_manage_button_education.xml b/libs/WindowManager/Shell/res/layout/bubbles_manage_button_education.xml index b28f58f8356d..4f6bdfd98d54 100644 --- a/libs/WindowManager/Shell/res/layout/bubbles_manage_button_education.xml +++ b/libs/WindowManager/Shell/res/layout/bubbles_manage_button_education.xml @@ -23,8 +23,8 @@ android:clickable="true" android:paddingTop="28dp" android:paddingBottom="16dp" - android:paddingEnd="@dimen/bubble_user_education_padding_end" - android:layout_marginEnd="@dimen/bubble_user_education_margin_end" + android:paddingEnd="@dimen/bubble_user_education_padding_horizontal" + android:layout_marginEnd="@dimen/bubble_user_education_margin_horizontal" android:orientation="vertical" android:background="@drawable/bubble_stack_user_education_bg" > diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml index de9d2a292540..f20d44df21b1 100644 --- a/libs/WindowManager/Shell/res/values/dimen.xml +++ b/libs/WindowManager/Shell/res/values/dimen.xml @@ -224,9 +224,9 @@ <dimen name="bubbles_user_education_width">480dp</dimen> <!-- Margin applied to the end of the user education views (really only matters for phone since the width is match parent). --> - <dimen name="bubble_user_education_margin_end">24dp</dimen> + <dimen name="bubble_user_education_margin_horizontal">24dp</dimen> <!-- Padding applied to the end of the user education view. --> - <dimen name="bubble_user_education_padding_end">58dp</dimen> + <dimen name="bubble_user_education_padding_horizontal">58dp</dimen> <!-- Padding between the bubble and the user education text. --> <dimen name="bubble_user_education_stack_padding">16dp</dimen> <!-- Max width for the bubble popup view. --> diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java index 144c456f8838..09ae84a50328 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java @@ -46,6 +46,12 @@ public class BubblePositioner { ? "BubblePositioner" : BubbleDebugConfig.TAG_BUBBLES; + /** The screen edge the bubble stack is pinned to */ + public enum StackPinnedEdge { + LEFT, + RIGHT + } + /** When the bubbles are collapsed in a stack only some of them are shown, this is how many. **/ public static final int NUM_VISIBLE_WHEN_RESTING = 2; /** Indicates a bubble's height should be the maximum available space. **/ @@ -694,6 +700,15 @@ public class BubblePositioner { final boolean startOnLeft = isAppBubble ? layoutDirection == LAYOUT_DIRECTION_RTL : layoutDirection != LAYOUT_DIRECTION_RTL; + return getStartPosition(startOnLeft ? StackPinnedEdge.LEFT : StackPinnedEdge.RIGHT); + } + + /** + * The stack position to use if user education is being shown. + * + * @param stackPinnedEdge the screen edge the stack is pinned to. + */ + public PointF getStartPosition(StackPinnedEdge stackPinnedEdge) { final RectF allowableStackPositionRegion = getAllowableStackPositionRegion( 1 /* default starts with 1 bubble */); if (isLargeScreen()) { @@ -702,7 +717,7 @@ public class BubblePositioner { final float desiredY = mScreenRect.height() / 2f - (mBubbleSize / 2f); final float offset = desiredY / mScreenRect.height(); return new BubbleStackView.RelativeStackPosition( - startOnLeft, + stackPinnedEdge == StackPinnedEdge.LEFT, offset) .getAbsolutePositionInRegion(allowableStackPositionRegion); } else { @@ -710,7 +725,7 @@ public class BubblePositioner { R.dimen.bubble_stack_starting_offset_y); // TODO: placement bug here because mPositionRect doesn't handle the overhanging edge return new BubbleStackView.RelativeStackPosition( - startOnLeft, + stackPinnedEdge == StackPinnedEdge.LEFT, startingVerticalOffset / mPositionRect.height()) .getAbsolutePositionInRegion(allowableStackPositionRegion); } 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 87461dcb0515..2cee675e83be 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 @@ -25,6 +25,8 @@ import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_STACK_ import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES; import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.wm.shell.bubbles.BubblePositioner.NUM_VISIBLE_WHEN_RESTING; +import static com.android.wm.shell.bubbles.BubblePositioner.StackPinnedEdge.LEFT; +import static com.android.wm.shell.bubbles.BubblePositioner.StackPinnedEdge.RIGHT; import static com.android.wm.shell.common.bubbles.BubbleConstants.BUBBLE_EXPANDED_SCRIM_ALPHA; import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BUBBLES; @@ -1296,6 +1298,9 @@ public class BubbleStackView extends FrameLayout return shouldShow; } + /** + * Show manage education if should show and was not showing before. + */ private void maybeShowManageEdu() { if (!shouldShowManageEdu()) { return; @@ -1304,7 +1309,16 @@ public class BubbleStackView extends FrameLayout mManageEduView = new ManageEducationView(mContext, mPositioner); addView(mManageEduView); } - mManageEduView.show(mExpandedBubble.getExpandedView()); + showManageEdu(); + } + + /** + * Show manage education if was not showing before. + */ + private void showManageEdu() { + if (mExpandedBubble == null || mExpandedBubble.getExpandedView() == null) return; + mManageEduView.show(mExpandedBubble.getExpandedView(), + mStackAnimationController.isStackOnLeftSide()); } @VisibleForTesting @@ -1350,10 +1364,21 @@ public class BubbleStackView extends FrameLayout mStackEduView = new StackEducationView(mContext, mPositioner, mBubbleController); addView(mStackEduView); } + return showStackEdu(); + } + + /** + * @return true if education view for the collapsed stack was not showing before. + */ + private boolean showStackEdu() { + // Stack appears on top of the education views mBubbleContainer.bringToFront(); // Ensure the stack is in the correct spot - mStackAnimationController.setStackPosition(mPositioner.getDefaultStartPosition()); - return mStackEduView.show(mPositioner.getDefaultStartPosition()); + PointF position = mPositioner.getStartPosition( + mStackAnimationController.isStackOnLeftSide() ? LEFT : RIGHT); + // Animate stack to the position + mStackAnimationController.springStackAfterFling(position.x, position.y); + return mStackEduView.show(position); } @VisibleForTesting @@ -1367,16 +1392,13 @@ public class BubbleStackView extends FrameLayout removeView(mStackEduView); mStackEduView = new StackEducationView(mContext, mPositioner, mBubbleController); addView(mStackEduView); - mBubbleContainer.bringToFront(); // Stack appears on top of the stack education - // Ensure the stack is in the correct spot - mStackAnimationController.setStackPosition(mPositioner.getDefaultStartPosition()); - mStackEduView.show(mPositioner.getDefaultStartPosition()); + showStackEdu(); } if (isManageEduVisible()) { removeView(mManageEduView); mManageEduView = new ManageEducationView(mContext, mPositioner); addView(mManageEduView); - mManageEduView.show(mExpandedBubble.getExpandedView()); + showManageEdu(); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/ManageEducationView.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/ManageEducationView.kt index 1b41f793311d..61e17c8ec459 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/ManageEducationView.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/ManageEducationView.kt @@ -19,6 +19,7 @@ import android.content.Context import android.graphics.Color import android.graphics.Rect import android.graphics.drawable.ColorDrawable +import android.view.Gravity import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -32,10 +33,10 @@ import com.android.wm.shell.animation.Interpolators * User education view to highlight the manage button that allows a user to configure the settings * for the bubble. Shown only the first time a user expands a bubble. */ -class ManageEducationView constructor(context: Context, positioner: BubblePositioner) - : LinearLayout(context) { +class ManageEducationView(context: Context, positioner: BubblePositioner) : LinearLayout(context) { - private val TAG = if (BubbleDebugConfig.TAG_WITH_CLASS_NAME) "ManageEducationView" + private val TAG = + if (BubbleDebugConfig.TAG_WITH_CLASS_NAME) "ManageEducationView" else BubbleDebugConfig.TAG_BUBBLES private val ANIMATE_DURATION: Long = 200 @@ -62,7 +63,7 @@ class ManageEducationView constructor(context: Context, positioner: BubblePositi override fun setLayoutDirection(layoutDirection: Int) { super.setLayoutDirection(layoutDirection) - setDrawableDirection() + setDrawableDirection(layoutDirection == LAYOUT_DIRECTION_LTR) } override fun onFinishInflate() { @@ -71,8 +72,10 @@ class ManageEducationView constructor(context: Context, positioner: BubblePositi } private fun setButtonColor() { - val typedArray = mContext.obtainStyledAttributes(intArrayOf( - com.android.internal.R.attr.colorAccentPrimary)) + val typedArray = + mContext.obtainStyledAttributes( + intArrayOf(com.android.internal.R.attr.colorAccentPrimary) + ) val buttonColor = typedArray.getColor(0 /* index */, Color.TRANSPARENT) typedArray.recycle() @@ -81,11 +84,11 @@ class ManageEducationView constructor(context: Context, positioner: BubblePositi gotItButton.setBackgroundDrawable(ColorDrawable(buttonColor)) } - private fun setDrawableDirection() { + private fun setDrawableDirection(isOnLeft: Boolean) { manageView.setBackgroundResource( - if (resources.configuration.layoutDirection == View.LAYOUT_DIRECTION_RTL) - R.drawable.bubble_stack_user_education_bg_rtl - else R.drawable.bubble_stack_user_education_bg) + if (isOnLeft) R.drawable.bubble_stack_user_education_bg + else R.drawable.bubble_stack_user_education_bg_rtl + ) } /** @@ -93,48 +96,31 @@ class ManageEducationView constructor(context: Context, positioner: BubblePositi * bubble stack is expanded for the first time. * * @param expandedView the expandedView the user education is shown on top of. + * @param isStackOnLeft the bubble stack position on the screen */ - fun show(expandedView: BubbleExpandedView) { + fun show(expandedView: BubbleExpandedView, isStackOnLeft: Boolean) { setButtonColor() if (visibility == VISIBLE) return bubbleExpandedView = expandedView expandedView.taskView?.setObscuredTouchRect(Rect(positioner.screenRect)) - layoutParams.width = if (positioner.isLargeScreen || positioner.isLandscape) - context.resources.getDimensionPixelSize(R.dimen.bubbles_user_education_width) - else ViewGroup.LayoutParams.MATCH_PARENT - alpha = 0f visibility = View.VISIBLE expandedView.getManageButtonBoundsOnScreen(realManageButtonRect) - val isRTL = mContext.resources.configuration.layoutDirection == LAYOUT_DIRECTION_RTL - if (isRTL) { - val rightPadding = positioner.screenRect.right - realManageButtonRect.right - - expandedView.manageButtonMargin - manageView.setPadding(manageView.paddingLeft, manageView.paddingTop, - rightPadding, manageView.paddingBottom) - } else { - manageView.setPadding(realManageButtonRect.left - expandedView.manageButtonMargin, - manageView.paddingTop, manageView.paddingRight, manageView.paddingBottom) - } + layoutManageView(realManageButtonRect, expandedView.manageButtonMargin, isStackOnLeft) + post { - manageButton - .setOnClickListener { - hide() - expandedView.requireViewById<View>(R.id.manage_button).performClick() - } + manageButton.setOnClickListener { + hide() + expandedView.requireViewById<View>(R.id.manage_button).performClick() + } gotItButton.setOnClickListener { hide() } setOnClickListener { hide() } val offsetViewBounds = Rect() manageButton.getDrawingRect(offsetViewBounds) manageView.offsetDescendantRectToMyCoords(manageButton, offsetViewBounds) - if (isRTL && (positioner.isLargeScreen || positioner.isLandscape)) { - translationX = (positioner.screenRect.right - width).toFloat() - } else { - translationX = 0f - } translationY = (realManageButtonRect.top - offsetViewBounds.top).toFloat() bringToFront() animate() @@ -145,6 +131,79 @@ class ManageEducationView constructor(context: Context, positioner: BubblePositi setShouldShow(false) } + /** + * On tablet the user education is aligned to the left or to right side depending on where the + * stack is positioned when collapsed. On phone the user education follows the layout direction. + * + * @param manageButtonRect the manage button rect on the screen + * @param manageButtonMargin the manage button margin + * @param isStackOnLeft the bubble stack position on the screen + */ + private fun layoutManageView( + manageButtonRect: Rect, + manageButtonMargin: Int, + isStackOnLeft: Boolean + ) { + val isLTR = resources.configuration.layoutDirection == LAYOUT_DIRECTION_LTR + val isPinnedLeft = if (positioner.isLargeScreen) isStackOnLeft else isLTR + val paddingHorizontal = + resources.getDimensionPixelSize(R.dimen.bubble_user_education_padding_horizontal) + + // The user education view background image direction + setDrawableDirection(isPinnedLeft) + + // The user education view layout gravity + gravity = if (isPinnedLeft) Gravity.LEFT else Gravity.RIGHT + + // The user education view width + manageView.layoutParams.width = + when { + // Left-to-Right direction and the education is on the right side + isLTR && !isPinnedLeft -> + positioner.screenRect.right - + (manageButtonRect.left - manageButtonMargin - paddingHorizontal) + // Right-to-Left direction and the education is on the left side + !isLTR && isPinnedLeft -> + manageButtonRect.right + manageButtonMargin + paddingHorizontal + // Large screen and the education position matches the layout direction + positioner.isLargeScreen -> ViewGroup.LayoutParams.WRAP_CONTENT + // Small screen, landscape orientation + positioner.isLandscape -> + resources.getDimensionPixelSize(R.dimen.bubbles_user_education_width) + // Otherwise + else -> ViewGroup.LayoutParams.MATCH_PARENT + } + + // The user education view margin on the opposite side of where it's pinned + (manageView.layoutParams as MarginLayoutParams).apply { + val edgeMargin = + resources.getDimensionPixelSize(R.dimen.bubble_user_education_margin_horizontal) + leftMargin = if (isPinnedLeft) 0 else edgeMargin + rightMargin = if (isPinnedLeft) edgeMargin else 0 + } + + // The user education view padding + manageView.apply { + val paddingLeft = + if (isLTR && isPinnedLeft) { + // Offset on the left to align with the manage button + manageButtonRect.left - manageButtonMargin + } else { + // Use default padding + paddingHorizontal + } + val paddingRight = + if (!isLTR && !isPinnedLeft) { + // Offset on the right to align with the manage button + positioner.screenRect.right - manageButtonRect.right - manageButtonMargin + } else { + // Use default padding + paddingHorizontal + } + setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom) + } + } + fun hide() { bubbleExpandedView?.taskView?.setObscuredTouchRect(null) if (visibility != VISIBLE || isHiding) return @@ -160,9 +219,12 @@ class ManageEducationView constructor(context: Context, positioner: BubblePositi } private fun setShouldShow(shouldShow: Boolean) { - context.getSharedPreferences(context.packageName, Context.MODE_PRIVATE) - .edit().putBoolean(PREF_MANAGED_EDUCATION, !shouldShow).apply() + context + .getSharedPreferences(context.packageName, Context.MODE_PRIVATE) + .edit() + .putBoolean(PREF_MANAGED_EDUCATION, !shouldShow) + .apply() } } -const val PREF_MANAGED_EDUCATION: String = "HasSeenBubblesManageOnboarding"
\ No newline at end of file +const val PREF_MANAGED_EDUCATION: String = "HasSeenBubblesManageOnboarding" diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/StackEducationView.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/StackEducationView.kt index 5e3a077a3716..2cabb65abe7a 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/StackEducationView.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/StackEducationView.kt @@ -21,7 +21,6 @@ import android.graphics.PointF import android.view.KeyEvent import android.view.LayoutInflater import android.view.View -import android.view.View.OnKeyListener import android.view.ViewGroup import android.widget.LinearLayout import android.widget.TextView @@ -30,16 +29,17 @@ import com.android.wm.shell.R import com.android.wm.shell.animation.Interpolators /** - * User education view to highlight the collapsed stack of bubbles. - * Shown only the first time a user taps the stack. + * User education view to highlight the collapsed stack of bubbles. Shown only the first time a user + * taps the stack. */ -class StackEducationView constructor( +class StackEducationView( context: Context, positioner: BubblePositioner, controller: BubbleController ) : LinearLayout(context) { - private val TAG = if (BubbleDebugConfig.TAG_WITH_CLASS_NAME) "BubbleStackEducationView" + private val TAG = + if (BubbleDebugConfig.TAG_WITH_CLASS_NAME) "BubbleStackEducationView" else BubbleDebugConfig.TAG_BUBBLES private val ANIMATE_DURATION: Long = 200 @@ -69,7 +69,7 @@ class StackEducationView constructor( override fun setLayoutDirection(layoutDirection: Int) { super.setLayoutDirection(layoutDirection) - setDrawableDirection() + setDrawableDirection(layoutDirection == LAYOUT_DIRECTION_LTR) } override fun onFinishInflate() { @@ -111,16 +111,16 @@ class StackEducationView constructor( descTextView.setTextColor(textColor) } - private fun setDrawableDirection() { + private fun setDrawableDirection(isOnLeft: Boolean) { view.setBackgroundResource( - if (resources.configuration.layoutDirection == View.LAYOUT_DIRECTION_LTR) - R.drawable.bubble_stack_user_education_bg - else R.drawable.bubble_stack_user_education_bg_rtl) + if (isOnLeft) R.drawable.bubble_stack_user_education_bg + else R.drawable.bubble_stack_user_education_bg_rtl + ) } /** - * If necessary, shows the user education view for the bubble stack. This appears the first - * time a user taps on a bubble. + * If necessary, shows the user education view for the bubble stack. This appears the first time + * a user taps on a bubble. * * @return true if user education was shown and wasn't showing before, false otherwise. */ @@ -129,29 +129,44 @@ class StackEducationView constructor( if (visibility == VISIBLE) return false controller.updateWindowFlagsForBackpress(true /* interceptBack */) - layoutParams.width = if (positioner.isLargeScreen || positioner.isLandscape) - context.resources.getDimensionPixelSize(R.dimen.bubbles_user_education_width) - else ViewGroup.LayoutParams.MATCH_PARENT + layoutParams.width = + if (positioner.isLargeScreen || positioner.isLandscape) + context.resources.getDimensionPixelSize(R.dimen.bubbles_user_education_width) + else ViewGroup.LayoutParams.MATCH_PARENT + + val isStackOnLeft = positioner.isStackOnLeft(stackPosition) + (view.layoutParams as MarginLayoutParams).apply { + // Update the horizontal margins depending on the stack position + val edgeMargin = + resources.getDimensionPixelSize(R.dimen.bubble_user_education_margin_horizontal) + leftMargin = if (isStackOnLeft) 0 else edgeMargin + rightMargin = if (isStackOnLeft) edgeMargin else 0 + } - val stackPadding = context.resources.getDimensionPixelSize( - R.dimen.bubble_user_education_stack_padding) + val stackPadding = + context.resources.getDimensionPixelSize(R.dimen.bubble_user_education_stack_padding) setAlpha(0f) setVisibility(View.VISIBLE) + setDrawableDirection(isOnLeft = isStackOnLeft) post { requestFocus() with(view) { - if (resources.configuration.layoutDirection == View.LAYOUT_DIRECTION_LTR) { - setPadding(positioner.bubbleSize + stackPadding, paddingTop, paddingRight, - paddingBottom) + if (isStackOnLeft) { + setPadding( + positioner.bubbleSize + stackPadding, + paddingTop, + paddingRight, + paddingBottom + ) + translationX = 0f } else { - setPadding(paddingLeft, paddingTop, positioner.bubbleSize + stackPadding, - paddingBottom) - if (positioner.isLargeScreen || positioner.isLandscape) { - translationX = (positioner.screenRect.right - width - stackPadding) - .toFloat() - } else { - translationX = 0f - } + setPadding( + paddingLeft, + paddingTop, + positioner.bubbleSize + stackPadding, + paddingBottom + ) + translationX = (positioner.screenRect.right - width - stackPadding).toFloat() } translationY = stackPosition.y + positioner.bubbleSize / 2 - getHeight() / 2 } @@ -168,7 +183,7 @@ class StackEducationView constructor( * If necessary, hides the stack education view. * * @param isExpanding if true this indicates the hide is happening due to the bubble being - * expanded, false if due to a touch outside of the bubble stack. + * expanded, false if due to a touch outside of the bubble stack. */ fun hide(isExpanding: Boolean) { if (visibility != VISIBLE || isHiding) return @@ -182,9 +197,12 @@ class StackEducationView constructor( } private fun setShouldShow(shouldShow: Boolean) { - context.getSharedPreferences(context.packageName, Context.MODE_PRIVATE) - .edit().putBoolean(PREF_STACK_EDUCATION, !shouldShow).apply() + context + .getSharedPreferences(context.packageName, Context.MODE_PRIVATE) + .edit() + .putBoolean(PREF_STACK_EDUCATION, !shouldShow) + .apply() } } -const val PREF_STACK_EDUCATION: String = "HasSeenBubblesOnboarding"
\ No newline at end of file +const val PREF_STACK_EDUCATION: String = "HasSeenBubblesOnboarding" |