Merge "Import translations. DO NOT MERGE ANYWHERE" into tm-qpr-dev
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java
index 26379eb..79f0880 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java
@@ -30,6 +30,7 @@
 import android.text.format.DateUtils;
 import android.util.Log;
 import android.view.View;
+import android.view.accessibility.AccessibilityManager;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.VisibleForTesting;
@@ -107,12 +108,9 @@
     private boolean mIs24HourFormat;
     private boolean mIsFooterPrefAdded = false;
     private View mBatteryChartViewGroup;
+    private View mCategoryTitleView;
     private PreferenceScreen mPreferenceScreen;
     private FooterPreference mFooterPreference;
-    // Daily view model only saves abbreviated day of week texts (e.g. MON). This field saves the
-    // full day of week texts (e.g. Monday), which is used in category title and battery detail
-    // page.
-    private List<String> mDailyTimestampFullTexts;
     private BatteryChartViewModel mDailyViewModel;
     private List<BatteryChartViewModel> mHourlyViewModels;
 
@@ -127,6 +125,13 @@
     private final AnimatorListenerAdapter mHourlyChartFadeOutAdapter =
             createHourlyChartAnimatorListenerAdapter(/*isToShow=*/ false);
 
+    @VisibleForTesting
+    final DailyChartLabelTextGenerator mDailyChartLabelTextGenerator =
+            new DailyChartLabelTextGenerator();
+    @VisibleForTesting
+    final HourlyChartLabelTextGenerator mHourlyChartLabelTextGenerator =
+            new HourlyChartLabelTextGenerator();
+
     // Preference cache to avoid create new instance each time.
     @VisibleForTesting
     final Map<String, Preference> mPreferenceCache = new HashMap<>();
@@ -284,29 +289,24 @@
                 getTotalHours(batteryLevelData));
 
         if (batteryLevelData == null) {
-            mDailyTimestampFullTexts = null;
             mDailyViewModel = null;
             mHourlyViewModels = null;
             refreshUi();
             return;
         }
-        mDailyTimestampFullTexts = generateTimestampDayOfWeekTexts(
-                mContext, batteryLevelData.getDailyBatteryLevels().getTimestamps(),
-                /* isAbbreviation= */ false);
         mDailyViewModel = new BatteryChartViewModel(
                 batteryLevelData.getDailyBatteryLevels().getLevels(),
-                generateTimestampDayOfWeekTexts(
-                        mContext, batteryLevelData.getDailyBatteryLevels().getTimestamps(),
-                        /* isAbbreviation= */ true),
-                BatteryChartViewModel.AxisLabelPosition.CENTER_OF_TRAPEZOIDS);
+                batteryLevelData.getDailyBatteryLevels().getTimestamps(),
+                BatteryChartViewModel.AxisLabelPosition.CENTER_OF_TRAPEZOIDS,
+                mDailyChartLabelTextGenerator);
         mHourlyViewModels = new ArrayList<>();
         for (BatteryLevelData.PeriodBatteryLevelData hourlyBatteryLevelsPerDay :
                 batteryLevelData.getHourlyBatteryLevelsPerDay()) {
             mHourlyViewModels.add(new BatteryChartViewModel(
                     hourlyBatteryLevelsPerDay.getLevels(),
-                    generateTimestampHourTexts(
-                            mContext, hourlyBatteryLevelsPerDay.getTimestamps()),
-                    BatteryChartViewModel.AxisLabelPosition.BETWEEN_TRAPEZOIDS));
+                    hourlyBatteryLevelsPerDay.getTimestamps(),
+                    BatteryChartViewModel.AxisLabelPosition.BETWEEN_TRAPEZOIDS,
+                    mHourlyChartLabelTextGenerator));
         }
         refreshUi();
     }
@@ -334,6 +334,7 @@
             mDailyChartIndex = trapezoidIndex;
             mHourlyChartIndex = BatteryChartViewModel.SELECTED_INDEX_ALL;
             refreshUi();
+            requestAccessibilityFocusForCategoryTitle(mDailyChartView);
             mMetricsFeatureProvider.action(
                     mPrefContext,
                     trapezoidIndex == BatteryChartViewModel.SELECTED_INDEX_ALL
@@ -349,6 +350,7 @@
             Log.d(TAG, "onHourlyChartSelect:" + trapezoidIndex);
             mHourlyChartIndex = trapezoidIndex;
             refreshUi();
+            requestAccessibilityFocusForCategoryTitle(mHourlyChartView);
             mMetricsFeatureProvider.action(
                     mPrefContext,
                     trapezoidIndex == BatteryChartViewModel.SELECTED_INDEX_ALL
@@ -532,6 +534,18 @@
         }
     }
 
