From 66c6c352139fbfcf89951ea4d8e93b92d07609ca Mon Sep 17 00:00:00 2001 From: Andrey Yepin Date: Thu, 10 Oct 2024 21:41:22 -0700 Subject: 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 --- java/res/layout/chooser_grid_item_hover.xml | 7 ++- java/res/values-sw600dp/dimens.xml | 1 + java/res/values/attrs.xml | 7 +++ java/res/values/dimens.xml | 2 + .../intentresolver/widget/ChooserTargetItemView.kt | 70 +++++++++++++++++++++- 5 files changed, 85 insertions(+), 2 deletions(-) (limited to 'java') 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 @@ + 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"> 624dp 250dp + 16dp 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 @@ + + + + + + + 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 @@ 18sp 12sp 12sp + 11dp + 2dp 32dp 0dp 18dp 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, + ) + } } -- cgit v1.2.3-59-g8ed1b