Refresh category title by different time slot condition

Bug: 177406865
Bug: 185187729
Test: make SettingsRoboTests
Test: make SettingsGoogleRoboTests
Change-Id: Ib124e1cfb9549f838540ff547bc616049f65180d
diff --git a/res/layout/preference_expand_divider.xml b/res/layout/preference_expand_divider.xml
index 685ec0e..164419a 100644
--- a/res/layout/preference_expand_divider.xml
+++ b/res/layout/preference_expand_divider.xml
@@ -38,7 +38,6 @@
         android:paddingEnd="4dp"
         android:singleLine="true"
         android:textAlignment="viewStart"
-        android:text="@string/battery_system_usage_for_past_24"
         style="@style/PreferenceCategoryTitleTextStyle"/>
 
     <ImageView
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 213b9e1..19f892e 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -6442,9 +6442,9 @@
     <!-- [CHAR_LIMIT=NONE] Battery system usage section header for past 24 hour -->
     <string name="battery_system_usage_for_past_24">System usage for past 24 hr</string>
     <!-- [CHAR_LIMIT=NONE] Battery system usage section header -->
-    <string name="battery_system_usage_for">System usage for</string>
+    <string name="battery_system_usage_for">System usage for <xliff:g id="slot">%s</xliff:g></string>
     <!-- [CHAR_LIMIT=NONE] Battery app usage section header -->
-    <string name="battery_app_usage_for">App usage for</string>
+    <string name="battery_app_usage_for">App usage for <xliff:g id="slot">%s</xliff:g></string>
     <!-- [CHAR_LIMIT=NONE] Battery usage section header for a specific time slot -->
     <string name="battery_usage_time_am">am</string>
     <!-- [CHAR_LIMIT=NONE] Battery usage section header for a specific time slot -->
diff --git a/src/com/android/settings/fuelgauge/BatteryChartPreferenceController.java b/src/com/android/settings/fuelgauge/BatteryChartPreferenceController.java
index 7131f28..649b410 100644
--- a/src/com/android/settings/fuelgauge/BatteryChartPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/BatteryChartPreferenceController.java
@@ -65,6 +65,8 @@
     @VisibleForTesting PreferenceGroup mAppListPrefGroup;
     @VisibleForTesting BatteryChartView mBatteryChartView;
     @VisibleForTesting ExpandDividerPreference mExpandDividerPreference;
+    @VisibleForTesting CategoryTitleType mCategoryTitleType =
+        CategoryTitleType.TYPE_UNKNOWN;
 
     @VisibleForTesting int[] mBatteryHistoryLevels;
     @VisibleForTesting long[] mBatteryHistoryKeys;
@@ -84,6 +86,14 @@
     @VisibleForTesting
     final List<BatteryDiffEntry> mSystemEntries = new ArrayList<>();
 
+    /** Which component data will be shown in the screen. */
+    enum CategoryTitleType {
+        TYPE_UNKNOWN,
+        TYPE_APP_COMPONENT,
+        TYPE_SYSTEM_COMPONENT,
+        TYPE_ALL_COMPONENTS
+    }
+
     public BatteryChartPreferenceController(
             Context context, String preferenceKey,
             Lifecycle lifecycle, SettingsActivity activity,
@@ -263,11 +273,13 @@
         mHandler.post(() -> {
             removeAndCacheAllPrefs();
             addAllPreferences();
+            refreshCategoryTitle();
         });
         return true;
     }
 
     private void addAllPreferences() {
+        mCategoryTitleType = CategoryTitleType.TYPE_UNKNOWN;
         final List<BatteryDiffEntry> entries =
             mBatteryIndexedMap.get(Integer.valueOf(mTrapezoidIndex));
         if (entries == null) {
@@ -296,6 +308,7 @@
         // Adds app entries to the list if it is not empty.
         if (!appEntries.isEmpty()) {
             addPreferenceToScreen(appEntries);
+            mCategoryTitleType = CategoryTitleType.TYPE_APP_COMPONENT;
         }
         // Adds the expabable divider if we have two sections data.
         if (!appEntries.isEmpty() && !mSystemEntries.isEmpty()) {
@@ -306,6 +319,9 @@
             mExpandDividerPreference.setOrder(
                 mAppListPrefGroup.getPreferenceCount());
             mAppListPrefGroup.addPreference(mExpandDividerPreference);
+            mCategoryTitleType = CategoryTitleType.TYPE_ALL_COMPONENTS;
+        } else if (appEntries.isEmpty() && !mSystemEntries.isEmpty()) {
+            mCategoryTitleType = CategoryTitleType.TYPE_SYSTEM_COMPONENT;
         }
         refreshExpandUi();
     }
@@ -386,6 +402,68 @@
     }
 
     @VisibleForTesting