+    private void requestAccessibilityFocusForCategoryTitle(View view) {
+        if (!AccessibilityManager.getInstance(mContext).isEnabled()) {
+            return;
+        }
+        if (mCategoryTitleView == null) {
+            mCategoryTitleView = view.getRootView().findViewById(com.android.internal.R.id.title);
+        }
+        if (mCategoryTitleView != null) {
+            mCategoryTitleView.requestAccessibilityFocus();
+        }
+    }
+
     private String getSlotInformation(boolean isApp, String slotInformation) {
         // TODO: Updates the right slot information from daily and hourly chart selection.
         // Null means we show all information without a specific time slot.
@@ -548,8 +562,7 @@
 
     @VisibleForTesting
     String getSlotInformation() {
-        if (mDailyTimestampFullTexts == null || mDailyViewModel == null
-                || mHourlyViewModels == null) {
+        if (mDailyViewModel == null || mHourlyViewModels == null) {
             // No data
             return null;
         }
@@ -557,17 +570,13 @@
             return null;
         }
 
-        final String selectedDayText = mDailyTimestampFullTexts.get(mDailyChartIndex);
+        final String selectedDayText = mDailyViewModel.getFullText(mDailyChartIndex);
         if (mHourlyChartIndex == BatteryChartViewModel.SELECTED_INDEX_ALL) {
             return selectedDayText;
         }
 
-        final String fromHourText = mHourlyViewModels.get(mDailyChartIndex).texts().get(
+        final String selectedHourText = mHourlyViewModels.get(mDailyChartIndex).getFullText(
                 mHourlyChartIndex);
-        final String toHourText = mHourlyViewModels.get(mDailyChartIndex).texts().get(
-                mHourlyChartIndex + 1);
-        final String selectedHourText =
-                String.format("%s%s%s", fromHourText, mIs24HourFormat ? "-" : " - ", toHourText);
         if (isBatteryLevelDataInOneDay()) {
             return selectedHourText;
         }
@@ -712,25 +721,6 @@
                 / DateUtils.HOUR_IN_MILLIS);
     }
 
-    private static List<String> generateTimestampDayOfWeekTexts(@NonNull final Context context,
-            @NonNull final List<Long> timestamps, final boolean isAbbreviation) {
-        final ArrayList<String> texts = new ArrayList<>();
-        for (Long timestamp : timestamps) {
-            texts.add(ConvertUtils.utcToLocalTimeDayOfWeek(context, timestamp, isAbbreviation));
-        }
-        return texts;
-    }
-
-    private static List<String> generateTimestampHourTexts(
-            @NonNull final Context context, @NonNull final List<Long> timestamps) {
-        final boolean is24HourFormat = DateFormat.is24HourFormat(context);
-        final ArrayList<String> texts = new ArrayList<>();
-        for (Long timestamp : timestamps) {
-            texts.add(ConvertUtils.utcToLocalTimeHour(context, timestamp, is24HourFormat));
-        }
-        return texts;
-    }
-
     /** Used for {@link AppBatteryPreferenceController}. */
     public static List<BatteryDiffEntry> getAppBatteryUsageData(Context context) {
         final long start = System.currentTimeMillis();
@@ -776,4 +766,36 @@
         }
         return null;
     }
+
+    private final class DailyChartLabelTextGenerator implements
+            BatteryChartViewModel.LabelTextGenerator {
+        @Override
+        public String generateText(List<Long> timestamps, int index) {
+            return ConvertUtils.utcToLocalTimeDayOfWeek(mContext,
+                    timestamps.get(index), /* isAbbreviation= */ true);
+        }
+
+        @Override
+        public String generateFullText(List<Long> timestamps, int index) {
+            return ConvertUtils.utcToLocalTimeDayOfWeek(mContext,
+                    timestamps.get(index), /* isAbbreviation= */ false);
+        }
+    }
+
+    private final class HourlyChartLabelTextGenerator implements
+            BatteryChartViewModel.LabelTextGenerator {
+        @Override
+        public String generateText(List<Long> timestamps, int index) {
+            return ConvertUtils.utcToLocalTimeHour(mContext, timestamps.get(index),
+                    mIs24HourFormat);
+        }
+
+        @Override
+        public String generateFullText(List<Long> timestamps, int index) {
+            return index == timestamps.size() - 1
+                    ? generateText(timestamps, index)
+                    : String.format("%s%s%s", generateText(timestamps, index),
+                            mIs24HourFormat ? "-" : " - ", generateText(timestamps, index + 1));
+        }
+    }
 }
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryChartView.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryChartView.java
index b51eacb..f84ced7 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 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,34 +28,34 @@
 import android.graphics.Paint;
 import android.graphics.Path;
 import android.graphics.Rect;
-import android.os.Handler;
+import android.os.Bundle;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.HapticFeedbackConstants;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.ViewParent;
+import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeProvider;
 import android.widget.TextView;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 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<String> 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 +66,32 @@
         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<Rect> 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<Rect> 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 AccessibilityNodeProvider mAccessibilityNodeProvider;
