From 11de1a6452d45dc48a78b8784d894dece36e7060 Mon Sep 17 00:00:00 2001 From: ykhung Date: Thu, 13 May 2021 15:35:01 +0800 Subject: [PATCH] Make chart time slot not clickable when accessibility servie is enabled after discuss with Shuan & Peggy, we will make the chat view is not clickable since accessibility service is enabled for talkback, switch access and voice access, since some gestures are conflict with our design (double click to show all contents is conflict with a11y behavior) Bug: 187814675 Test: make SettingsRoboTests Change-Id: I7eecafc42cf4b4a0374ab46f07461e77907fc03a --- .../settings/fuelgauge/BatteryChartView.java | 41 +++++++++++-- .../fuelgauge/BatteryChartViewTest.java | 60 +++++++++++++++++++ 2 files changed, 97 insertions(+), 4 deletions(-) diff --git a/src/com/android/settings/fuelgauge/BatteryChartView.java b/src/com/android/settings/fuelgauge/BatteryChartView.java index 104801704d1..1590a57818d 100644 --- a/src/com/android/settings/fuelgauge/BatteryChartView.java +++ b/src/com/android/settings/fuelgauge/BatteryChartView.java @@ -24,6 +24,7 @@ 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; @@ -44,7 +45,8 @@ import java.util.List; import java.util.Locale; /** A widget component to draw chart graph. */ -public class BatteryChartView extends AppCompatImageView implements View.OnClickListener { +public class BatteryChartView extends AppCompatImageView implements View.OnClickListener, + AccessibilityManager.AccessibilityStateChangeListener { private static final String TAG = "BatteryChartView"; private static final List ACCESSIBILITY_SERVICE_NAMES = Arrays.asList("SwitchAccessService", "TalkBackService", "JustSpeakService"); @@ -52,6 +54,8 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick private static final String[] PERCENTAGES = new String[] {"100%", "50%", "0%"}; private static final int DEFAULT_TRAPEZOID_COUNT = 12; private static final int DEFAULT_TIMESTAMP_COUNT = 4; + private static final int DIVIDER_COLOR = Color.parseColor("#CDCCC5"); + private static final long UPDATE_STATE_DELAYED_TIME = 500L; /** Selects all trapezoid shapes. */ public static final int SELECTED_INDEX_ALL = -1; @@ -74,7 +78,6 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick // Colors for drawing the trapezoid shape and dividers. private int mTrapezoidColor; private int mTrapezoidSolidColor; - private final int mDividerColor = Color.parseColor("#CDCCC5"); // For drawing the percentage information. private int mTextPadding; private final Rect mIndent = new Rect(); @@ -85,11 +88,17 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick private final Rect[] mTimestampsBounds = new Rect[] {new Rect(), new Rect(), new Rect(), new Rect()}; + @VisibleForTesting + Handler mHandler = new Handler(); + @VisibleForTesting + final Runnable mUpdateClickableStateRun = () -> updateClickableState(); + private int[] mLevels; private Paint mTextPaint; private Paint mDividerPaint; private Paint mTrapezoidPaint; - private Paint mTrapezoidCurvePaint = null; + @VisibleForTesting + Paint mTrapezoidCurvePaint = null; private TrapezoidSlot[] mTrapezoidSlots; // Records the location to calculate selected index. private MotionEvent mTouchUpEvent; @@ -257,6 +266,26 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick 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() { @@ -275,6 +304,10 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick mTrapezoidCurvePaint.setColor(mTrapezoidSolidColor); mTrapezoidCurvePaint.setStyle(Paint.Style.STROKE); mTrapezoidCurvePaint.setStrokeWidth(mDividerWidth * 2); + } else if (mIsSlotsClickabled) { + mTrapezoidCurvePaint = null; + // Sets levels again to force update the click state. + setLevels(mLevels); } invalidate(); } @@ -299,7 +332,7 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick mDividerHeight = resources.getDimensionPixelSize(R.dimen.chartview_divider_height); mDividerPaint = new Paint(); mDividerPaint.setAntiAlias(true); - mDividerPaint.setColor(mDividerColor); + mDividerPaint.setColor(DIVIDER_COLOR); mDividerPaint.setStyle(Paint.Style.STROKE); mDividerPaint.setStrokeWidth(mDividerWidth); Log.i(TAG, "mDividerWidth:" + mDividerWidth); diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryChartViewTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryChartViewTest.java index 877ebc28734..3998a332630 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryChartViewTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryChartViewTest.java @@ -130,6 +130,7 @@ public final class BatteryChartViewTest { mBatteryChartView.onAttachedToWindow(); assertThat(mBatteryChartView.isClickable()).isFalse(); + assertThat(mBatteryChartView.mTrapezoidCurvePaint).isNotNull(); } @Test @@ -141,6 +142,7 @@ public final class BatteryChartViewTest { mBatteryChartView.onAttachedToWindow(); assertThat(mBatteryChartView.isClickable()).isTrue(); + assertThat(mBatteryChartView.mTrapezoidCurvePaint).isNull(); } @Test @@ -155,6 +157,7 @@ public final class BatteryChartViewTest { mBatteryChartView.onAttachedToWindow(); assertThat(mBatteryChartView.isClickable()).isTrue(); + assertThat(mBatteryChartView.mTrapezoidCurvePaint).isNull(); } @Test @@ -166,5 +169,62 @@ public final class BatteryChartViewTest { mBatteryChartView.onAttachedToWindow(); assertThat(mBatteryChartView.isClickable()).isFalse(); + assertThat(mBatteryChartView.mTrapezoidCurvePaint).isNotNull(); + } + + @Test + public void testClickable_restoreFromNonClickableState() { + final int[] levels = new int[13]; + for (int index = 0; index < levels.length; index++) { + levels[index] = index + 1; + } + mBatteryChartView.setTrapezoidCount(12); + mBatteryChartView.setLevels(levels); + mBatteryChartView.setClickableForce(true); + when(mPowerUsageFeatureProvider.isChartGraphSlotsEnabled(mContext)) + .thenReturn(true); + doReturn(true).when(mockAccessibilityManager).isEnabled(); + mBatteryChartView.onAttachedToWindow(); + // Ensures the testing environment is correct. + assertThat(mBatteryChartView.isClickable()).isFalse(); + // Turns off accessibility service. + doReturn(false).when(mockAccessibilityManager).isEnabled(); + + mBatteryChartView.onAttachedToWindow(); + + assertThat(mBatteryChartView.isClickable()).isTrue(); + } + + @Test + public void testOnAttachedToWindow_addAccessibilityStateChangeListener() { + mBatteryChartView.onAttachedToWindow(); + verify(mockAccessibilityManager) + .addAccessibilityStateChangeListener(mBatteryChartView); + } + + @Test + public void testOnDetachedFromWindow_removeAccessibilityStateChangeListener() { + mBatteryChartView.onAttachedToWindow(); + mBatteryChartView.mHandler.postDelayed( + mBatteryChartView.mUpdateClickableStateRun, 1000); + + mBatteryChartView.onDetachedFromWindow(); + + verify(mockAccessibilityManager) + .removeAccessibilityStateChangeListener(mBatteryChartView); + assertThat(mBatteryChartView.mHandler.hasCallbacks( + mBatteryChartView.mUpdateClickableStateRun)) + .isFalse(); + } + + @Test + public void testOnAccessibilityStateChanged_postUpdateStateRunnable() { + mBatteryChartView.mHandler = spy(mBatteryChartView.mHandler); + mBatteryChartView.onAccessibilityStateChanged(/*enabled=*/ true); + + verify(mBatteryChartView.mHandler) + .removeCallbacks(mBatteryChartView.mUpdateClickableStateRun); + verify(mBatteryChartView.mHandler) + .postDelayed(mBatteryChartView.mUpdateClickableStateRun, 500L); } }