Use larger frame of settings button for clicks

That way, the tappable area is of the minimum size. Additionally, set
the accessibility class name of the SettingsButton (now an ImageView) to
be Button, so the description matches the other buttons in the
FooterActions.

Test: manual
Test: Accessibility Scanner
Test: FooterActionsControllerTest
Fixes: 227536054
Change-Id: If412d7a5bdb53c363728f06e404fd70725b8c15a
This commit is contained in:
Fabian Kozynski
2022-04-08 13:17:00 -04:00
parent 3fda2bf279
commit 638f61a57a
5 changed files with 37 additions and 16 deletions

View File

@@ -73,6 +73,9 @@
android:layout_height="@dimen/qs_footer_icon_size" android:layout_height="@dimen/qs_footer_icon_size"
android:layout_gravity="center" android:layout_gravity="center"
android:background="@android:color/transparent" android:background="@android:color/transparent"
android:focusable="false"
android:clickable="false"
android:importantForAccessibility="yes"
android:contentDescription="@string/accessibility_quick_settings_settings" android:contentDescription="@string/accessibility_quick_settings_settings"
android:scaleType="centerInside" android:scaleType="centerInside"
android:src="@drawable/ic_settings" android:src="@drawable/ic_settings"

View File

@@ -38,7 +38,6 @@ import com.android.systemui.qs.dagger.QSFlagsModule.PM_LITE_ENABLED
import com.android.systemui.qs.dagger.QSScope import com.android.systemui.qs.dagger.QSScope
import com.android.systemui.settings.UserTracker import com.android.systemui.settings.UserTracker
import com.android.systemui.statusbar.phone.MultiUserSwitchController import com.android.systemui.statusbar.phone.MultiUserSwitchController
import com.android.systemui.statusbar.phone.SettingsButton
import com.android.systemui.statusbar.policy.DeviceProvisionedController import com.android.systemui.statusbar.policy.DeviceProvisionedController
import com.android.systemui.statusbar.policy.UserInfoController import com.android.systemui.statusbar.policy.UserInfoController
import com.android.systemui.statusbar.policy.UserInfoController.OnUserInfoChangedListener import com.android.systemui.statusbar.policy.UserInfoController.OnUserInfoChangedListener
@@ -89,8 +88,7 @@ internal class FooterActionsController @Inject constructor(
updateVisibility() updateVisibility()
} }
private val settingsButton: SettingsButton = view.findViewById(R.id.settings_button) private val settingsButtonContainer: View = view.findViewById(R.id.settings_button_container)
private val settingsButtonContainer: View? = view.findViewById(R.id.settings_button_container)
private val securityFootersContainer: ViewGroup? = private val securityFootersContainer: ViewGroup? =
view.findViewById(R.id.security_footers_container) view.findViewById(R.id.security_footers_container)
private val powerMenuLite: View = view.findViewById(R.id.pm_lite) private val powerMenuLite: View = view.findViewById(R.id.pm_lite)
@@ -121,7 +119,7 @@ internal class FooterActionsController @Inject constructor(
if (!visible || falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) { if (!visible || falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
return@OnClickListener return@OnClickListener
} }
if (v === settingsButton) { if (v === settingsButtonContainer) {
if (!deviceProvisionedController.isCurrentUserSetup) { if (!deviceProvisionedController.isCurrentUserSetup) {
// If user isn't setup just unlock the device and dump them back at SUW. // If user isn't setup just unlock the device and dump them back at SUW.
activityStarter.postQSRunnableDismissingKeyguard {} activityStarter.postQSRunnableDismissingKeyguard {}
@@ -166,7 +164,7 @@ internal class FooterActionsController @Inject constructor(
} else { } else {
powerMenuLite.visibility = View.GONE powerMenuLite.visibility = View.GONE
} }
settingsButton.setOnClickListener(onClickListener) settingsButtonContainer.setOnClickListener(onClickListener)
multiUserSetting.isListening = true multiUserSetting.isListening = true
val securityFooter = securityFooterController.view val securityFooter = securityFooterController.view

View File

@@ -29,7 +29,6 @@ import com.android.settingslib.Utils
import com.android.settingslib.drawable.UserIconDrawable import com.android.settingslib.drawable.UserIconDrawable
import com.android.systemui.R import com.android.systemui.R
import com.android.systemui.statusbar.phone.MultiUserSwitch import com.android.systemui.statusbar.phone.MultiUserSwitch
import com.android.systemui.statusbar.phone.SettingsButton
/** /**
* Quick Settings bottom buttons placed in footer (aka utility bar) - always visible in expanded QS, * Quick Settings bottom buttons placed in footer (aka utility bar) - always visible in expanded QS,
@@ -38,7 +37,6 @@ import com.android.systemui.statusbar.phone.SettingsButton
*/ */
class FooterActionsView(context: Context?, attrs: AttributeSet?) : LinearLayout(context, attrs) { class FooterActionsView(context: Context?, attrs: AttributeSet?) : LinearLayout(context, attrs) {
private lateinit var settingsContainer: View private lateinit var settingsContainer: View
private lateinit var settingsButton: SettingsButton
private lateinit var multiUserSwitch: MultiUserSwitch private lateinit var multiUserSwitch: MultiUserSwitch
private lateinit var multiUserAvatar: ImageView private lateinit var multiUserAvatar: ImageView
@@ -47,15 +45,14 @@ class FooterActionsView(context: Context?, attrs: AttributeSet?) : LinearLayout(
override fun onFinishInflate() { override fun onFinishInflate() {
super.onFinishInflate() super.onFinishInflate()
settingsButton = findViewById(R.id.settings_button)
settingsContainer = findViewById(R.id.settings_button_container) settingsContainer = findViewById(R.id.settings_button_container)
multiUserSwitch = findViewById(R.id.multi_user_switch) multiUserSwitch = findViewById(R.id.multi_user_switch)
multiUserAvatar = multiUserSwitch.findViewById(R.id.multi_user_avatar) multiUserAvatar = multiUserSwitch.findViewById(R.id.multi_user_avatar)
// RenderThread is doing more harm than good when touching the header (to expand quick // RenderThread is doing more harm than good when touching the header (to expand quick
// settings), so disable it for this view // settings), so disable it for this view
if (settingsButton.background is RippleDrawable) { if (settingsContainer.background is RippleDrawable) {
(settingsButton.background as RippleDrawable).setForceSoftware(true) (settingsContainer.background as RippleDrawable).setForceSoftware(true)
} }
importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_YES importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_YES
} }
@@ -82,7 +79,7 @@ class FooterActionsView(context: Context?, attrs: AttributeSet?) : LinearLayout(
private fun updateClickabilities() { private fun updateClickabilities() {
multiUserSwitch.isClickable = multiUserSwitch.visibility == VISIBLE multiUserSwitch.isClickable = multiUserSwitch.visibility == VISIBLE
settingsButton.isClickable = settingsButton.visibility == VISIBLE settingsContainer.isClickable = settingsContainer.visibility == VISIBLE
} }
private fun updateVisibilities( private fun updateVisibilities(
@@ -91,7 +88,7 @@ class FooterActionsView(context: Context?, attrs: AttributeSet?) : LinearLayout(
settingsContainer.visibility = if (qsDisabled) GONE else VISIBLE settingsContainer.visibility = if (qsDisabled) GONE else VISIBLE
multiUserSwitch.visibility = if (multiUserEnabled) VISIBLE else GONE multiUserSwitch.visibility = if (multiUserEnabled) VISIBLE else GONE
val isDemo = UserManager.isDeviceInDemoMode(context) val isDemo = UserManager.isDeviceInDemoMode(context)
settingsButton.visibility = if (isDemo) INVISIBLE else VISIBLE settingsContainer.visibility = if (isDemo) INVISIBLE else VISIBLE
} }
fun onUserInfoChanged(picture: Drawable?, isGuestUser: Boolean) { fun onUserInfoChanged(picture: Drawable?, isGuestUser: Boolean) {

View File

@@ -24,13 +24,15 @@ import android.view.HapticFeedbackConstants;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.view.ViewConfiguration; import android.view.ViewConfiguration;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.animation.Animation; import android.view.animation.Animation;
import android.view.animation.AnimationUtils; import android.view.animation.AnimationUtils;
import android.widget.Button;
import com.android.keyguard.AlphaOptimizedImageButton;
import com.android.systemui.animation.Interpolators; import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.AlphaOptimizedImageView;
public class SettingsButton extends AlphaOptimizedImageButton { public class SettingsButton extends AlphaOptimizedImageView {
private static final boolean TUNER_ENABLE_AVAILABLE = false; private static final boolean TUNER_ENABLE_AVAILABLE = false;
@@ -170,6 +172,12 @@ public class SettingsButton extends AlphaOptimizedImageButton {
mAnimator.start(); mAnimator.start();
} }
@Override
public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfoInternal(info);
info.setClassName(Button.class.getName());
}
private final Runnable mLongPressCallback = new Runnable() { private final Runnable mLongPressCallback = new Runnable() {
@Override @Override
public void run() { public void run() {

View File

@@ -1,5 +1,6 @@
package com.android.systemui.qs package com.android.systemui.qs
import android.content.Intent
import android.os.Handler import android.os.Handler
import android.os.UserManager import android.os.UserManager
import android.provider.Settings import android.provider.Settings
@@ -14,6 +15,7 @@ import com.android.internal.logging.MetricsLogger
import com.android.internal.logging.UiEventLogger import com.android.internal.logging.UiEventLogger
import com.android.internal.logging.testing.FakeMetricsLogger import com.android.internal.logging.testing.FakeMetricsLogger
import com.android.systemui.R import com.android.systemui.R
import com.android.systemui.animation.ActivityLaunchAnimator
import com.android.systemui.classifier.FalsingManagerFake import com.android.systemui.classifier.FalsingManagerFake
import com.android.systemui.globalactions.GlobalActionsDialogLite import com.android.systemui.globalactions.GlobalActionsDialogLite
import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.ActivityStarter
@@ -136,12 +138,25 @@ class FooterActionsControllerTest : LeakCheckedTest() {
.log(GlobalActionsDialogLite.GlobalActionsEvent.GA_OPEN_QS) .log(GlobalActionsDialogLite.GlobalActionsEvent.GA_OPEN_QS)
} }
@Test
fun testSettings() {
val captor = ArgumentCaptor.forClass(Intent::class.java)
whenever(deviceProvisionedController.isCurrentUserSetup).thenReturn(true)
view.findViewById<View>(R.id.settings_button_container).performClick()
verify(activityStarter)
.startActivity(capture(captor), anyBoolean(), any<ActivityLaunchAnimator.Controller>())
assertThat(captor.value.action).isEqualTo(Settings.ACTION_SETTINGS)
}
@Test @Test
fun testSettings_UserNotSetup() { fun testSettings_UserNotSetup() {
whenever(deviceProvisionedController.isCurrentUserSetup).thenReturn(false) whenever(deviceProvisionedController.isCurrentUserSetup).thenReturn(false)
view.findViewById<View>(R.id.settings_button).performClick() view.findViewById<View>(R.id.settings_button_container).performClick()
// Verify Settings wasn't launched. // Verify Settings wasn't launched.
verify<ActivityStarter>(activityStarter, Mockito.never()).startActivity(any(), anyBoolean()) verify(activityStarter, never())
.startActivity(any(), anyBoolean(), any<ActivityLaunchAnimator.Controller>())
} }
@Test @Test