+    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);
@@ -175,7 +158,7 @@
             if (mViewModel != null) {
                 int maxTop = 0;
                 for (int index = 0; index < mViewModel.size(); index++) {
-                    final String text = mViewModel.texts().get(index);
+                    final String text = mViewModel.getText(index);
                     mTextPaint.getTextBounds(text, 0, text.length(), mAxisLabelsBounds.get(index));
                     maxTop = Math.max(maxTop, -mAxisLabelsBounds.get(index).top);
                 }
@@ -225,10 +208,23 @@
                 if (mHoveredIndex != trapezoidIndex) {
                     mHoveredIndex = trapezoidIndex;
                     invalidate();
+                    sendAccessibilityEventForHover(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER);
                 }
-                break;
+                // Ignore the super.onHoverEvent() because the hovered trapezoid has already been
+                // sent here.
+                return true;
+            case MotionEvent.ACTION_HOVER_EXIT:
+                if (mHoveredIndex != BatteryChartViewModel.SELECTED_INDEX_INVALID) {
+                    sendAccessibilityEventForHover(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT);
+                    mHoveredIndex = BatteryChartViewModel.SELECTED_INDEX_INVALID; // reset
+                    invalidate();
+                }
+                // Ignore the super.onHoverEvent() because the hovered trapezoid has already been
+                // sent here.
+                return true;
+            default:
+                return super.onTouchEvent(event);
         }
-        return super.onHoverEvent(event);
     }
 
     @Override
@@ -246,79 +242,51 @@
             Log.w(TAG, "invalid motion event for onClick() callback");
             return;
         }
-        final int trapezoidIndex = getTrapezoidIndex(mTouchUpEventX);
+        onTrapezoidClicked(view, getTrapezoidIndex(mTouchUpEventX));
+    }
+
+    @Override
+    public AccessibilityNodeProvider getAccessibilityNodeProvider() {
+        if (mViewModel == null) {
+            return super.getAccessibilityNodeProvider();
+        }
+        if (mAccessibilityNodeProvider == null) {
+            mAccessibilityNodeProvider = new BatteryChartAccessibilityNodeProvider();
+        }
+        return mAccessibilityNodeProvider;
+    }
+
+    private void onTrapezoidClicked(View view, int index) {
         // Ignores the click event if the level is zero.
-        if (trapezoidIndex == BatteryChartViewModel.SELECTED_INDEX_INVALID
-                || !isValidToDraw(mViewModel, trapezoidIndex)) {
+        if (!isValidToDraw(mViewModel, index)) {
             return;
         }
         if (mOnSelectListener != null) {
             // Selects all if users click the same trapezoid item two times.
             mOnSelectListener.onSelect(
-                    trapezoidIndex == mViewModel.selectedIndex()
-                            ? BatteryChartViewModel.SELECTED_INDEX_ALL : trapezoidIndex);
+                    index == mViewModel.selectedIndex()
+                            ? BatteryChartViewModel.SELECTED_INDEX_ALL : index);
         }
         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);
+    private boolean sendAccessibilityEvent(int virtualDescendantId, int eventType) {
+        ViewParent parent = getParent();
+        if (parent == null || !AccessibilityManager.getInstance(mContext).isEnabled()) {
+            return false;
         }
-        invalidate();
+        AccessibilityEvent accessibilityEvent = new AccessibilityEvent(eventType);
+        accessibilityEvent.setSource(this, virtualDescendantId);
+        accessibilityEvent.setEnabled(true);
+        accessibilityEvent.setClassName(getAccessibilityClassName());
+        accessibilityEvent.setPackageName(getContext().getPackageName());
+        return parent.requestSendAccessibilityEvent(this, accessibilityEvent);
     }
 
-    @Override
-    public void setClickable(boolean clickable) {
-        super.setClickable(mIsSlotsClickabled && clickable);
-    }
-
-    @VisibleForTesting
-    void setClickableForce(boolean clickable) {
-        super.setClickable(clickable);
+    private void sendAccessibilityEventForHover(int eventType) {
+        if (isTrapezoidIndexValid(mViewModel, mHoveredIndex)) {
+            sendAccessibilityEvent(mHoveredIndex, eventType);
+        }
     }
 
     private void initializeTrapezoidSlots(int count) {
@@ -522,7 +490,7 @@
             Canvas canvas, final int index, final Rect displayArea, final float baselineY) {
         mTextPaint.setTextAlign(Paint.Align.CENTER);
         canvas.drawText(
-                mViewModel.texts().get(index),
+                mViewModel.getText(index),
                 displayArea.centerX(),
                 baselineY,
                 mTextPaint);
@@ -545,25 +513,20 @@
         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(
-                    trapezoidBottom - requireNonNull(mViewModel.levels().get(index)) * unitHeight);
+                    trapezoidBottom - requireNonNull(mViewModel.getLevel(index)) * unitHeight);
             final float rightTop = round(trapezoidBottom
-                    - requireNonNull(mViewModel.levels().get(index + 1)) * unitHeight);
+                    - requireNonNull(mViewModel.getLevel(index + 1)) * unitHeight);
             trapezoidPath.reset();
             trapezoidPath.moveTo(mTrapezoidSlots[index].mLeft, trapezoidBottom);
             trapezoidPath.lineTo(mTrapezoidSlots[index].mLeft, leftTop);
@@ -574,22 +537,6 @@
             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;
         }
     }
 
