Refine startBatteryDetailPage method to support history data

Bug: 177406865
Test: make SettingsRoboTests
Test: make SettingsGoogleRoboTests
Change-Id: Iee3b6b353c4f92bdad37fac55adad58b4f205bf6
diff --git a/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java b/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java
index f28ae00..6d73359 100644
--- a/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java
+++ b/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java
@@ -116,37 +116,82 @@
 
     private String mPackageName;
 
-    /**
-     * Launches battery details page for an individual battery consumer.
-     */
+    // A wrapper class to carry LaunchBatteryDetailPage required arguments.
+    private static final class LaunchBatteryDetailPageArgs {
+        private String mUsagePercent;
+        private String mPackageName;
+        private String mAppLabel;
+        private int mUid;
+        private int mIconId;
+        private int mConsumedPower;
+        private long mForegroundTimeMs;
+        private long mBackgroundTimeMs;
+        private boolean mIsUserEntry;
+    }
+
+    /** Launches battery details page for an individual battery consumer. */
+    public static void startBatteryDetailPage(
+            Activity caller, InstrumentedPreferenceFragment fragment,
+            BatteryDiffEntry diffEntry, String usagePercent) {
+        final BatteryHistEntry histEntry = diffEntry.mBatteryHistEntry;
+        final LaunchBatteryDetailPageArgs launchArgs = new LaunchBatteryDetailPageArgs();
+        // configure the launch argument.
+        launchArgs.mUsagePercent = usagePercent;
+        launchArgs.mPackageName = diffEntry.getPackageName();
+        launchArgs.mAppLabel = diffEntry.getAppLabel();
+        launchArgs.mUid = (int) histEntry.mUid;
+        launchArgs.mIconId = diffEntry.getAppIconId();
+        launchArgs.mConsumedPower = (int) diffEntry.mConsumePower;
+        launchArgs.mForegroundTimeMs = diffEntry.mForegroundUsageTimeInMs;
+        launchArgs.mBackgroundTimeMs = diffEntry.mBackgroundUsageTimeInMs;
+        launchArgs.mIsUserEntry = histEntry.isUserEntry();
+        startBatteryDetailPage(caller, fragment, launchArgs);
+    }
+
+    /** Launches battery details page for an individual battery consumer. */
     public static void startBatteryDetailPage(Activity caller,
             InstrumentedPreferenceFragment fragment, BatteryEntry entry, String usagePercent) {
+        final LaunchBatteryDetailPageArgs launchArgs = new LaunchBatteryDetailPageArgs();
+        // configure the launch argument.
+        launchArgs.mUsagePercent = usagePercent;
+        launchArgs.mPackageName = entry.getDefaultPackageName();
+        launchArgs.mAppLabel = entry.getLabel();
+        launchArgs.mUid = entry.getUid();
+        launchArgs.mIconId = entry.iconId;
+        launchArgs.mConsumedPower = (int) entry.getConsumedPower();
+        launchArgs.mForegroundTimeMs = entry.getTimeInForegroundMs();
+        launchArgs.mBackgroundTimeMs = entry.getTimeInBackgroundMs();
+        launchArgs.mIsUserEntry = entry.isUserEntry();
+        startBatteryDetailPage(caller, fragment, launchArgs);
+    }
+
+    private static void startBatteryDetailPage(Activity caller,
+            InstrumentedPreferenceFragment fragment, LaunchBatteryDetailPageArgs launchArgs) {
         final Bundle args = new Bundle();
-        final long foregroundTimeMs = entry.getTimeInForegroundMs();
-        final long backgroundTimeMs = entry.getTimeInBackgroundMs();
-        final String packageName = entry.getDefaultPackageName();
-        if (packageName == null) {
+        if (launchArgs.mPackageName == null) {
             // populate data for system app
-            args.putString(EXTRA_LABEL, entry.getLabel());
-            args.putInt(EXTRA_ICON_ID, entry.iconId);
+            args.putString(EXTRA_LABEL, launchArgs.mAppLabel);
+            args.putInt(EXTRA_ICON_ID, launchArgs.mIconId);
             args.putString(EXTRA_PACKAGE_NAME, null);
         } else {
             // populate data for normal app
-            args.putString(EXTRA_PACKAGE_NAME, packageName);
+            args.putString(EXTRA_PACKAGE_NAME, launchArgs.mPackageName);
         }
 
-        args.putInt(EXTRA_UID, entry.getUid());
-        args.putLong(EXTRA_BACKGROUND_TIME, backgroundTimeMs);
-        args.putLong(EXTRA_FOREGROUND_TIME, foregroundTimeMs);
-        args.putString(EXTRA_POWER_USAGE_PERCENT, usagePercent);
-        args.putInt(EXTRA_POWER_USAGE_AMOUNT, (int) entry.getConsumedPower());
+        args.putInt(EXTRA_UID, launchArgs.mUid);
+        args.putLong(EXTRA_BACKGROUND_TIME, launchArgs.mBackgroundTimeMs);
+        args.putLong(EXTRA_FOREGROUND_TIME, launchArgs.mForegroundTimeMs);
+        args.putString(EXTRA_POWER_USAGE_PERCENT, launchArgs.mUsagePercent);
+        args.putInt(EXTRA_POWER_USAGE_AMOUNT, launchArgs.mConsumedPower);
+        final int userId = launchArgs.mIsUserEntry ? ActivityManager.getCurrentUser()
+            : UserHandle.getUserId(launchArgs.mUid);
 
         new SubSettingLauncher(caller)
                 .setDestination(AdvancedPowerUsageDetail.class.getName())
                 .setTitleRes(R.string.battery_details_title)
                 .setArguments(args)
                 .setSourceMetricsCategory(fragment.getMetricsCategory())
-                .setUserHandle(new UserHandle(getUserIdToLaunchAdvancePowerUsageDetail(entry)))
+                .setUserHandle(new UserHandle(userId))
                 .launch();
     }
 
diff --git a/src/com/android/settings/fuelgauge/BatteryChartPreferenceController.java b/src/com/android/settings/fuelgauge/BatteryChartPreferenceController.java
index eca2bf3..54591af 100644
--- a/src/com/android/settings/fuelgauge/BatteryChartPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/BatteryChartPreferenceController.java
@@ -58,6 +58,7 @@
     Map<Integer, List<BatteryDiffEntry>> mBatteryIndexedMap;
 
     @VisibleForTesting Context mPrefContext;
+    @VisibleForTesting BatteryUtils mBatteryUtils;
     @VisibleForTesting PreferenceGroup mAppListPrefGroup;
     @VisibleForTesting BatteryChartView mBatteryChartView;
 
@@ -98,6 +99,9 @@
         }
         mHandler.removeCallbacksAndMessages(/*token=*/ null);
         mPreferenceCache.clear();
