Merge changes I60f2bedb,Ie0e3647b,I1c77a810 into sc-v2-dev

* changes:
  Fix up back press with bubbles manage menu or user education
  Fix touches activating TaskView when showing user education
  Updates to user education for large screen
This commit is contained in:
Mady Mellor
2021-08-10 17:28:17 +00:00
committed by Android (Google) Code Review
11 changed files with 165 additions and 87 deletions

View File

@@ -17,7 +17,7 @@
<com.android.wm.shell.common.AlphaOptimizedButton
xmlns:android="http://schemas.android.com/apk/res/android"
style="@android:style/Widget.DeviceDefault.Button.Borderless"
android:id="@+id/settings_button"
android:id="@+id/manage_button"
android:layout_gravity="start"
android:layout_width="wrap_content"
android:layout_height="@dimen/bubble_manage_button_height"

View File

@@ -21,7 +21,6 @@
android:layout_width="wrap_content"
android:paddingTop="48dp"
android:paddingBottom="48dp"
android:paddingStart="@dimen/bubble_stack_user_education_side_inset"
android:paddingEnd="16dp"
android:layout_marginEnd="24dp"
android:orientation="vertical"

View File

@@ -23,7 +23,6 @@
android:clickable="true"
android:paddingTop="28dp"
android:paddingBottom="16dp"
android:paddingStart="@dimen/bubble_expanded_view_padding"
android:paddingEnd="48dp"
android:layout_marginEnd="24dp"
android:orientation="vertical"
@@ -66,27 +65,21 @@
android:id="@+id/button_layout"
android:orientation="horizontal" >
<com.android.wm.shell.common.AlphaOptimizedButton
style="@android:style/Widget.Material.Button.Borderless"
android:id="@+id/manage"
android:layout_gravity="start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:focusable="true"
android:clickable="false"
android:text="@string/manage_bubbles_text"
android:textColor="@android:color/system_neutral1_900"
<include
layout="@layout/bubble_manage_button"
/>
<com.android.wm.shell.common.AlphaOptimizedButton
style="@android:style/Widget.Material.Button.Borderless"
style="@android:style/Widget.DeviceDefault.Button.Borderless"
android:id="@+id/got_it"
android:layout_gravity="start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_height="@dimen/bubble_manage_button_height"
android:focusable="true"
android:text="@string/bubbles_user_education_got_it"
android:textSize="@*android:dimen/text_size_body_2_material"
android:textColor="@android:color/system_neutral1_900"
android:background="@drawable/bubble_manage_btn_bg"
/>
</LinearLayout>
</LinearLayout>

View File

@@ -184,14 +184,8 @@
<dimen name="bubble_dismiss_target_padding_x">40dp</dimen>
<dimen name="bubble_dismiss_target_padding_y">20dp</dimen>
<dimen name="bubble_manage_menu_elevation">4dp</dimen>
<!-- Bubbles user education views -->
<dimen name="bubbles_manage_education_width">160dp</dimen>
<!-- The inset from the top bound of the manage button to place the user education. -->
<dimen name="bubbles_manage_education_top_inset">65dp</dimen>
<!-- Size of padding for the user education cling, this should at minimum be larger than
individual_bubble_size + some padding. -->
<dimen name="bubble_stack_user_education_side_inset">72dp</dimen>
<!-- Size of user education views on large screens (phone is just match parent). -->
<dimen name="bubbles_user_education_width_large_screen">400dp</dimen>
<!-- The width/height of the size compat restart button. -->
<dimen name="size_compat_button_size">48dp</dimen>

View File