@@ -617,14 +564,19 @@
 
     private static boolean isTrapezoidValid(
             @NonNull BatteryChartViewModel viewModel, int trapezoidIndex) {
-        return viewModel.levels().get(trapezoidIndex) != null
-                && viewModel.levels().get(trapezoidIndex + 1) != null;
+        return viewModel.getLevel(trapezoidIndex) != null
+                && viewModel.getLevel(trapezoidIndex + 1) != null;
+    }
+
+    private static boolean isTrapezoidIndexValid(
+            @NonNull BatteryChartViewModel viewModel, int trapezoidIndex) {
+        return viewModel != null
+                && trapezoidIndex >= 0
+                && trapezoidIndex < viewModel.size() - 1;
     }
 
     private static boolean isValidToDraw(BatteryChartViewModel viewModel, int trapezoidIndex) {
-        return viewModel != null
-                && trapezoidIndex >= 0
-                && trapezoidIndex < viewModel.size() - 1
+        return isTrapezoidIndexValid(viewModel, trapezoidIndex)
                 && isTrapezoidValid(viewModel, trapezoidIndex);
     }
 
@@ -645,27 +597,61 @@
                 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<AccessibilityServiceInfo> 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;
+    private class BatteryChartAccessibilityNodeProvider extends AccessibilityNodeProvider {
+        @Override
+        public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) {
+            if (virtualViewId == AccessibilityNodeProvider.HOST_VIEW_ID) {
+                final AccessibilityNodeInfo hostInfo =
+                        new AccessibilityNodeInfo(BatteryChartView.this);
+                for (int index = 0; index < mViewModel.size() - 1; index++) {
+                    hostInfo.addChild(BatteryChartView.this, index);
                 }
+                return hostInfo;
+            }
+            final int index = virtualViewId;
+            if (!isTrapezoidIndexValid(mViewModel, index)) {
+                Log.w(TAG, "Invalid virtual view id:" + index);
+                return null;
+            }
+            final AccessibilityNodeInfo childInfo =
+                    new AccessibilityNodeInfo(BatteryChartView.this, index);
+            onInitializeAccessibilityNodeInfo(childInfo);
+            childInfo.setClickable(isValidToDraw(mViewModel, index));
+            childInfo.setText(mViewModel.getFullText(index));
+            childInfo.setContentDescription(mViewModel.getFullText(index));
+
+            final Rect bounds = new Rect();
+            getBoundsOnScreen(bounds, true);
+            final int hostLeft = bounds.left;
+            bounds.left = round(hostLeft + mTrapezoidSlots[index].mLeft);
+            bounds.right = round(hostLeft + mTrapezoidSlots[index].mRight);
+            childInfo.setBoundsInScreen(bounds);
+            return childInfo;
+        }
+
+        @Override
+        public boolean performAction(int virtualViewId, int action,
+                @Nullable Bundle arguments) {
+            if (virtualViewId == AccessibilityNodeProvider.HOST_VIEW_ID) {
+                return performAccessibilityAction(action, arguments);
+            }
+            switch (action) {
+                case AccessibilityNodeInfo.ACTION_CLICK:
+                    onTrapezoidClicked(BatteryChartView.this, virtualViewId);
+                    return true;
+
+                case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS:
+                    return sendAccessibilityEvent(virtualViewId,
+                            AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
+
+                case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS:
+                    return sendAccessibilityEvent(virtualViewId,
+                            AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED);
+
+                default:
+                    return performAccessibilityAction(action, arguments);
             }
         }
-        return false;
     }
 
     // A container class for each trapezoid left and right location.
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryChartViewModel.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryChartViewModel.java
index ac01bfd..f58d241 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryChartViewModel.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryChartViewModel.java
@@ -19,6 +19,7 @@
 import androidx.annotation.NonNull;
 import androidx.core.util.Preconditions;
 
+import java.util.Arrays;
 import java.util.List;
 import java.util.Locale;
 import java.util.Objects;
@@ -38,34 +39,59 @@
         CENTER_OF_TRAPEZOIDS,
     }
 
+    interface LabelTextGenerator {
+        /** Generate the label text. The text may be abbreviated to save space. */
+        String generateText(List<Long> timestamps, int index);
+
+        /** Generate the full text for accessibility. */
+        String generateFullText(List<Long> timestamps, int index);
+    }
+
     private final List<Integer> mLevels;
-    private final List<String> mTexts;
+    private final List<Long> mTimestamps;
     private final AxisLabelPosition mAxisLabelPosition;
+    private final LabelTextGenerator mLabelTextGenerator;
+    private final String[] mTexts;
+    private final String[] mFullTexts;
+
     private int mSelectedIndex = SELECTED_INDEX_ALL;
 
-    BatteryChartViewModel(
-            @NonNull List<Integer> levels, @NonNull List<String> texts,
-            @NonNull AxisLabelPosition axisLabelPosition) {
+    BatteryChartViewModel(@NonNull List<Integer> levels, @NonNull List<Long> timestamps,
+            @NonNull AxisLabelPosition axisLabelPosition,
+            @NonNull LabelTextGenerator labelTextGenerator) {
         Preconditions.checkArgument(
-                levels.size() == texts.size() && levels.size() >= MIN_LEVELS_DATA_SIZE,
+                levels.size() == timestamps.size() && levels.size() >= MIN_LEVELS_DATA_SIZE,
                 String.format(Locale.ENGLISH,
-                        "Invalid BatteryChartViewModel levels.size: %d, texts.size: %d.",
-                        levels.size(), texts.size()));
+                        "Invalid BatteryChartViewModel levels.size: %d, timestamps.size: %d.",
+                        levels.size(), timestamps.size()));
         mLevels = levels;
