diff options
author | 2024-10-10 21:41:22 -0700 | |
---|---|---|
committer | 2024-10-14 15:51:12 -0700 | |
commit | 66c6c352139fbfcf89951ea4d8e93b92d07609ca (patch) | |
tree | 275bb35aea838bbc9c3a3c825c5b071b1c0aaf43 | |
parent | 33867d44db91247f2d5742f011574c651fe42e88 (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.xml | 7 | ||||
-rw-r--r-- | java/res/values-sw600dp/dimens.xml | 1 | ||||
-rw-r--r-- | java/res/values/attrs.xml | 7 | ||||
-rw-r--r-- | java/res/values/dimens.xml | 2 | ||||
-rw-r--r-- | java/src/com/android/intentresolver/widget/ChooserTargetItemView.kt | 70 |
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, + ) + } } |