+        if (mAppListPrefGroup != null) {
+            mAppListPrefGroup.removeAll();
+        }
     }
 
     @Override
@@ -120,6 +124,28 @@
 
     @Override
     public boolean handlePreferenceTreeClick(Preference preference) {
+        if (!(preference instanceof PowerGaugePreference)) {
+            return false;
+        }
+        final PowerGaugePreference powerPref = (PowerGaugePreference) preference;
+        final BatteryDiffEntry diffEntry = powerPref.getBatteryDiffEntry();
+        final BatteryHistEntry histEntry = diffEntry.mBatteryHistEntry;
+        // Checks whether the package is installed or not.
+        boolean isValidPackage = true;
+        if (histEntry.isAppEntry()) {
+            if (mBatteryUtils == null) {
+                mBatteryUtils = BatteryUtils.getInstance(mPrefContext);
+            }
+            isValidPackage = mBatteryUtils.getPackageUid(histEntry.mPackageName)
+                != BatteryUtils.UID_NULL;
+        }
+        Log.d(TAG, String.format("handleClick() label=%s key=%s isValid:%b",
+            diffEntry.getAppLabel(), histEntry.getKey(), isValidPackage));
+        if (isValidPackage) {
+            AdvancedPowerUsageDetail.startBatteryDetailPage(
+                mActivity, mFragment, diffEntry, powerPref.getPercent());
+            return true;
+        }
         return false;
     }
 