-        mTexts = texts;
+        mTimestamps = timestamps;
         mAxisLabelPosition = axisLabelPosition;
+        mLabelTextGenerator = labelTextGenerator;
+        mTexts = new String[size()];
+        mFullTexts = new String[size()];
     }
 
     public int size() {
         return mLevels.size();
     }
 
-    public List<Integer> levels() {
-        return mLevels;
+    public Integer getLevel(int index) {
+        return mLevels.get(index);
     }
 
-    public List<String> texts() {
-        return mTexts;
+    public String getText(int index) {
+        if (mTexts[index] == null) {
+            mTexts[index] = mLabelTextGenerator.generateText(mTimestamps, index);
+        }
+        return mTexts[index];
+    }
+
+    public String getFullText(int index) {
+        if (mFullTexts[index] == null) {
+            mFullTexts[index] = mLabelTextGenerator.generateFullText(mTimestamps, index);
+        }
+        return mFullTexts[index];
     }
 
     public AxisLabelPosition axisLabelPosition() {
@@ -82,7 +108,7 @@
 
     @Override
     public int hashCode() {
-        return Objects.hash(mLevels, mTexts, mSelectedIndex, mAxisLabelPosition);
+        return Objects.hash(mLevels, mTimestamps, mSelectedIndex, mAxisLabelPosition);
     }
 
     @Override
@@ -94,16 +120,26 @@
         }
         final BatteryChartViewModel batteryChartViewModel = (BatteryChartViewModel) other;
         return Objects.equals(mLevels, batteryChartViewModel.mLevels)
-                && Objects.equals(mTexts, batteryChartViewModel.mTexts)
+                && Objects.equals(mTimestamps, batteryChartViewModel.mTimestamps)
                 && mAxisLabelPosition == batteryChartViewModel.mAxisLabelPosition
                 && mSelectedIndex == batteryChartViewModel.mSelectedIndex;
     }
 
     @Override
     public String toString() {
-        return String.format(Locale.ENGLISH,
-                "levels: %s,\ntexts: %s,\naxisLabelPosition: %s, selectedIndex: %d",
-                Objects.toString(mLevels), Objects.toString(mTexts), mAxisLabelPosition,
-                mSelectedIndex);
+        // Generate all the texts and full texts.
+        for (int i = 0; i < size(); i++) {
+            getText(i);
+            getFullText(i);
+        }
+
+        return new StringBuilder()
+                .append("levels: " + Objects.toString(mLevels))
+                .append(", timestamps: " + Objects.toString(mTimestamps))
+                .append(", texts: " + Arrays.toString(mTexts))
+                .append(", fullTexts: " + Arrays.toString(mFullTexts))
+                .append(", axisLabelPosition: " + mAxisLabelPosition)
+                .append(", selectedIndex: " + mSelectedIndex)
+                .toString();
     }
 }
diff --git a/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java b/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java
index 125f879..f493ece 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java
@@ -18,6 +18,7 @@
 
 import static com.android.settings.fuelgauge.batteryusage.ConvertUtils.utcToLocalTime;
 
+import android.app.settings.SettingsEnums;
 import android.content.ContentValues;
 import android.content.Context;
 import android.os.AsyncTask;
@@ -36,6 +37,7 @@
 import com.android.settings.Utils;
 import com.android.settings.fuelgauge.BatteryUtils;
 import com.android.settings.overlay.FeatureFactory;
+import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
 import com.android.settingslib.fuelgauge.BatteryStatus;
 
 import java.time.Duration;
@@ -354,10 +356,25 @@
         insertDailyUsageDiffData(hourlyBatteryLevelsPerDay, resultMap);
         // Insert diff data [SELECTED_INDEX_ALL][SELECTED_INDEX_ALL].
         insertAllUsageDiffData(resultMap);
+        // Compute the apps number before purge. Must put before purgeLowPercentageAndFakeData.
+        final int countOfAppBeforePurge = getCountOfApps(resultMap);
         purgeLowPercentageAndFakeData(context, resultMap);
+        // Compute the apps number after purge. Must put after purgeLowPercentageAndFakeData.
+        final int countOfAppAfterPurge = getCountOfApps(resultMap);
         if (!isUsageMapValid(resultMap, hourlyBatteryLevelsPerDay)) {
             return null;
         }
+
+        final MetricsFeatureProvider metricsFeatureProvider =
+                FeatureFactory.getFactory(context).getMetricsFeatureProvider();
+        metricsFeatureProvider.action(
+                context,
+                SettingsEnums.ACTION_BATTERY_USAGE_SHOWN_APP_COUNT,
+                countOfAppAfterPurge);
+        metricsFeatureProvider.action(
+                context,
+                SettingsEnums.ACTION_BATTERY_USAGE_HIDDEN_APP_COUNT,
+                countOfAppBeforePurge - countOfAppAfterPurge);
         return resultMap;
     }
 
