From 9c962b03e9f23afbb1b274a35993e383fa3e0582 Mon Sep 17 00:00:00 2001 From: Zaiyue Xue Date: Mon, 22 Aug 2022 14:09:24 +0800 Subject: [PATCH] Support accessibility for battery chart (1) Remove the logic of disabling clickable when accessability is on in battery chartview. Bug: 242989585 Test: manual Change-Id: I92ce0ff5aac5220d686d600dbdf1d5738fe2c385 Merged-In: I92ce0ff5aac5220d686d600dbdf1d5738fe2c385 --- .../batteryusage/BatteryChartView.java | 153 ++---------------- .../batteryusage/BatteryChartViewTest.java | 152 ----------------- 2 files changed, 12 insertions(+), 293 deletions(-) diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryChartView.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryChartView.java index b51eacb90d2..fc6daf70c8b 100644 --- a/src/com/android/settings/fuelgauge/batteryusage/BatteryChartView.java +++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryChartView.java @@ -20,7 +20,6 @@ import static com.android.settings.Utils.formatPercentage; import static java.lang.Math.round; import static java.util.Objects.requireNonNull; -import android.accessibilityservice.AccessibilityServiceInfo; import android.content.Context; import android.content.res.Resources; import android.graphics.Canvas; @@ -29,13 +28,11 @@ import android.graphics.CornerPathEffect; import android.graphics.Paint; import android.graphics.Path; import android.graphics.Rect; -import android.os.Handler; import android.util.AttributeSet; import android.util.Log; import android.view.HapticFeedbackConstants; import android.view.MotionEvent; import android.view.View; -import android.view.accessibility.AccessibilityManager; import android.widget.TextView; import androidx.annotation.NonNull; @@ -43,20 +40,15 @@ import androidx.annotation.VisibleForTesting; import androidx.appcompat.widget.AppCompatImageView; import com.android.settings.R; -import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.Utils; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.Locale; /** A widget component to draw chart graph. */ -public class BatteryChartView extends AppCompatImageView implements View.OnClickListener, - AccessibilityManager.AccessibilityStateChangeListener { +public class BatteryChartView extends AppCompatImageView implements View.OnClickListener { private static final String TAG = "BatteryChartView"; - private static final List ACCESSIBILITY_SERVICE_NAMES = - Arrays.asList("SwitchAccessService", "TalkBackService", "JustSpeakService"); private static final int DIVIDER_COLOR = Color.parseColor("#CDCCC5"); private static final long UPDATE_STATE_DELAYED_TIME = 500L; @@ -67,48 +59,31 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick void onSelect(int trapezoidIndex); } - private BatteryChartViewModel mViewModel; + private final String[] mPercentages = getPercentages(); + private final Rect mIndent = new Rect(); + private final Rect[] mPercentageBounds = new Rect[]{new Rect(), new Rect(), new Rect()}; + private final List mAxisLabelsBounds = new ArrayList<>(); + private BatteryChartViewModel mViewModel; + private int mHoveredIndex = BatteryChartViewModel.SELECTED_INDEX_INVALID; private int mDividerWidth; private int mDividerHeight; private float mTrapezoidVOffset; private float mTrapezoidHOffset; - private boolean mIsSlotsClickabled; - private String[] mPercentages = getPercentages(); - - @VisibleForTesting - int mHoveredIndex = BatteryChartViewModel.SELECTED_INDEX_INVALID; - - // Colors for drawing the trapezoid shape and dividers. private int mTrapezoidColor; private int mTrapezoidSolidColor; private int mTrapezoidHoverColor; - // For drawing the percentage information. private int mTextPadding; - private final Rect mIndent = new Rect(); - private final Rect[] mPercentageBounds = - new Rect[]{new Rect(), new Rect(), new Rect()}; - // For drawing the axis label information. - private final List mAxisLabelsBounds = new ArrayList<>(); - - - @VisibleForTesting - Handler mHandler = new Handler(); - @VisibleForTesting - final Runnable mUpdateClickableStateRun = () -> updateClickableState(); - - private Paint mTextPaint; private Paint mDividerPaint; private Paint mTrapezoidPaint; + private Paint mTextPaint; + private BatteryChartView.OnSelectListener mOnSelectListener; - @VisibleForTesting - Paint mTrapezoidCurvePaint = null; @VisibleForTesting TrapezoidSlot[] mTrapezoidSlots; // Records the location to calculate selected index. @VisibleForTesting float mTouchUpEventX = Float.MIN_VALUE; - private BatteryChartView.OnSelectListener mOnSelectListener; public BatteryChartView(Context context) { super(context, null); @@ -261,66 +236,6 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick view.performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK); } - @Override - public void onAttachedToWindow() { - super.onAttachedToWindow(); - updateClickableState(); - mContext.getSystemService(AccessibilityManager.class) - .addAccessibilityStateChangeListener(/*listener=*/ this); - } - - @Override - public void onDetachedFromWindow() { - super.onDetachedFromWindow(); - mContext.getSystemService(AccessibilityManager.class) - .removeAccessibilityStateChangeListener(/*listener=*/ this); - mHandler.removeCallbacks(mUpdateClickableStateRun); - } - - @Override - public void onAccessibilityStateChanged(boolean enabled) { - Log.d(TAG, "onAccessibilityStateChanged:" + enabled); - mHandler.removeCallbacks(mUpdateClickableStateRun); - // We should delay it a while since accessibility manager will spend - // some times to bind with new enabled accessibility services. - mHandler.postDelayed( - mUpdateClickableStateRun, UPDATE_STATE_DELAYED_TIME); - } - - private void updateClickableState() { - final Context context = mContext; - mIsSlotsClickabled = - FeatureFactory.getFactory(context) - .getPowerUsageFeatureProvider(context) - .isChartGraphSlotsEnabled(context) - && !isAccessibilityEnabled(context); - Log.d(TAG, "isChartGraphSlotsEnabled:" + mIsSlotsClickabled); - setClickable(isClickable()); - // Initializes the trapezoid curve paint for non-clickable case. - if (!mIsSlotsClickabled && mTrapezoidCurvePaint == null) { - mTrapezoidCurvePaint = new Paint(); - mTrapezoidCurvePaint.setAntiAlias(true); - mTrapezoidCurvePaint.setColor(mTrapezoidSolidColor); - mTrapezoidCurvePaint.setStyle(Paint.Style.STROKE); - mTrapezoidCurvePaint.setStrokeWidth(mDividerWidth * 2); - } else if (mIsSlotsClickabled) { - mTrapezoidCurvePaint = null; - // Sets view model again to force update the click state. - setViewModel(mViewModel); - } - invalidate(); - } - - @Override - public void setClickable(boolean clickable) { - super.setClickable(mIsSlotsClickabled && clickable); - } - - @VisibleForTesting - void setClickableForce(boolean clickable) { - super.setClickable(clickable); - } - private void initializeTrapezoidSlots(int count) { mTrapezoidSlots = new TrapezoidSlot[count]; for (int index = 0; index < mTrapezoidSlots.length; index++) { @@ -545,19 +460,14 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick for (int index = 0; index < mTrapezoidSlots.length; index++) { // Not draws the trapezoid for corner or not initialization cases. if (!isValidToDraw(mViewModel, index)) { - if (mTrapezoidCurvePaint != null && trapezoidCurvePath != null) { - canvas.drawPath(trapezoidCurvePath, mTrapezoidCurvePaint); - trapezoidCurvePath = null; - } continue; } // Configures the trapezoid paint color. - final int trapezoidColor = mIsSlotsClickabled && (mViewModel.selectedIndex() == index + final int trapezoidColor = (mViewModel.selectedIndex() == index || mViewModel.selectedIndex() == BatteryChartViewModel.SELECTED_INDEX_ALL) ? mTrapezoidSolidColor : mTrapezoidColor; - final boolean isHoverState = - mIsSlotsClickabled && mHoveredIndex == index - && isValidToDraw(mViewModel, mHoveredIndex); + final boolean isHoverState = mHoveredIndex == index && isValidToDraw(mViewModel, + mHoveredIndex); mTrapezoidPaint.setColor(isHoverState ? mTrapezoidHoverColor : trapezoidColor); final float leftTop = round( @@ -574,22 +484,6 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick trapezoidPath.lineTo(mTrapezoidSlots[index].mLeft, leftTop); // Draws the trapezoid shape into canvas. canvas.drawPath(trapezoidPath, mTrapezoidPaint); - - // Generates path for non-clickable trapezoid curve. - if (mTrapezoidCurvePaint != null) { - if (trapezoidCurvePath == null) { - trapezoidCurvePath = new Path(); - trapezoidCurvePath.moveTo(mTrapezoidSlots[index].mLeft, leftTop); - } else { - trapezoidCurvePath.lineTo(mTrapezoidSlots[index].mLeft, leftTop); - } - trapezoidCurvePath.lineTo(mTrapezoidSlots[index].mRight, rightTop); - } - } - // Draws the trapezoid curve for non-clickable case. - if (mTrapezoidCurvePaint != null && trapezoidCurvePath != null) { - canvas.drawPath(trapezoidCurvePath, mTrapezoidCurvePaint); - trapezoidCurvePath = null; } } @@ -645,29 +539,6 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick formatPercentage(/*percentage=*/ 0, /*round=*/ true)}; } - @VisibleForTesting - static boolean isAccessibilityEnabled(Context context) { - final AccessibilityManager accessibilityManager = - context.getSystemService(AccessibilityManager.class); - if (!accessibilityManager.isEnabled()) { - return false; - } - final List serviceInfoList = - accessibilityManager.getEnabledAccessibilityServiceList( - AccessibilityServiceInfo.FEEDBACK_SPOKEN - | AccessibilityServiceInfo.FEEDBACK_GENERIC); - for (AccessibilityServiceInfo info : serviceInfoList) { - for (String serviceName : ACCESSIBILITY_SERVICE_NAMES) { - final String serviceId = info.getId(); - if (serviceId != null && serviceId.contains(serviceName)) { - Log.d(TAG, "acccessibilityEnabled:" + serviceId); - return true; - } - } - } - return false; - } - // A container class for each trapezoid left and right location. @VisibleForTesting static final class TrapezoidSlot { diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartViewTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartViewTest.java index 8a430875614..7e423e0ccab 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartViewTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartViewTest.java @@ -17,17 +17,11 @@ package com.android.settings.fuelgauge.batteryusage; import static com.google.common.truth.Truth.assertThat; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import android.accessibilityservice.AccessibilityServiceInfo; import android.content.Context; import android.os.LocaleList; import android.view.View; -import android.view.accessibility.AccessibilityManager; import com.android.settings.fuelgauge.PowerUsageFeatureProvider; import com.android.settings.testutils.FakeFeatureFactory; @@ -40,8 +34,6 @@ import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; -import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.Locale; @@ -53,10 +45,6 @@ public final class BatteryChartViewTest { private FakeFeatureFactory mFeatureFactory; private PowerUsageFeatureProvider mPowerUsageFeatureProvider; - @Mock - private AccessibilityServiceInfo mMockAccessibilityServiceInfo; - @Mock - private AccessibilityManager mMockAccessibilityManager; @Mock private View mMockView; @@ -69,34 +57,6 @@ public final class BatteryChartViewTest { mContext.getResources().getConfiguration().setLocales( new LocaleList(new Locale("en_US"))); mBatteryChartView = new BatteryChartView(mContext); - doReturn(mMockAccessibilityManager).when(mContext) - .getSystemService(AccessibilityManager.class); - doReturn("TalkBackService").when(mMockAccessibilityServiceInfo).getId(); - doReturn(Arrays.asList(mMockAccessibilityServiceInfo)) - .when(mMockAccessibilityManager) - .getEnabledAccessibilityServiceList(anyInt()); - } - - @Test - public void isAccessibilityEnabled_disable_returnFalse() { - doReturn(false).when(mMockAccessibilityManager).isEnabled(); - assertThat(BatteryChartView.isAccessibilityEnabled(mContext)).isFalse(); - } - - @Test - public void isAccessibilityEnabled_emptyInfo_returnFalse() { - doReturn(true).when(mMockAccessibilityManager).isEnabled(); - doReturn(new ArrayList()) - .when(mMockAccessibilityManager) - .getEnabledAccessibilityServiceList(anyInt()); - - assertThat(BatteryChartView.isAccessibilityEnabled(mContext)).isFalse(); - } - - @Test - public void isAccessibilityEnabled_validServiceId_returnTrue() { - doReturn(true).when(mMockAccessibilityManager).isEnabled(); - assertThat(BatteryChartView.isAccessibilityEnabled(mContext)).isTrue(); } @Test @@ -130,116 +90,4 @@ public final class BatteryChartViewTest { mBatteryChartView.onClick(mMockView); assertThat(selectedIndex[0]).isEqualTo(BatteryChartViewModel.SELECTED_INDEX_ALL); } - - @Test - public void clickable_isChartGraphSlotsEnabledIsFalse_notClickable() { - mBatteryChartView.setClickableForce(true); - when(mPowerUsageFeatureProvider.isChartGraphSlotsEnabled(mContext)) - .thenReturn(false); - - mBatteryChartView.onAttachedToWindow(); - - assertThat(mBatteryChartView.isClickable()).isFalse(); - assertThat(mBatteryChartView.mTrapezoidCurvePaint).isNotNull(); - } - - @Test - public void clickable_accessibilityIsDisabled_clickable() { - mBatteryChartView.setClickableForce(true); - when(mPowerUsageFeatureProvider.isChartGraphSlotsEnabled(mContext)) - .thenReturn(true); - doReturn(false).when(mMockAccessibilityManager).isEnabled(); - - mBatteryChartView.onAttachedToWindow(); - - assertThat(mBatteryChartView.isClickable()).isTrue(); - assertThat(mBatteryChartView.mTrapezoidCurvePaint).isNull(); - } - - @Test - public void clickable_accessibilityIsEnabledWithoutValidId_clickable() { - mBatteryChartView.setClickableForce(true); - when(mPowerUsageFeatureProvider.isChartGraphSlotsEnabled(mContext)) - .thenReturn(true); - doReturn(true).when(mMockAccessibilityManager).isEnabled(); - doReturn(new ArrayList()) - .when(mMockAccessibilityManager) - .getEnabledAccessibilityServiceList(anyInt()); - - mBatteryChartView.onAttachedToWindow(); - - assertThat(mBatteryChartView.isClickable()).isTrue(); - assertThat(mBatteryChartView.mTrapezoidCurvePaint).isNull(); - } - - @Test - public void clickable_accessibilityIsEnabledWithValidId_notClickable() { - mBatteryChartView.setClickableForce(true); - when(mPowerUsageFeatureProvider.isChartGraphSlotsEnabled(mContext)) - .thenReturn(true); - doReturn(true).when(mMockAccessibilityManager).isEnabled(); - - mBatteryChartView.onAttachedToWindow(); - - assertThat(mBatteryChartView.isClickable()).isFalse(); - assertThat(mBatteryChartView.mTrapezoidCurvePaint).isNotNull(); - } - - @Test - public void clickable_restoreFromNonClickableState() { - final List levels = new ArrayList(); - final List texts = new ArrayList(); - for (int index = 0; index < 13; index++) { - levels.add(index + 1); - texts.add(""); - } - mBatteryChartView.setViewModel(new BatteryChartViewModel(levels, texts, - BatteryChartViewModel.AxisLabelPosition.BETWEEN_TRAPEZOIDS)); - mBatteryChartView.setClickableForce(true); - when(mPowerUsageFeatureProvider.isChartGraphSlotsEnabled(mContext)) - .thenReturn(true); - doReturn(true).when(mMockAccessibilityManager).isEnabled(); - mBatteryChartView.onAttachedToWindow(); - // Ensures the testing environment is correct. - assertThat(mBatteryChartView.isClickable()).isFalse(); - // Turns off accessibility service. - doReturn(false).when(mMockAccessibilityManager).isEnabled(); - - mBatteryChartView.onAttachedToWindow(); - - assertThat(mBatteryChartView.isClickable()).isTrue(); - } - - @Test - public void onAttachedToWindow_addAccessibilityStateChangeListener() { - mBatteryChartView.onAttachedToWindow(); - verify(mMockAccessibilityManager) - .addAccessibilityStateChangeListener(mBatteryChartView); - } - - @Test - public void onDetachedFromWindow_removeAccessibilityStateChangeListener() { - mBatteryChartView.onAttachedToWindow(); - mBatteryChartView.mHandler.postDelayed( - mBatteryChartView.mUpdateClickableStateRun, 1000); - - mBatteryChartView.onDetachedFromWindow(); - - verify(mMockAccessibilityManager) - .removeAccessibilityStateChangeListener(mBatteryChartView); - assertThat(mBatteryChartView.mHandler.hasCallbacks( - mBatteryChartView.mUpdateClickableStateRun)) - .isFalse(); - } - - @Test - public void onAccessibilityStateChanged_postUpdateStateRunnable() { - mBatteryChartView.mHandler = spy(mBatteryChartView.mHandler); - mBatteryChartView.onAccessibilityStateChanged(/*enabled=*/ true); - - verify(mBatteryChartView.mHandler) - .removeCallbacks(mBatteryChartView.mUpdateClickableStateRun); - verify(mBatteryChartView.mHandler) - .postDelayed(mBatteryChartView.mUpdateClickableStateRun, 500L); - } }