@@ -273,6 +299,8 @@
             pref.setTitle(appLabel);
             pref.setOrder(prefIndex);
             pref.setPercent(entry.getPercentOfTotal());
+            // Sets the BatteryDiffEntry to preference for launching detailed page.
+            pref.setBatteryDiffEntry(entry);
             mAppListPrefGroup.addPreference(pref);
             prefIndex++;
         }
diff --git a/src/com/android/settings/fuelgauge/BatteryDiffEntry.java b/src/com/android/settings/fuelgauge/BatteryDiffEntry.java
index 652b54c..92731b7 100644
--- a/src/com/android/settings/fuelgauge/BatteryDiffEntry.java
+++ b/src/com/android/settings/fuelgauge/BatteryDiffEntry.java
@@ -57,6 +57,7 @@
     private UserManager mUserManager;
     private String mDefaultPackageName = null;
 
+    @VisibleForTesting int mAppIconId;
     @VisibleForTesting String mAppLabel = null;
     @VisibleForTesting Drawable mAppIcon = null;
     @VisibleForTesting boolean mIsLoaded = false;
@@ -112,9 +113,16 @@
         return mAppIcon;
     }
 
+    /** Gets the app icon id for this entry. */
+    public int getAppIconId() {
+        loadLabelAndIcon();
+        return mAppIconId;
+    }
+
     /** Gets the searching package name for UID battery type. */
     public String getPackageName() {
-        return mDefaultPackageName;
+        return mDefaultPackageName != null
+            ? mDefaultPackageName : mBatteryHistEntry.mPackageName;
     }
 
     /** Whether the current BatteryDiffEntry is system component or not. */
@@ -153,6 +161,7 @@
                 if (nameAndIconForSystem != null) {
                     mAppLabel = nameAndIconForSystem.name;
                     if (nameAndIconForSystem.iconId != 0) {
+                        mAppIconId = nameAndIconForSystem.iconId;
                         mAppIcon = mContext.getDrawable(nameAndIconForSystem.iconId);
                     }
                 }
@@ -225,8 +234,8 @@
         // Clears BatteryEntry internal cache since we will have another one.
         BatteryEntry.clearUidCache();
         if (nameAndIcon != null) {
-            mAppLabel = getNonNull(mAppLabel, nameAndIcon.name);
-            mAppIcon = getNonNull(mAppIcon, nameAndIcon.icon);
+            mAppLabel = nameAndIcon.name;
+            mAppIcon = nameAndIcon.icon;
             mDefaultPackageName = nameAndIcon.packageName;
             if (mDefaultPackageName != null
                     && !mDefaultPackageName.equals(nameAndIcon.packageName)) {
@@ -265,8 +274,4 @@
         final int appUid = UserHandle.getAppId(uid);
         return appUid >= Process.SYSTEM_UID && appUid < Process.FIRST_APPLICATION_UID;
     }
-
-    private static <T> T getNonNull(T originalObj, T newObj) {
-        return newObj != null ? newObj : originalObj;
-    }
 }
diff --git a/src/com/android/settings/fuelgauge/BatteryEntry.java b/src/com/android/settings/fuelgauge/BatteryEntry.java
index 151284a..f9c4b28 100644
--- a/src/com/android/settings/fuelgauge/BatteryEntry.java
+++ b/src/com/android/settings/fuelgauge/BatteryEntry.java
@@ -113,10 +113,9 @@
                         be.mContext, be.getUid(), sHandler, be,
                         be.mDefaultPackageName, be.name, be.icon);
                 if (nameAndIcon != null) {
-                    be.icon = getNonNull(be.icon, nameAndIcon.icon);
-                    be.name = getNonNull(be.name, nameAndIcon.name);
-                    be.mDefaultPackageName = getNonNull(
-                        be.mDefaultPackageName, nameAndIcon.packageName);
+                    be.icon = nameAndIcon.icon;
+                    be.name = nameAndIcon.name;
+                    be.mDefaultPackageName = nameAndIcon.packageName;
                 }
             }
         }
@@ -589,8 +588,4 @@
         }
         return new NameAndIcon(name, null /* icon */, iconId);
     }