@@ -933,6 +950,15 @@
         return calendar.getTimeInMillis();
     }
 
+    private static int getCountOfApps(final Map<Integer, Map<Integer, BatteryDiffData>> resultMap) {
+        final BatteryDiffData diffDataList =
+                resultMap.get(SELECTED_INDEX_ALL).get(SELECTED_INDEX_ALL);
+        return diffDataList == null
+                ? 0
+                : diffDataList.getAppDiffEntryList().size()
+                        + diffDataList.getSystemDiffEntryList().size();
+    }
+
     private static boolean contains(String target, Set<CharSequence> packageNames) {
         if (target != null && packageNames != null) {
             for (CharSequence packageName : packageNames) {
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerTest.java
index 20af849..26e0f50 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerTest.java
@@ -19,6 +19,7 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.atLeast;
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.never;
@@ -173,22 +174,33 @@
 
     @Test
     public void setBatteryChartViewModel_6Hours() {
+        reset(mHourlyChartView);
         mBatteryChartPreferenceController.setBatteryHistoryMap(createBatteryHistoryMap(6));
 
         verify(mDailyChartView, atLeastOnce()).setVisibility(View.GONE);
         verify(mHourlyChartView, atLeastOnce()).setVisibility(View.VISIBLE);
-        verify(mHourlyChartView).setViewModel(new BatteryChartViewModel(
+        // Ignore fast refresh ui from the data processor callback.
+        verify(mHourlyChartView, atLeast(0)).setViewModel(null);
+        verify(mHourlyChartView, atLeastOnce()).setViewModel(new BatteryChartViewModel(
                 List.of(100, 97, 95),
-                List.of("8 AM", "10 AM", "12 PM"),
-                BatteryChartViewModel.AxisLabelPosition.BETWEEN_TRAPEZOIDS));
+                List.of(1619251200000L /* 8 AM */,
+                        1619258400000L /* 10 AM */,
+                        1619265600000L /* 12 PM */),
+                BatteryChartViewModel.AxisLabelPosition.BETWEEN_TRAPEZOIDS,
+                mBatteryChartPreferenceController.mHourlyChartLabelTextGenerator));
     }
 
     @Test
     public void setBatteryChartViewModel_60Hours() {
         BatteryChartViewModel expectedDailyViewModel = new BatteryChartViewModel(
                 List.of(100, 83, 59, 41),
-                List.of("Sat", "Sun", "Mon", "Mon"),
-                BatteryChartViewModel.AxisLabelPosition.CENTER_OF_TRAPEZOIDS);
+                // "Sat", "Sun", "Mon", "Mon"
+                List.of(1619251200000L /* Sat */,
+                        1619308800000L /* Sun */,
+                        1619395200000L /* Mon */,
+                        1619460000000L /* Mon */),
+                BatteryChartViewModel.AxisLabelPosition.CENTER_OF_TRAPEZOIDS,
+                mBatteryChartPreferenceController.mDailyChartLabelTextGenerator);
 
         mBatteryChartPreferenceController.setBatteryHistoryMap(createBatteryHistoryMap(60));
 
@@ -208,9 +220,17 @@
         verify(mDailyChartView).setViewModel(expectedDailyViewModel);
         verify(mHourlyChartView).setViewModel(new BatteryChartViewModel(
                 List.of(100, 97, 95, 93, 91, 89, 87, 85, 83),
-                List.of("8 AM", "10 AM", "12 PM", "2 PM", "4 PM", "6 PM", "8 PM", "10 PM",
-                        "12 AM"),
-                BatteryChartViewModel.AxisLabelPosition.BETWEEN_TRAPEZOIDS));
+                List.of(1619251200000L /* 8 AM */,
+                        1619258400000L /* 10 AM */,
+                        1619265600000L /* 12 PM */,
+                        1619272800000L /* 2 PM */,
+                        1619280000000L /* 4 PM */,
+                        1619287200000L /* 6 PM */,
+                        1619294400000L /* 8 PM */,
+                        1619301600000L /* 10 PM */,
+                        1619308800000L /* 12 AM */),
+                BatteryChartViewModel.AxisLabelPosition.BETWEEN_TRAPEZOIDS,
+                mBatteryChartPreferenceController.mHourlyChartLabelTextGenerator));
 
         reset(mDailyChartView);
         reset(mHourlyChartView);
@@ -224,9 +244,21 @@
         verify(mDailyChartView).setViewModel(expectedDailyViewModel);
         BatteryChartViewModel expectedHourlyViewModel = new BatteryChartViewModel(
                 List.of(83, 81, 79, 77, 75, 73, 71, 69, 67, 65, 63, 61, 59),
-                List.of("12 AM", "2 AM", "4 AM", "6 AM", "8 AM", "10 AM", "12 PM", "2 PM",
-                        "4 PM", "6 PM", "8 PM", "10 PM", "12 AM"),
-                BatteryChartViewModel.AxisLabelPosition.BETWEEN_TRAPEZOIDS);
+                List.of(1619308800000L /* 12 AM */,
+                        1619316000000L /* 2 AM */,
+                        1619323200000L /* 4 AM */,
+                        1619330400000L /* 6 AM */,
+                        1619337600000L /* 8 AM */,
+                        1619344800000L /* 10 AM */,
+                        1619352000000L /* 12 PM */,
+                        1619359200000L /* 2 PM */,
+                        1619366400000L /* 4 PM */,
+                        1619373600000L /* 6 PM */,
+                        1619380800000L /* 8 PM */,
+                        1619388000000L /* 10 PM */,
+                        1619395200000L /* 12 AM */),
+                BatteryChartViewModel.AxisLabelPosition.BETWEEN_TRAPEZOIDS,
+                mBatteryChartPreferenceController.mHourlyChartLabelTextGenerator);
         expectedHourlyViewModel.setSelectedIndex(6);
         verify(mHourlyChartView).setViewModel(expectedHourlyViewModel);
 