@@ -636,10 +636,16 @@ public class BubbleController {
}
}
/** For the overflow to be focusable & receive key events the flags must be update. **/
void updateWindowFlagsForOverflow(boolean showingOverflow) {
/**
* In some situations bubble's should be able to receive key events for back:
* - when the bubble overflow is showing
* - when the user education for the stack is showing.
*
* @param interceptBack whether back should be intercepted or not.
*/
void updateWindowFlagsForBackpress(boolean interceptBack) {
if (mStackView != null && mAddedToWindowManager) {
mWmLayoutParams.flags = showingOverflow
mWmLayoutParams.flags = interceptBack
? 0
: WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;

View File

@@ -228,7 +228,7 @@ public class BubbleExpandedView extends LinearLayout {
@Override
public void onBackPressedOnTaskRoot(int taskId) {
if (mTaskId == taskId && mStackView.isExpanded()) {
mController.collapseStack();
mStackView.onBackPressed();
}
}
};

View File

@@ -142,7 +142,7 @@ public class BubbleOverflowContainerView extends LinearLayout {
super.onAttachedToWindow();
if (mController != null) {
// For the overflow to get key events (e.g. back press) we need to adjust the flags
mController.updateWindowFlagsForOverflow(true);
mController.updateWindowFlagsForBackpress(true);
}
setOnKeyListener(mKeyListener);
}
@@ -151,7 +151,7 @@ public class BubbleOverflowContainerView extends LinearLayout {
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (mController != null) {
mController.updateWindowFlagsForOverflow(false);
mController.updateWindowFlagsForBackpress(false);
}
setOnKeyListener(null);
}

View File

@@ -241,6 +241,13 @@ public class BubblePositioner {
return mPositionRect;
}
/**
* @return a rect of the screen size.
*/
public Rect getScreenRect() {
return mScreenRect;
}
/**
* @return the relevant insets (status bar, nav bar, cutouts). If taskbar is showing, its
* inset is not included here.

View File

@@ -110,9 +110,6 @@ public class BubbleStackView extends FrameLayout
private static final int FADE_IN_DURATION = 320;
/** Percent to darken the bubbles when they're in the dismiss target. */
private static final float DARKEN_PERCENT = 0.3f;
/** How long to wait, in milliseconds, before hiding the flyout. */
@VisibleForTesting
static final int FLYOUT_HIDE_AFTER = 5000;
@@ -559,7 +556,7 @@ public class BubbleStackView extends FrameLayout
if (mBubbleData.isExpanded()) {
if (mManageEduView != null) {
mManageEduView.hide(false /* show */);
mManageEduView.hide();
}
// If we're expanded, tell the animation controller to prepare to drag this bubble,
@@ -797,8 +794,6 @@ public class BubbleStackView extends FrameLayout
mBubbleContainer.setClipChildren(false);
addView(mBubbleContainer, new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
updateUserEdu();
mExpandedViewContainer = new FrameLayout(context);
mExpandedViewContainer.setElevation(elevation);
mExpandedViewContainer.setClipChildren(false);
@@ -932,8 +927,10 @@ public class BubbleStackView extends FrameLayout
setOnClickListener(view -> {
if (mShowingManage) {
showManageMenu(false /* show */);
} else if (mManageEduView != null && mManageEduView.getVisibility() == VISIBLE) {
mManageEduView.hide();
} else if (mStackEduView != null && mStackEduView.getVisibility() == VISIBLE) {
mStackEduView.hide(false);
mStackEduView.hide(false /* isExpanding */);
} else if (mBubbleData.isExpanded()) {
mBubbleData.setExpanded(false);
}
@@ -1132,10 +1129,10 @@ public class BubbleStackView extends FrameLayout
return;
}
if (mManageEduView == null) {
mManageEduView = new ManageEducationView(mContext);
mManageEduView = new ManageEducationView(mContext, mPositioner);
addView(mManageEduView);
}
mManageEduView.show(mExpandedBubble.getExpandedView(), mTempRect);
mManageEduView.show(mExpandedBubble.getExpandedView());
}
/**
@@ -1163,21 +1160,27 @@ public class BubbleStackView extends FrameLayout
return false;
}
if (mStackEduView == null) {
mStackEduView = new StackEducationView(mContext);
mStackEduView = new StackEducationView(mContext, mPositioner, mBubbleController);
addView(mStackEduView);
}
mBubbleContainer.bringToFront();
return mStackEduView.show(mPositioner.getDefaultStartPosition());
}
// Recreates & shows the education views. Call when a theme/config change happens.
private void updateUserEdu() {
maybeShowStackEdu();
if (mManageEduView != null) {
mManageEduView.invalidate();
if (mStackEduView != null && mStackEduView.getVisibility() == VISIBLE) {
removeView(mStackEduView);
mStackEduView = new StackEducationView(mContext, mPositioner, mBubbleController);
addView(mStackEduView);
mBubbleContainer.bringToFront(); // Stack appears on top of the stack education
mStackEduView.show(mPositioner.getDefaultStartPosition());
}
maybeShowManageEdu();
if (mStackEduView != null) {
mStackEduView.invalidate();
if (mManageEduView != null && mManageEduView.getVisibility() == VISIBLE) {
removeView(mManageEduView);
mManageEduView = new ManageEducationView(mContext, mPositioner);
addView(mManageEduView);
mManageEduView.show(mExpandedBubble.getExpandedView());
}
}
@@ -1274,6 +1277,7 @@ public class BubbleStackView extends FrameLayout
setUpManageMenu();
setUpFlyout();
setUpDismissView();
updateUserEdu();
mBubbleSize = mPositioner.getBubbleSize();
for (Bubble b : mBubbleData.getBubbles()) {
if (b.getIconView() == null) {
@@ -1730,6 +1734,21 @@ public class BubbleStackView extends FrameLayout
notifyExpansionChanged(mExpandedBubble, mIsExpanded);
}
/**
* Called when back press occurs while bubbles are expanded.
*/
public void onBackPressed() {
if (mIsExpanded) {
if (mShowingManage) {
showManageMenu(false);
} else if (mManageEduView != null && mManageEduView.getVisibility() == VISIBLE) {
mManageEduView.hide();
} else {
setExpanded(false);
}
}
}
void setBubbleVisibility(Bubble b, boolean visible) {
if (b.getIconView() != null) {
b.getIconView().setVisibility(visible ? VISIBLE : GONE);
@@ -1955,6 +1974,9 @@ public class BubbleStackView extends FrameLayout
private void animateCollapse() {
cancelDelayedExpandCollapseSwitchAnimations();
if (mManageEduView != null && mManageEduView.getVisibility() == VISIBLE) {
mManageEduView.hide();
}
// Hide the menu if it's visible.
showManageMenu(false);
@@ -2032,7 +2054,7 @@ public class BubbleStackView extends FrameLayout
final BubbleViewProvider previouslySelected = mExpandedBubble;
beforeExpandedViewAnimation();
if (mManageEduView != null) {
mManageEduView.hide(false /* fromExpansion */);
mManageEduView.hide();
}
if (DEBUG_BUBBLE_STACK_VIEW) {

View File

@@ -18,12 +18,13 @@ package com.android.wm.shell.bubbles
import android.content.Context
import android.graphics.Color
import android.graphics.Rect
import android.graphics.drawable.ColorDrawable
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.LinearLayout
import android.widget.TextView
import com.android.internal.util.ContrastColorUtil
import com.android.internal.R.color.system_neutral1_900
import com.android.wm.shell.R
import com.android.wm.shell.animation.Interpolators
@@ -31,21 +32,22 @@ 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) : LinearLayout(context) {
class ManageEducationView constructor(context: Context, positioner: BubblePositioner)
: LinearLayout(context) {
private val TAG = if (BubbleDebugConfig.TAG_WITH_CLASS_NAME) "BubbleManageEducationView"
private val TAG = if (BubbleDebugConfig.TAG_WITH_CLASS_NAME) "ManageEducationView"
else BubbleDebugConfig.TAG_BUBBLES
private val ANIMATE_DURATION: Long = 200
private val ANIMATE_DURATION_SHORT: Long = 40
private val manageView by lazy { findViewById<View>(R.id.manage_education_view) }
private val manageButton by lazy { findViewById<Button>(R.id.manage) }
private val positioner: BubblePositioner = positioner
private val manageView by lazy { findViewById<ViewGroup>(R.id.manage_education_view) }
private val manageButton by lazy { findViewById<Button>(R.id.manage_button) }
private val gotItButton by lazy { findViewById<Button>(R.id.got_it) }
private val titleTextView by lazy { findViewById<TextView>(R.id.user_education_title) }
private val descTextView by lazy { findViewById<TextView>(R.id.user_education_description) }
private var isHiding = false
private var realManageButtonRect = Rect()
private var bubbleExpandedView: BubbleExpandedView? = null
init {
LayoutInflater.from(context).inflate(R.layout.bubbles_manage_button_education, this)
@@ -66,18 +68,17 @@ class ManageEducationView constructor(context: Context) : LinearLayout(context)
override fun onFinishInflate() {
super.onFinishInflate()
layoutDirection = resources.configuration.layoutDirection
setTextColor()
}
private fun setTextColor() {
val typedArray = mContext.obtainStyledAttributes(intArrayOf(android.R.attr.colorAccent,
android.R.attr.textColorPrimaryInverse))
val bgColor = typedArray.getColor(0 /* index */, Color.BLACK)
var textColor = typedArray.getColor(1 /* index */, Color.WHITE)
private fun setButtonColor() {
val typedArray = mContext.obtainStyledAttributes(intArrayOf(
com.android.internal.R.attr.colorAccentPrimary))
val buttonColor = typedArray.getColor(0 /* index */, Color.TRANSPARENT)
typedArray.recycle()
textColor = ContrastColorUtil.ensureTextContrast(textColor, bgColor, true)
titleTextView.setTextColor(textColor)
descTextView.setTextColor(textColor)
manageButton.setTextColor(mContext.getColor(system_neutral1_900))
manageButton.setBackgroundDrawable(ColorDrawable(buttonColor))
gotItButton.setBackgroundDrawable(ColorDrawable(buttonColor))
}
private fun setDrawableDirection() {
@@ -91,30 +92,39 @@ class ManageEducationView constructor(context: Context) : LinearLayout(context)
* If necessary, toggles the user education view for the manage button. This is shown when the
* bubble stack is expanded for the first time.
*
* @param show whether the user education view should show or not.
* @param expandedView the expandedView the user education is shown on top of.
*/
fun show(expandedView: BubbleExpandedView, rect: Rect) {
fun show(expandedView: BubbleExpandedView) {
setButtonColor()
if (visibility == VISIBLE) return
bubbleExpandedView = expandedView
expandedView.taskView?.setObscuredTouchRect(Rect(positioner.screenRect))
layoutParams.width = if (positioner.isLargeScreen)
context.resources.getDimensionPixelSize(
R.dimen.bubbles_user_education_width_large_screen)
else ViewGroup.LayoutParams.MATCH_PARENT
alpha = 0f
visibility = View.VISIBLE
expandedView.getManageButtonBoundsOnScreen(realManageButtonRect)
manageView.setPadding(realManageButtonRect.left - expandedView.manageButtonMargin,
manageView.paddingTop, manageView.paddingRight, manageView.paddingBottom)
post {
expandedView.getManageButtonBoundsOnScreen(rect)
manageButton
.setOnClickListener {
expandedView.findViewById<View>(R.id.settings_button).performClick()
hide(true /* isStackExpanding */)
hide()
expandedView.findViewById<View>(R.id.manage_button).performClick()
}
gotItButton.setOnClickListener { hide(true /* isStackExpanding */) }
setOnClickListener { hide(true /* isStackExpanding */) }
gotItButton.setOnClickListener { hide() }
setOnClickListener { hide() }
with(manageView) {
translationX = 0f
val inset = resources.getDimensionPixelSize(
R.dimen.bubbles_manage_education_top_inset)
translationY = (rect.top - manageView.height + inset).toFloat()
}
val offsetViewBounds = Rect()
manageButton.getDrawingRect(offsetViewBounds)
manageView.offsetDescendantRectToMyCoords(manageButton, offsetViewBounds)
translationX = 0f
translationY = (realManageButtonRect.top - offsetViewBounds.top).toFloat()
bringToFront()
animate()
.setDuration(ANIMATE_DURATION)
@@ -124,13 +134,14 @@ class ManageEducationView constructor(context: Context) : LinearLayout(context)
setShouldShow(false)
}
fun hide(isStackExpanding: Boolean) {
fun hide() {
bubbleExpandedView?.taskView?.setObscuredTouchRect(null)
if (visibility != VISIBLE || isHiding) return
animate()
.withStartAction { isHiding = true }
.alpha(0f)
.setDuration(if (isStackExpanding) ANIMATE_DURATION_SHORT else ANIMATE_DURATION)
.setDuration(ANIMATE_DURATION)
.withEndAction {
isHiding = false
visibility = GONE

View File

@@ -18,8 +18,11 @@ package com.android.wm.shell.bubbles
import android.content.Context
import android.graphics.Color
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
import com.android.internal.util.ContrastColorUtil
@@ -30,7 +33,12 @@ 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.
*/
class StackEducationView constructor(context: Context) : LinearLayout(context) {
class StackEducationView constructor(
context: Context,
positioner: BubblePositioner,
controller: BubbleController
)
: LinearLayout(context) {
private val TAG = if (BubbleDebugConfig.TAG_WITH_CLASS_NAME) "BubbleStackEducationView"
else BubbleDebugConfig.TAG_BUBBLES
@@ -38,6 +46,9 @@ class StackEducationView constructor(context: Context) : LinearLayout(context) {
private val ANIMATE_DURATION: Long = 200
private val ANIMATE_DURATION_SHORT: Long = 40
private val positioner: BubblePositioner = positioner
private val controller: BubbleController = controller
private val view by lazy { findViewById<View>(R.id.stack_education_layout) }
private val titleTextView by lazy { findViewById<TextView>(R.id.stack_education_title) }
private val descTextView by lazy { findViewById<TextView>(R.id.stack_education_description) }
@@ -67,6 +78,28 @@ class StackEducationView constructor(context: Context) : LinearLayout(context) {
setTextColor()
}
override fun onAttachedToWindow() {
super.onAttachedToWindow()
setFocusableInTouchMode(true)
setOnKeyListener(object : OnKeyListener {
override fun onKey(v: View?, keyCode: Int, event: KeyEvent): Boolean {
// if the event is a key down event on the enter button
if (event.action == KeyEvent.ACTION_UP &&
keyCode == KeyEvent.KEYCODE_BACK && !isHiding) {
hide(false)
return true
}
return false
}
})
}
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
setOnKeyListener(null)
controller.updateWindowFlagsForBackpress(false /* interceptBack */)
}
private fun setTextColor() {
val ta = mContext.obtainStyledAttributes(intArrayOf(android.R.attr.colorAccent,
android.R.attr.textColorPrimaryInverse))
@@ -94,13 +127,25 @@ class StackEducationView constructor(context: Context) : LinearLayout(context) {
fun show(stackPosition: PointF): Boolean {
if (visibility == VISIBLE) return false
controller.updateWindowFlagsForBackpress(true /* interceptBack */)
layoutParams.width = if (positioner.isLargeScreen)
context.resources.getDimensionPixelSize(
R.dimen.bubbles_user_education_width_large_screen)
else ViewGroup.LayoutParams.MATCH_PARENT
setAlpha(0f)
setVisibility(View.VISIBLE)
post {
requestFocus()
with(view) {
val bubbleSize = context.resources.getDimensionPixelSize(
R.dimen.bubble_size)
translationY = stackPosition.y + bubbleSize / 2 - getHeight() / 2
if (resources.configuration.layoutDirection == View.LAYOUT_DIRECTION_LTR) {
setPadding(positioner.bubbleSize + paddingRight, paddingTop, paddingRight,
paddingBottom)
} else {
setPadding(paddingLeft, paddingTop, positioner.bubbleSize + paddingLeft,
paddingBottom)
}
translationY = stackPosition.y + positioner.bubbleSize / 2 - getHeight() / 2
}
animate()
.setDuration(ANIMATE_DURATION)
@@ -114,15 +159,16 @@ class StackEducationView constructor(context: Context) : LinearLayout(context) {
/**
* If necessary, hides the stack education view.
*
* @param fromExpansion if true this indicates the hide is happening due to the bubble being
* @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.
*/
fun hide(fromExpansion: Boolean) {
fun hide(isExpanding: Boolean) {
if (visibility != VISIBLE || isHiding) return
controller.updateWindowFlagsForBackpress(false /* interceptBack */)
animate()
.alpha(0f)
.setDuration(if (fromExpansion) ANIMATE_DURATION_SHORT else ANIMATE_DURATION)
.setDuration(if (isExpanding) ANIMATE_DURATION_SHORT else ANIMATE_DURATION)
.withEndAction { visibility = GONE }
}