-
-    private static <T> T getNonNull(T originalObj, T newObj) {
-        return newObj != null ? newObj : originalObj;
-    }
 }
diff --git a/src/com/android/settings/fuelgauge/BatteryHistEntry.java b/src/com/android/settings/fuelgauge/BatteryHistEntry.java
index 41fd55f..43078e9 100644
--- a/src/com/android/settings/fuelgauge/BatteryHistEntry.java
+++ b/src/com/android/settings/fuelgauge/BatteryHistEntry.java
@@ -113,6 +113,16 @@
         return mIsValidEntry;
     }
 
+    /** Whether this {@link BatteryHistEntry} is user consumer or not. */
+    public boolean isUserEntry() {
+        return mConsumerType == ConvertUtils.CONSUMER_TYPE_USER_BATTERY;
+    }
+
+    /** Whether this {@link BatteryHistEntry} is app consumer or not. */
+    public boolean isAppEntry() {
+        return mConsumerType == ConvertUtils.CONSUMER_TYPE_UID_BATTERY;
+    }
+
     /** Gets an identifier to represent this {@link BatteryHistEntry}. */
     public String getKey() {
         if (mKey == null) {
diff --git a/src/com/android/settings/fuelgauge/PowerGaugePreference.java b/src/com/android/settings/fuelgauge/PowerGaugePreference.java
index b75acc6..ea79d11 100644
--- a/src/com/android/settings/fuelgauge/PowerGaugePreference.java
+++ b/src/com/android/settings/fuelgauge/PowerGaugePreference.java
@@ -37,6 +37,7 @@
 public class PowerGaugePreference extends AppPreference {
 
     private BatteryEntry mInfo;
+    private BatteryDiffEntry mBatteryDiffEntry;
     private CharSequence mContentDescription;
     private CharSequence mProgress;
     private boolean mShowAnomalyIcon;
@@ -98,10 +99,18 @@
         return mShowAnomalyIcon;
     }
 
+    public void setBatteryDiffEntry(BatteryDiffEntry entry) {
+        mBatteryDiffEntry = entry;
+    }
+
     BatteryEntry getInfo() {
         return mInfo;
     }
 
+    BatteryDiffEntry getBatteryDiffEntry() {
+        return mBatteryDiffEntry;
+    }
+
     @Override
     public void onBindViewHolder(PreferenceViewHolder view) {
         super.onBindViewHolder(view);
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryChartPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryChartPreferenceControllerTest.java
index 66ef2d2..bef250b 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryChartPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryChartPreferenceControllerTest.java
@@ -63,6 +63,7 @@
     @Mock private BatteryHistEntry mBatteryHistEntry;
     @Mock private BatteryChartView mBatteryChartView;
     @Mock private PowerGaugePreference mPowerGaugePreference;
+    @Mock private BatteryUtils mBatteryUtils;
 
     private Context mContext;
     private BatteryDiffEntry mBatteryDiffEntry;
@@ -128,6 +129,12 @@
     }
 
     @Test
+    public void testOnDestroy_removeAllPreferenceFromPreferenceGroup() {
+        mBatteryChartPreferenceController.onDestroy();
+        verify(mAppListGroup).removeAll();
+    }
+
+    @Test
     public void testSetBatteryHistoryMap_createExpectedKeysAndLevels() {
         mBatteryChartPreferenceController.setBatteryHistoryMap(
             createBatteryHistoryMap(/*size=*/ 5));
@@ -266,6 +273,34 @@
         assertThat(pref.getTitle()).isEqualTo(appLabel);
         assertThat(pref.getIcon()).isEqualTo(mDrawable);
         assertThat(pref.getOrder()).isEqualTo(1);
+        assertThat(pref.getBatteryDiffEntry()).isSameInstanceAs(mBatteryDiffEntry);
+    }
+
+    @Test
+    public void testHandlePreferenceTreeClick_notPowerGaugePreference_returnFalse() {
+        assertThat(mBatteryChartPreferenceController.handlePreferenceTreeClick(mAppListGroup))
+            .isFalse();
+    }
+
+    @Test
+    public void testHandlePreferenceTreeClick_validPackageName_returnTrue() {
+        doReturn(false).when(mBatteryHistEntry).isAppEntry();
+        doReturn(mBatteryDiffEntry).when(mPowerGaugePreference).getBatteryDiffEntry();
+
+        assertThat(mBatteryChartPreferenceController.handlePreferenceTreeClick(
+            mPowerGaugePreference)).isTrue();
+    }
+
+    @Test
+    public void testHandlePreferenceTreeClick_appEntryWithInvalidPackage_returnFalse() {
+        mBatteryChartPreferenceController.mBatteryUtils = mBatteryUtils;
+        doReturn(true).when(mBatteryHistEntry).isAppEntry();
+        doReturn(BatteryUtils.UID_NULL).when(mBatteryUtils)
+            .getPackageUid(mBatteryHistEntry.mPackageName);
+        doReturn(mBatteryDiffEntry).when(mPowerGaugePreference).getBatteryDiffEntry();
+
+        assertThat(mBatteryChartPreferenceController.handlePreferenceTreeClick(
+            mPowerGaugePreference)).isFalse();
     }
 
     private Map<Long, List<BatteryHistEntry>> createBatteryHistoryMap(int size) {
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryDiffEntryTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryDiffEntryTest.java
index d1bd19f..c536b06 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryDiffEntryTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryDiffEntryTest.java
@@ -30,6 +30,8 @@
 import android.os.UserManager;
 import android.os.UserHandle;
 
+import com.android.settings.R;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -118,6 +120,7 @@
         final BatteryDiffEntry entry = createBatteryDiffEntry(10, batteryHistEntry);
 
         assertThat(entry.getAppLabel()).isEqualTo("Ambient display");
+        assertThat(entry.getAppIconId()).isEqualTo(R.drawable.ic_settings_aod);
         assertThat(BatteryDiffEntry.sResourceCache).isEmpty();
     }
 
@@ -134,6 +137,7 @@
 
         assertThat(entry.getAppLabel()).isEqualTo("Removed user");
         assertThat(entry.getAppIcon()).isNull();
+        assertThat(entry.getAppIconId()).isEqualTo(0);
         assertThat(BatteryDiffEntry.sResourceCache).isEmpty();
     }
 
@@ -154,6 +158,7 @@
         final BatteryDiffEntry entry = createBatteryDiffEntry(10, batteryHistEntry);
 
         assertThat(entry.getAppLabel()).isEqualTo(expectedAppLabel);
+        assertThat(entry.getAppIconId()).isEqualTo(0);
         assertThat(BatteryDiffEntry.sResourceCache).hasSize(1);
         // Verifies the app label in the cache.
         final BatteryEntry.NameAndIcon nameAndIcon =
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryHistEntryTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryHistEntryTest.java
index 72ccebe..819a223 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryHistEntryTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryHistEntryTest.java
@@ -167,6 +167,30 @@
         assertThat(batteryHistEntry.getKey()).isEqualTo("S|1");
     }
 
+    @Test
+    public void testIsAppEntry_returnExpectedResult() {
+        assertThat(createEntry(ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY).isAppEntry())
+            .isFalse();
+        assertThat(createEntry(ConvertUtils.CONSUMER_TYPE_USER_BATTERY).isAppEntry())
+            .isFalse();
+        assertThat(createEntry(ConvertUtils.CONSUMER_TYPE_UID_BATTERY).isAppEntry())
+            .isTrue();
+    }
+
+    @Test
+    public void testIsUserEntry_returnExpectedResult() {
+        assertThat(createEntry(ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY).isUserEntry())
+            .isFalse();
+        assertThat(createEntry(ConvertUtils.CONSUMER_TYPE_USER_BATTERY).isUserEntry())
+            .isTrue();
+        assertThat(createEntry(ConvertUtils.CONSUMER_TYPE_UID_BATTERY).isUserEntry())
+            .isFalse();
+    }
+
+    private static BatteryHistEntry createEntry(int consumerType) {
+        return new BatteryHistEntry(getContentValuesWithType(consumerType));
+    }
+
     private static ContentValues getContentValuesWithType(int consumerType) {
         final ContentValues values = new ContentValues();
         values.put("consumerType", Integer.valueOf(consumerType));