@@ -243,9 +275,18 @@
         verify(mDailyChartView).setViewModel(expectedDailyViewModel);
         verify(mHourlyChartView).setViewModel(new BatteryChartViewModel(
                 List.of(59, 57, 55, 53, 51, 49, 47, 45, 43, 41),
-                List.of("12 AM", "2 AM", "4 AM", "6 AM", "8 AM", "10 AM", "12 PM", "2 PM",
-                        "4 PM", "6 PM"),
-                BatteryChartViewModel.AxisLabelPosition.BETWEEN_TRAPEZOIDS));
+                List.of(1619395200000L /* 12 AM */,
+                        1619402400000L /* 2 AM */,
+                        1619409600000L /* 4 AM */,
+                        1619416800000L /* 6 AM */,
+                        1619424000000L /* 8 AM */,
+                        1619431200000L /* 10 AM */,
+                        1619438400000L /* 12 PM */,
+                        1619445600000L /* 2 PM */,
+                        1619452800000L /* 4 PM */,
+                        1619460000000L /* 6 PM */),
+                BatteryChartViewModel.AxisLabelPosition.BETWEEN_TRAPEZOIDS,
+                mBatteryChartPreferenceController.mHourlyChartLabelTextGenerator));
     }
 
     @Test
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 8a43087..5213199 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 @@
 
 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.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
 
-import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
 import java.util.Locale;
 
@@ -54,10 +46,6 @@
     private PowerUsageFeatureProvider mPowerUsageFeatureProvider;
 
     @Mock
-    private AccessibilityServiceInfo mMockAccessibilityServiceInfo;
-    @Mock
-    private AccessibilityManager mMockAccessibilityManager;
-    @Mock
     private View mMockView;
 
     @Before
@@ -69,42 +57,14 @@
         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<AccessibilityServiceInfo>())
-                .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
     public void onClick_invokesCallback() {
         final int originalSelectedIndex = 2;
         BatteryChartViewModel batteryChartViewModel = new BatteryChartViewModel(
-                List.of(90, 80, 70, 60), List.of("", "", "", ""),
-                BatteryChartViewModel.AxisLabelPosition.BETWEEN_TRAPEZOIDS);
+                List.of(90, 80, 70, 60), List.of(0L, 0L, 0L, 0L),
+                BatteryChartViewModel.AxisLabelPosition.BETWEEN_TRAPEZOIDS, null);
         batteryChartViewModel.setSelectedIndex(originalSelectedIndex);
         mBatteryChartView.setViewModel(batteryChartViewModel);
         for (int i = 0; i < mBatteryChartView.mTrapezoidSlots.length; i++) {
@@ -130,116 +90,4 @@
         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<AccessibilityServiceInfo>())
-                .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<Integer> levels = new ArrayList<Integer>();
-        final List<String> texts = new ArrayList<String>();
-        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);
-    }
 }
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java
index 883b0e7..84f9310 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java
@@ -18,9 +18,12 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.app.settings.SettingsEnums;
 import android.content.ContentValues;
 import android.content.Context;
 import android.text.format.DateUtils;
@@ -28,6 +31,7 @@
 import com.android.settings.fuelgauge.BatteryUtils;
 import com.android.settings.fuelgauge.PowerUsageFeatureProvider;
 import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -52,6 +56,7 @@
     private Context mContext;
 
     private FakeFeatureFactory mFeatureFactory;
+    private MetricsFeatureProvider mMetricsFeatureProvider;
     private PowerUsageFeatureProvider mPowerUsageFeatureProvider;
 
     @Before
@@ -61,6 +66,7 @@
 
         mContext = spy(RuntimeEnvironment.application);
         mFeatureFactory = FakeFeatureFactory.setupForTest();
+        mMetricsFeatureProvider = mFeatureFactory.metricsFeatureProvider;
         mPowerUsageFeatureProvider = mFeatureFactory.powerUsageFeatureProvider;
     }
 
@@ -75,6 +81,10 @@
         assertThat(DataProcessor.getBatteryLevelData(
                 mContext, /*handler=*/ null, new HashMap<>(), /*asyncResponseDelegate=*/ null))
                 .isNull();
