Merge "Make chart time slot not clickable when accessibility servie is enabled" into sc-dev
diff --git a/src/com/android/settings/fuelgauge/BatteryChartView.java b/src/com/android/settings/fuelgauge/BatteryChartView.java
index 1048017..1590a57 100644
--- a/src/com/android/settings/fuelgauge/BatteryChartView.java
+++ b/src/com/android/settings/fuelgauge/BatteryChartView.java
@@ -24,6 +24,7 @@
 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.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<String> ACCESSIBILITY_SERVICE_NAMES =
         Arrays.asList("SwitchAccessService", "TalkBackService", "JustSpeakService");
@@ -52,6 +54,8 @@
     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 @@
     // 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 @@
     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 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 @@
             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 @@
         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 877ebc2..3998a33 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 @@
 
         mBatteryChartView.onAttachedToWindow();
         assertThat(mBatteryChartView.isClickable()).isFalse();
+        assertThat(mBatteryChartView.mTrapezoidCurvePaint).isNotNull();
     }
 
     @Test
@@ -141,6 +142,7 @@
 
         mBatteryChartView.onAttachedToWindow();
         assertThat(mBatteryChartView.isClickable()).isTrue();
+        assertThat(mBatteryChartView.mTrapezoidCurvePaint).isNull();
     }
 
     @Test
@@ -155,6 +157,7 @@
 
         mBatteryChartView.onAttachedToWindow();
         assertThat(mBatteryChartView.isClickable()).isTrue();
+        assertThat(mBatteryChartView.mTrapezoidCurvePaint).isNull();
     }
 
     @Test
@@ -166,5 +169,62 @@
 
         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);
     }
 }