+    void refreshCategoryTitle() {
+        final String slotInformation = getSlotInformation();
+        Log.d(TAG, String.format("refreshCategoryTitle:%s slotInfo:%s",
+            mCategoryTitleType, slotInformation));
+        refreshPreferenceCategoryTitle(slotInformation);
+        refreshExpandableDividerTitle(slotInformation);
+    }
+
+    private void refreshExpandableDividerTitle(String slotInformation) {
+        if (mExpandDividerPreference == null) {
+            return;
+        }
+        mExpandDividerPreference.setTitle(
+            mCategoryTitleType == CategoryTitleType.TYPE_ALL_COMPONENTS
+                ? getSlotInformation(/*isApp=*/ false, slotInformation)
+                : null);
+    }
+
+    private void refreshPreferenceCategoryTitle(String slotInformation) {
+        if (mAppListPrefGroup == null) {
+            return;
+        }
+        switch (mCategoryTitleType) {
+            case TYPE_APP_COMPONENT:
+            case TYPE_ALL_COMPONENTS:
+                mAppListPrefGroup.setTitle(
+                    getSlotInformation(/*isApp=*/ true, slotInformation));
+                break;
+            case TYPE_SYSTEM_COMPONENT:
+                mAppListPrefGroup.setTitle(
+                    getSlotInformation(/*isApp=*/ false, slotInformation));
+                break;
+            default:
+                mAppListPrefGroup.setTitle(R.string.battery_app_usage_for_past_24);
+        }
+    }
+
+    private String getSlotInformation(boolean isApp, String slotInformation) {
+        // Null means we show all information without a specific time slot.
+        if (slotInformation == null) {
+            return isApp
+                ? mPrefContext.getString(R.string.battery_app_usage_for_past_24)
+                : mPrefContext.getString(R.string.battery_system_usage_for_past_24);
+        } else {
+            return isApp
+                ? mPrefContext.getString(R.string.battery_app_usage_for, slotInformation)
+                : mPrefContext.getString(R.string.battery_system_usage_for ,slotInformation);
+        }
+    }
+
+    private String getSlotInformation() {
+        if (mTrapezoidIndex < 0) {
+            return null;
+        }
+        final String fromHour = ConvertUtils.utcToLocalTimeHour(
+            mBatteryHistoryKeys[mTrapezoidIndex * 2]);
+        final String toHour = ConvertUtils.utcToLocalTimeHour(
+            mBatteryHistoryKeys[(mTrapezoidIndex + 1) * 2]);
+        return String.format("%s-%s", fromHour, toHour);
+    }
+
+    @VisibleForTesting
     void setPreferenceSummary(
             PowerGaugePreference preference, BatteryDiffEntry entry) {
         final long foregroundUsageTimeInMs = entry.mForegroundUsageTimeInMs;
diff --git a/src/com/android/settings/fuelgauge/ExpandDividerPreference.java b/src/com/android/settings/fuelgauge/ExpandDividerPreference.java
index 06476df..40536eb 100644
--- a/src/com/android/settings/fuelgauge/ExpandDividerPreference.java
+++ b/src/com/android/settings/fuelgauge/ExpandDividerPreference.java
@@ -71,9 +71,10 @@
         }
     }
 