+        verify(mMetricsFeatureProvider, never())
+                .action(mContext, SettingsEnums.ACTION_BATTERY_USAGE_SHOWN_APP_COUNT);
+        verify(mMetricsFeatureProvider, never())
+                .action(mContext, SettingsEnums.ACTION_BATTERY_USAGE_HIDDEN_APP_COUNT);
     }
 
     @Test
@@ -88,6 +98,10 @@
         assertThat(DataProcessor.getBatteryLevelData(
                 mContext, /*handler=*/ null, batteryHistoryMap, /*asyncResponseDelegate=*/ null))
                 .isNull();
+        verify(mMetricsFeatureProvider, never())
+                .action(mContext, SettingsEnums.ACTION_BATTERY_USAGE_SHOWN_APP_COUNT);
+        verify(mMetricsFeatureProvider, never())
+                .action(mContext, SettingsEnums.ACTION_BATTERY_USAGE_HIDDEN_APP_COUNT);
     }
 
     @Test
@@ -421,6 +435,10 @@
 
         assertThat(DataProcessor.getBatteryUsageMap(
                 mContext, hourlyBatteryLevelsPerDay, new HashMap<>())).isNull();
+        verify(mMetricsFeatureProvider, never())
+                .action(mContext, SettingsEnums.ACTION_BATTERY_USAGE_SHOWN_APP_COUNT);
+        verify(mMetricsFeatureProvider, never())
+                .action(mContext, SettingsEnums.ACTION_BATTERY_USAGE_HIDDEN_APP_COUNT);
     }
 
     @Test
@@ -549,6 +567,10 @@
                 resultDiffData.getSystemDiffEntryList().get(0), currentUserId, /*uid=*/ 3L,
                 ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY, /*consumePercentage=*/ 25.0,
                 /*foregroundUsageTimeInMs=*/ 50, /*backgroundUsageTimeInMs=*/ 60);
+        verify(mMetricsFeatureProvider)
+                .action(mContext, SettingsEnums.ACTION_BATTERY_USAGE_SHOWN_APP_COUNT, 3);
+        verify(mMetricsFeatureProvider)
+                .action(mContext, SettingsEnums.ACTION_BATTERY_USAGE_HIDDEN_APP_COUNT, 0);
     }
 
     @Test
@@ -640,6 +662,10 @@
                 /*backgroundUsageTimeInMs=*/ 0);
         assertThat(resultMap.get(0).get(0)).isNotNull();
         assertThat(resultMap.get(0).get(DataProcessor.SELECTED_INDEX_ALL)).isNotNull();
+        verify(mMetricsFeatureProvider)
+                .action(mContext, SettingsEnums.ACTION_BATTERY_USAGE_SHOWN_APP_COUNT, 2);
+        verify(mMetricsFeatureProvider)
+                .action(mContext, SettingsEnums.ACTION_BATTERY_USAGE_HIDDEN_APP_COUNT, 0);
     }
 
     @Test
@@ -701,6 +727,10 @@
                 .isEqualTo(entry.mConsumePower * ratio);
         assertThat(resultMap.get(0).get(0)).isNotNull();
         assertThat(resultMap.get(0).get(DataProcessor.SELECTED_INDEX_ALL)).isNotNull();
+        verify(mMetricsFeatureProvider)
+                .action(mContext, SettingsEnums.ACTION_BATTERY_USAGE_SHOWN_APP_COUNT, 1);
+        verify(mMetricsFeatureProvider)
+                .action(mContext, SettingsEnums.ACTION_BATTERY_USAGE_HIDDEN_APP_COUNT, 0);
     }
 
     @Test
@@ -772,6 +802,10 @@
                 resultDiffData.getAppDiffEntryList().get(0), currentUserId, /*uid=*/ 2L,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*consumePercentage=*/ 50.0,
                 /*foregroundUsageTimeInMs=*/ 10, /*backgroundUsageTimeInMs=*/ 20);
+        verify(mMetricsFeatureProvider)
+                .action(mContext, SettingsEnums.ACTION_BATTERY_USAGE_SHOWN_APP_COUNT, 1);
+        verify(mMetricsFeatureProvider)
+                .action(mContext, SettingsEnums.ACTION_BATTERY_USAGE_HIDDEN_APP_COUNT, 1);
     }
 
     @Test
@@ -843,6 +877,10 @@
         assertThat(resultEntry.mBackgroundUsageTimeInMs).isEqualTo(20);
         resultEntry = resultDiffData.getAppDiffEntryList().get(1);
         assertThat(resultEntry.mBackgroundUsageTimeInMs).isEqualTo(0);
+        verify(mMetricsFeatureProvider)
+                .action(mContext, SettingsEnums.ACTION_BATTERY_USAGE_SHOWN_APP_COUNT, 2);
+        verify(mMetricsFeatureProvider)
+                .action(mContext, SettingsEnums.ACTION_BATTERY_USAGE_HIDDEN_APP_COUNT, 0);
     }
 
     private static Map<Long, Map<String, BatteryHistEntry>> createHistoryMap(