summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Andrey Yepin <ayepin@google.com> 2024-10-10 21:41:22 -0700
committer Andrey Yepin <ayepin@google.com> 2024-10-14 15:51:12 -0700
commit66c6c352139fbfcf89951ea4d8e93b92d07609ca (patch)
tree275bb35aea838bbc9c3a3c825c5b071b1c0aaf43
parent33867d44db91247f2d5742f011574c651fe42e88 (diff)
Add keboard focus outline for Chooser targets
This change applies the same focus outline as Launcher but the end result still needs more polishing. Some noticeable issues are: * the outline may overlap with a long label; * targets with a one-line labels look adjusted to the top and not centered; * with the light system ui theme, the outer online frame is barely visible compare to the inner outline (this is also true for Launcher). Bug: 295175912 Test: visual effect testing Flag: com.android.intentresolver.target_hover_and_keyboard_focus_states Change-Id: I1d22b187e0cc4b95c385d4f5b956effa31fd4505
-rw-r--r--java/res/layout/chooser_grid_item_hover.xml7
-rw-r--r--java/res/values-sw600dp/dimens.xml1
-rw-r--r--java/res/values/attrs.xml7
-rw-r--r--java/res/values/dimens.xml2
-rw-r--r--java/src/com/android/intentresolver/widget/ChooserTargetItemView.kt70
5 files changed, 85 insertions, 2 deletions
diff --git a/java/res/layout/chooser_grid_item_hover.xml b/java/res/layout/chooser_grid_item_hover.xml
index f4396ec6..05206065 100644
--- a/java/res/layout/chooser_grid_item_hover.xml
+++ b/java/res/layout/chooser_grid_item_hover.xml
@@ -19,6 +19,7 @@
<com.android.intentresolver.widget.ChooserTargetItemView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@androidprv:id/item"
android:orientation="vertical"
android:layout_width="match_parent"
@@ -28,7 +29,11 @@
android:paddingVertical="1dp"
android:paddingHorizontal="4dp"
android:focusable="true"
- android:background="?android:attr/selectableItemBackgroundBorderless">
+ android:defaultFocusHighlightEnabled="false"
+ app:focusOutlineWidth="@dimen/chooser_item_focus_outline_width"
+ app:focusOutlineCornerRadius="@dimen/chooser_item_focus_outline_corner_radius"
+ app:focusOutlineColor="?androidprv:attr/materialColorSecondaryFixed"
+ app:focusInnerOutlineColor="?androidprv:attr/materialColorOnSecondaryFixedVariant">
<ImageView android:id="@android:id/icon"
android:layout_width="@dimen/chooser_icon_width_with_padding"
diff --git a/java/res/values-sw600dp/dimens.xml b/java/res/values-sw600dp/dimens.xml
index 240ee067..e152ba06 100644
--- a/java/res/values-sw600dp/dimens.xml
+++ b/java/res/values-sw600dp/dimens.xml
@@ -20,4 +20,5 @@
<resources>
<dimen name="chooser_width">624dp</dimen>
<dimen name="modify_share_text_toggle_max_width">250dp</dimen>
+ <dimen name="chooser_item_focus_outline_corner_radius">16dp</dimen>
</resources>
diff --git a/java/res/values/attrs.xml b/java/res/values/attrs.xml
index c9f2c300..8c3ff7e2 100644
--- a/java/res/values/attrs.xml
+++ b/java/res/values/attrs.xml
@@ -56,4 +56,11 @@
<attr name="itemOuterSpacing" format="dimension" />
<attr name="maxWidthHint" format="dimension" />
</declare-styleable>
+
+ <declare-styleable name="ChooserTargetItemView">
+ <attr name="focusOutlineColor" format="color" />
+ <attr name="focusInnerOutlineColor" format="color" />
+ <attr name="focusOutlineWidth" format="dimension" />
+ <attr name="focusOutlineCornerRadius" format="dimension" />
+ </declare-styleable>
</resources>
diff --git a/java/res/values/dimens.xml b/java/res/values/dimens.xml
index f85ad069..515343b6 100644
--- a/java/res/values/dimens.xml
+++ b/java/res/values/dimens.xml
@@ -41,6 +41,8 @@
<dimen name="chooser_headline_text_size">18sp</dimen>
<dimen name="chooser_grid_target_name_text_size">12sp</dimen>
<dimen name="chooser_grid_activity_name_text_size">12sp</dimen>
+ <dimen name="chooser_item_focus_outline_corner_radius">11dp</dimen>
+ <dimen name="chooser_item_focus_outline_width">2dp</dimen>
<dimen name="resolver_icon_size">32dp</dimen>
<dimen name="resolver_button_bar_spacing">0dp</dimen>
<dimen name="resolver_badge_size">18dp</dimen>
diff --git a/java/src/com/android/intentresolver/widget/ChooserTargetItemView.kt b/java/src/com/android/intentresolver/widget/ChooserTargetItemView.kt
index 28934495..b5a4d617 100644
--- a/java/src/com/android/intentresolver/widget/ChooserTargetItemView.kt
+++ b/java/src/com/android/intentresolver/widget/ChooserTargetItemView.kt
@@ -17,11 +17,16 @@
package com.android.intentresolver.widget
import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.Paint
import android.util.AttributeSet
+import android.util.TypedValue
import android.view.MotionEvent
import android.view.View
import android.widget.ImageView
import android.widget.LinearLayout
+import com.android.intentresolver.R
class ChooserTargetItemView(
context: Context,
@@ -29,6 +34,14 @@ class ChooserTargetItemView(
defStyleAttr: Int,
defStyleRes: Int,
) : LinearLayout(context, attrs, defStyleAttr, defStyleRes) {
+ private val outlineRadius: Float
+ private val outlineWidth: Float
+ private val outlinePaint: Paint =
+ Paint(Paint.ANTI_ALIAS_FLAG).apply { style = Paint.Style.STROKE }
+ private val outlineInnerPaint: Paint =
+ Paint(Paint.ANTI_ALIAS_FLAG).apply { style = Paint.Style.STROKE }
+ private var iconView: ImageView? = null
+
constructor(context: Context) : this(context, null)
constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
@@ -39,7 +52,28 @@ class ChooserTargetItemView(
defStyleAttr: Int,
) : this(context, attrs, defStyleAttr, 0)
- private var iconView: ImageView? = null
+ init {
+ val a = context.obtainStyledAttributes(attrs, R.styleable.ChooserTargetItemView)
+ val defaultWidth =
+ TypedValue.applyDimension(
+ TypedValue.COMPLEX_UNIT_DIP,
+ 2f,
+ context.resources.displayMetrics,
+ )
+ outlineRadius =
+ a.getDimension(R.styleable.ChooserTargetItemView_focusOutlineCornerRadius, 0f)
+ outlineWidth =
+ a.getDimension(R.styleable.ChooserTargetItemView_focusOutlineWidth, defaultWidth)
+
+ outlinePaint.strokeWidth = outlineWidth
+ outlinePaint.color =
+ a.getColor(R.styleable.ChooserTargetItemView_focusOutlineColor, Color.TRANSPARENT)
+
+ outlineInnerPaint.strokeWidth = outlineWidth
+ outlineInnerPaint.color =
+ a.getColor(R.styleable.ChooserTargetItemView_focusInnerOutlineColor, Color.TRANSPARENT)
+ a.recycle()
+ }
override fun onViewAdded(child: View) {
super.onViewAdded(child)
@@ -70,4 +104,38 @@ class ChooserTargetItemView(
}
override fun onInterceptHoverEvent(event: MotionEvent?) = true
+
+ override fun dispatchDraw(canvas: Canvas) {
+ super.dispatchDraw(canvas)
+ if (isFocused) {
+ drawFocusInnerOutline(canvas)
+ drawFocusOutline(canvas)
+ }
+ }
+
+ private fun drawFocusInnerOutline(canvas: Canvas) {
+ val outlineOffset = outlineWidth + outlineWidth / 2
+ canvas.drawRoundRect(
+ outlineOffset,
+ outlineOffset,
+ maxOf(0f, width - outlineOffset),
+ maxOf(0f, height - outlineOffset),
+ outlineRadius - outlineWidth,
+ outlineRadius - outlineWidth,
+ outlineInnerPaint,
+ )
+ }
+
+ private fun drawFocusOutline(canvas: Canvas) {
+ val outlineOffset = outlineWidth / 2
+ canvas.drawRoundRect(
+ outlineOffset,
+ outlineOffset,
+ maxOf(0f, width - outlineOffset),
+ maxOf(0f, height - outlineOffset),
+ outlineRadius,
+ outlineRadius,
+ outlinePaint,
+ )
+ }
}