-    void setTitle(String titleContent) {
+    void setTitle(final String titleContent) {
         if (mTextView != null) {
-            mTextView.setText(titleContent);
+            mTextView.postDelayed(
+                () -> mTextView.setText(titleContent), 50);
         }
     }
 
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryChartPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryChartPreferenceControllerTest.java
index 9f0ffb0..9cf45ea 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryChartPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryChartPreferenceControllerTest.java
@@ -52,8 +52,10 @@
 import java.util.Arrays;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.Locale;
 import java.util.List;
 import java.util.Map;
+import java.util.TimeZone;
 
 @RunWith(RobolectricTestRunner.class)
 public final class BatteryChartPreferenceControllerTest {
@@ -68,6 +70,7 @@
     @Mock private BatteryHistEntry mBatteryHistEntry;
     @Mock private BatteryChartView mBatteryChartView;
     @Mock private PowerGaugePreference mPowerGaugePreference;
+    @Mock private ExpandDividerPreference mExpandDividerPreference;
     @Mock private BatteryUtils mBatteryUtils;
 
     private Context mContext;
@@ -480,6 +483,94 @@
         assertThat(mBatteryChartPreferenceController.mPreferenceCache).hasSize(1);
     }
 
+    @Test
+    public void testRefreshCategoryTitle_appComponent_setHourIntoPreferenceTitle() {
+        setUpBatteryHistoryKeys();
+        mBatteryChartPreferenceController.mCategoryTitleType =
+            BatteryChartPreferenceController.CategoryTitleType.TYPE_APP_COMPONENT;
+        mBatteryChartPreferenceController.mExpandDividerPreference =
+            mExpandDividerPreference;
+        // Simulates select the first slot.
+        mBatteryChartPreferenceController.mTrapezoidIndex = 0;
+
+        mBatteryChartPreferenceController.refreshCategoryTitle();
+
+        final ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
+        // Verifies the title in the preference group.
+        verify(mAppListGroup).setTitle(captor.capture());
+        assertThat(captor.getValue())
+            .isEqualTo("App usage for 4 pm-7 am");
+        verify(mExpandDividerPreference).setTitle(null);
+    }
+
+    @Test
+    public void testRefreshCategoryTitle_systemComponent_setHourIntoPreferenceTitle() {
+        setUpBatteryHistoryKeys();
+        mBatteryChartPreferenceController.mCategoryTitleType =
+            BatteryChartPreferenceController.CategoryTitleType.TYPE_SYSTEM_COMPONENT;
+        mBatteryChartPreferenceController.mExpandDividerPreference =
+            mExpandDividerPreference;
+        // Simulates select the first slot.
+        mBatteryChartPreferenceController.mTrapezoidIndex = 0;
+
+        mBatteryChartPreferenceController.refreshCategoryTitle();
+
+        final ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
+        // Verifies the title in the preference group.
+        verify(mAppListGroup).setTitle(captor.capture());
+        assertThat(captor.getValue())
+            .isEqualTo("System usage for 4 pm-7 am");
+        verify(mExpandDividerPreference).setTitle(null);
+    }
+
+    @Test
+    public void testRefreshCategoryTitle_allComponents_setHourIntoBothTitleTextView() {
+        setUpBatteryHistoryKeys();
+        mBatteryChartPreferenceController.mCategoryTitleType =
+            BatteryChartPreferenceController.CategoryTitleType.TYPE_ALL_COMPONENTS;
+        mBatteryChartPreferenceController.mExpandDividerPreference =
+            mExpandDividerPreference;
+        // Simulates select the first slot.
+        mBatteryChartPreferenceController.mTrapezoidIndex = 0;
+
+        mBatteryChartPreferenceController.refreshCategoryTitle();
+
+        ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
+        // Verifies the title in the preference group.
+        verify(mAppListGroup).setTitle(captor.capture());
+        assertThat(captor.getValue())
+            .isEqualTo("App usage for 4 pm-7 am");
+        // Verifies the title in the expandable divider.
+        captor = ArgumentCaptor.forClass(String.class);
+        verify(mExpandDividerPreference).setTitle(captor.capture());
+        assertThat(captor.getValue())
+            .isEqualTo("System usage for 4 pm-7 am");
+    }
+
+    @Test
+    public void testRefreshCategoryTitle_allComponents_setLast24HrIntoBothTitleTextView() {
+        mBatteryChartPreferenceController.mCategoryTitleType =
+            BatteryChartPreferenceController.CategoryTitleType.TYPE_ALL_COMPONENTS;
+        mBatteryChartPreferenceController.mExpandDividerPreference =
+            mExpandDividerPreference;
+        // Simulates select all condition.
+        mBatteryChartPreferenceController.mTrapezoidIndex =
+            BatteryChartView.SELECTED_INDEX_ALL;
+
+        mBatteryChartPreferenceController.refreshCategoryTitle();
+
+        ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
+        // Verifies the title in the preference group.
+        verify(mAppListGroup).setTitle(captor.capture());
+        assertThat(captor.getValue())
+            .isEqualTo("App usage for past 24 hr");
+        // Verifies the title in the expandable divider.
+        captor = ArgumentCaptor.forClass(String.class);
+        verify(mExpandDividerPreference).setTitle(captor.capture());
+        assertThat(captor.getValue())
+            .isEqualTo("System usage for past 24 hr");
+    }
+
     private static Map<Long, List<BatteryHistEntry>> createBatteryHistoryMap(int size) {
         final Map<Long, List<BatteryHistEntry>> batteryHistoryMap = new HashMap<>();
         for (int index = 0; index < size; index++) {
@@ -497,4 +588,13 @@
             mContext, foregroundUsageTimeInMs, backgroundUsageTimeInMs,
             /*consumePower=*/ 0, mBatteryHistEntry);
     }
+
+    private void setUpBatteryHistoryKeys() {
+        mBatteryChartPreferenceController.mBatteryHistoryKeys =
+            new long[] {1619196786769L, 0L, 1619247636826L};
+        ConvertUtils.utcToLocalTimeHour(/*timestamp=*/ 0);
+        // Simulates the locale in GMT.
+        ConvertUtils.sSimpleDateFormatForHour
+             .setTimeZone(TimeZone.getTimeZone("GMT"));
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/ConvertUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/ConvertUtilsTest.java
index 12913a2..c9c9f3b 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/ConvertUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/ConvertUtilsTest.java
@@ -263,10 +263,10 @@
           // Invokes the method first to create the SimpleDateFormat.
           ConvertUtils.utcToLocalTime(/*timestamp=*/ 0);
           ConvertUtils.sSimpleDateFormat
-              .setTimeZone(TimeZone.getTimeZone("GMT"));
+              .setTimeZone(TimeZone.getTimeZone("America/Los_Angeles"));
 
           assertThat(ConvertUtils.utcToLocalTime(timestamp))
-              .isEqualTo("Apr 23,2021 16:53:06");
+              .isEqualTo("Apr 23,2021 09:53:06");
     }
 
     @Test
@@ -276,10 +276,10 @@
           // Invokes the method first to create the SimpleDateFormat.
           ConvertUtils.utcToLocalTimeHour(/*timestamp=*/ 0);
           ConvertUtils.sSimpleDateFormatForHour
-              .setTimeZone(TimeZone.getTimeZone("GMT"));
+              .setTimeZone(TimeZone.getTimeZone("America/Los_Angeles"));
 
           assertThat(ConvertUtils.utcToLocalTimeHour(timestamp))
-              .isEqualTo("4 pm");
+              .isEqualTo("9 am");
     }
 
     private static BatteryHistEntry createBatteryHistEntry(
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/ExpandDividerPreferenceTest.java b/tests/robotests/src/com/android/settings/fuelgauge/ExpandDividerPreferenceTest.java
index f9009a1..97af282 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/ExpandDividerPreferenceTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/ExpandDividerPreferenceTest.java
@@ -19,6 +19,7 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.never;
@@ -35,7 +36,7 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.Mock;
+import org.mockito.ArgumentCaptor;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
@@ -46,13 +47,15 @@
     private Context mContext;
     private ExpandDividerPreference mExpandDividerPreference;
 
-    @Mock private ImageView mImageView;
-    @Mock private TextView mTextView;
+    private ImageView mImageView;
+    private TextView mTextView;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         mContext = spy(RuntimeEnvironment.application);
+        mImageView = spy(new ImageView(mContext));
+        mTextView = spy(new TextView(mContext));
         mExpandDividerPreference = new ExpandDividerPreference(mContext);
         doReturn(R.id.expand_title).when(mTextView).getId();
         doReturn(R.id.expand_icon).when(mImageView).getId();
@@ -72,6 +75,9 @@
         mExpandDividerPreference.mTextView = mTextView;
 
         mExpandDividerPreference.setTitle(titleContent);
+        final ArgumentCaptor<Runnable> captor = ArgumentCaptor.forClass(Runnable.class);
+        verify(mTextView).postDelayed(captor.capture(), eq(50L));
+        captor.getValue().run();
         verify(mTextView).setText(titleContent);
     }