Add focus outline to overview clear all button
Use the same class BorderAnimator in TaskView to draw focus outline with padding between button and outline as UX design
Bug: 324911125
Test: Manual, launcher overview, use keyboard left arrow to show clear all button, outline should be shown
Flag: LEGACY ENABLE_KEYBOARD_QUICK_SWITCH ENABLED
Change-Id: I62ac2ce7a8f62170421b4318c9fa58805384187b
diff --git a/quickstep/res/drawable/bg_overview_clear_all_button.xml b/quickstep/res/drawable/bg_overview_clear_all_button.xml
index f3ff6ce..143761f 100644
--- a/quickstep/res/drawable/bg_overview_clear_all_button.xml
+++ b/quickstep/res/drawable/bg_overview_clear_all_button.xml
@@ -20,7 +20,7 @@
<item>
<shape android:shape="rectangle"
android:tint="?colorButtonNormal">
- <corners android:radius="24dp" />
+ <corners android:radius="@dimen/recents_clear_all_outline_radius" />
<solid android:color="?androidprv:attr/materialColorSurfaceBright"/>
</shape>
</item>
diff --git a/quickstep/res/layout/overview_clear_all_button.xml b/quickstep/res/layout/overview_clear_all_button.xml
index da94c3a..3380ea4 100644
--- a/quickstep/res/layout/overview_clear_all_button.xml
+++ b/quickstep/res/layout/overview_clear_all_button.xml
@@ -17,10 +17,12 @@
<com.android.quickstep.views.ClearAllButton
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ xmlns:launcher="http://schemas.android.com/apk/res-auto"
style="@style/OverviewClearAllButton"
android:id="@+id/clear_all"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/recents_clear_all"
android:textColor="?androidprv:attr/materialColorOnSurface"
+ launcher:focusBorderColor="?androidprv:attr/materialColorOutline"
android:textSize="14sp" />
\ No newline at end of file
diff --git a/quickstep/res/values/attrs.xml b/quickstep/res/values/attrs.xml
index 7288774..ccc7f18 100644
--- a/quickstep/res/values/attrs.xml
+++ b/quickstep/res/values/attrs.xml
@@ -30,6 +30,11 @@
<attr name="hoverBorderColor" format="color" />
</declare-styleable>
+ <declare-styleable name="ClearAllButton">
+ <!-- focus border color for overview clear all button views -->
+ <attr name="focusBorderColor" />
+ </declare-styleable>
+
<!--
Gesture nav edu specific attributes. These attributes are used to customize Gesture nav edu
view lottie animation colors in XML files.
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 93ef735..25eb2ba 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -98,6 +98,8 @@
<dimen name="default_task_dismiss_drag_velocity_grid_focus_task">5dp</dimen>
<dimen name="recents_clear_all_deadzone_vertical_margin">70dp</dimen>
+ <dimen name="recents_clear_all_outline_radius">24dp</dimen>
+ <dimen name="recents_clear_all_outline_padding">2dp</dimen>
<!-- The speed in dp/s at which the user needs to be scrolling in recents such that we start
loading full resolution screenshots. -->
diff --git a/quickstep/src/com/android/quickstep/views/ClearAllButton.java b/quickstep/src/com/android/quickstep/views/ClearAllButton.java
index 32ef904..acda2e1 100644
--- a/quickstep/src/com/android/quickstep/views/ClearAllButton.java
+++ b/quickstep/src/com/android/quickstep/views/ClearAllButton.java
@@ -17,15 +17,28 @@
package com.android.quickstep.views;
import static com.android.launcher3.Flags.enableGridOnlyOverview;
+import static com.android.quickstep.util.BorderAnimator.DEFAULT_BORDER_COLOR;
import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.FloatProperty;
import android.widget.Button;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Flags;
+import com.android.launcher3.R;
import com.android.launcher3.statemanager.StatefulActivity;
import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
+import com.android.quickstep.util.BorderAnimator;
+
+import kotlin.Unit;
public class ClearAllButton extends Button {
@@ -71,11 +84,71 @@
private float mScrollOffsetPrimary;
private int mSidePadding;
+ private int mOutlinePadding;
+ private boolean mBorderEnabled;
+ @Nullable
+ private final BorderAnimator mFocusBorderAnimator;
public ClearAllButton(Context context, AttributeSet attrs) {
super(context, attrs);
mIsRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
mActivity = StatefulActivity.fromContext(context);
+
+ if (Flags.enableFocusOutline()) {
+ TypedArray styledAttrs = context.obtainStyledAttributes(attrs,
+ R.styleable.ClearAllButton);
+ Resources resources = getResources();
+ mOutlinePadding = resources.getDimensionPixelSize(
+ R.dimen.recents_clear_all_outline_padding);
+ mFocusBorderAnimator =
+ BorderAnimator.createSimpleBorderAnimator(
+ /* borderRadiusPx= */ resources.getDimensionPixelSize(
+ R.dimen.recents_clear_all_outline_radius),
+ /* borderWidthPx= */ context.getResources().getDimensionPixelSize(
+ R.dimen.keyboard_quick_switch_border_width),
+ /* boundsBuilder= */ this::updateBorderBounds,
+ /* targetView= */ this,
+ /* borderColor= */ styledAttrs.getColor(
+ R.styleable.ClearAllButton_focusBorderColor,
+ DEFAULT_BORDER_COLOR));
+ styledAttrs.recycle();
+ } else {
+ mFocusBorderAnimator = null;
+ }
+ }
+
+ private Unit updateBorderBounds(@NonNull Rect bounds) {
+ bounds.set(0, 0, getWidth(), getHeight());
+ // Make the value negative to form a padding between button and outline
+ bounds.inset(-mOutlinePadding, -mOutlinePadding);
+ return Unit.INSTANCE;
+ }
+
+ @Override
+ public void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
+ super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
+ if (mFocusBorderAnimator != null && mBorderEnabled) {
+ mFocusBorderAnimator.setBorderVisibility(gainFocus, /* animated= */ true);
+ }
+ }
+
+ /**
+ * Enable or disable showing border on focus change
+ */
+ public void setBorderEnabled(boolean enabled) {
+ mBorderEnabled = enabled;
+ if (mFocusBorderAnimator != null) {
+ mFocusBorderAnimator.setBorderVisibility(/* visible= */
+ enabled && isFocused(), /* animated= */true);
+ }
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ if (mFocusBorderAnimator != null) {
+ mFocusBorderAnimator.drawBorder(canvas);
+ }
+ super.draw(canvas);
}
@Override
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 2aa16a9..cce3fe4 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -1445,6 +1445,7 @@
TaskView taskView = requireTaskViewAt(i);
taskView.setBorderEnabled(enabled);
}
+ mClearAllButton.setBorderEnabled(enabled);
}
/**
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index abd4ec4..6cbdc97 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -425,7 +425,8 @@
mCurrentFullscreenParams = new FullscreenDrawParams(context);
mDigitalWellBeingToast = new DigitalWellBeingToast(mActivity, this);
- boolean keyboardFocusHighlightEnabled = FeatureFlags.ENABLE_KEYBOARD_QUICK_SWITCH.get();
+ boolean keyboardFocusHighlightEnabled = FeatureFlags.ENABLE_KEYBOARD_QUICK_SWITCH.get()
+ || Flags.enableFocusOutline();
boolean cursorHoverStatesEnabled = enableCursorHoverStates();
setWillNotDraw(!keyboardFocusHighlightEnabled && !cursorHoverStatesEnabled);