From db88c994b4b34d0f7fce8d613f6e85378bef4388 Mon Sep 17 00:00:00 2001 From: ykhung Date: Tue, 13 Apr 2021 17:02:34 +0800 Subject: [PATCH] Load application icon and label from package manager if available Bug: 185187669 Test: make SettingsRoboTests Test: make SettingsGoogleRoboTests Change-Id: Id612f0f1db51d538abb41fc711b9350d9a147cb8 --- .../settings/fuelgauge/BatteryDiffEntry.java | 74 +++++++++++++++- .../settings/fuelgauge/ConvertUtils.java | 3 + .../fuelgauge/BatteryDiffEntryTest.java | 86 +++++++++++++++++++ .../settings/fuelgauge/ConvertUtilsTest.java | 6 +- 4 files changed, 166 insertions(+), 3 deletions(-) diff --git a/src/com/android/settings/fuelgauge/BatteryDiffEntry.java b/src/com/android/settings/fuelgauge/BatteryDiffEntry.java index 6c885a19e34..1f61b8b2e1e 100644 --- a/src/com/android/settings/fuelgauge/BatteryDiffEntry.java +++ b/src/com/android/settings/fuelgauge/BatteryDiffEntry.java @@ -13,29 +13,49 @@ */ package com.android.settings.fuelgauge; +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.IPackageManager; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.graphics.drawable.Drawable; +import android.util.Log; + import java.time.Duration; +import java.util.Comparator; /** A container class to carry battery data in a specific time slot. */ public final class BatteryDiffEntry { private static final String TAG = "BatteryDiffEntry"; + /** A comparator for {@link BatteryDiffEntry} based on consumed percentage. */ + public static final Comparator COMPARATOR = + (a, b) -> Double.compare(b.getPercentOfTotal(), a.getPercentOfTotal()); + public long mForegroundUsageTimeInMs; public long mBackgroundUsageTimeInMs; public double mConsumePower; // A BatteryHistEntry corresponding to this diff usage data. public final BatteryHistEntry mBatteryHistEntry; - private double mTotalConsumePower; private double mPercentOfTotal; + private Context mContext; + private String mAppLabel = null; + private Drawable mAppIcon = null; + private boolean mIsLoaded = false; + public BatteryDiffEntry( + Context context, long foregroundUsageTimeInMs, long backgroundUsageTimeInMs, double consumePower, BatteryHistEntry batteryHistEntry) { + mContext = context; + mConsumePower = consumePower; mForegroundUsageTimeInMs = foregroundUsageTimeInMs; mBackgroundUsageTimeInMs = backgroundUsageTimeInMs; - mConsumePower = consumePower; mBatteryHistEntry = batteryHistEntry; } @@ -54,12 +74,62 @@ public final class BatteryDiffEntry { /** Clones a new instance. */ public BatteryDiffEntry clone() { return new BatteryDiffEntry( + this.mContext, this.mForegroundUsageTimeInMs, this.mBackgroundUsageTimeInMs, this.mConsumePower, this.mBatteryHistEntry /*same instance*/); } + /** Gets the app label name for this entry. */ + public String getAppLabel() { + loadLabelAndIcon(); + return mAppLabel; + } + + /** Gets the app icon {@link Drawable} for this entry. */ + public Drawable getAppIcon() { + loadLabelAndIcon(); + return mAppIcon; + } + + private void loadLabelAndIcon() { + if (mIsLoaded) { + return; + } + mIsLoaded = true; + // Loads application icon and label based on consumer type. + switch (mBatteryHistEntry.mConsumerType) { + case ConvertUtils.CONSUMER_TYPE_USER_BATTERY: + final BatteryEntry.NameAndIcon nameAndIconForUser = + BatteryEntry.getNameAndIconFromUserId( + mContext, (int) mBatteryHistEntry.mUserId); + if (nameAndIconForUser != null) { + mAppIcon = nameAndIconForUser.icon; + mAppLabel = nameAndIconForUser.name; + } + break; + case ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY: + final BatteryEntry.NameAndIcon nameAndIconForSystem = + BatteryEntry.getNameAndIconFromDrainType( + mContext, mBatteryHistEntry.mDrainType); + if (nameAndIconForSystem != null) { + mAppLabel = nameAndIconForSystem.name; + if (nameAndIconForSystem.iconId != 0) { + mAppIcon = mContext.getDrawable(nameAndIconForSystem.iconId); + } + } + break; + case ConvertUtils.CONSUMER_TYPE_UID_BATTERY: + loadNameAndIconForUid(); + break; + } + } + + private void loadNameAndIconForUid() { + // TODO(b/185187669) fetch label and icon for UID battery type + } + @Override public String toString() { final StringBuilder builder = new StringBuilder() diff --git a/src/com/android/settings/fuelgauge/ConvertUtils.java b/src/com/android/settings/fuelgauge/ConvertUtils.java index 2e943d12c72..015541295c3 100644 --- a/src/com/android/settings/fuelgauge/ConvertUtils.java +++ b/src/com/android/settings/fuelgauge/ConvertUtils.java @@ -17,6 +17,7 @@ import android.annotation.IntDef; import android.content.ContentValues; import android.os.BatteryConsumer; import android.os.BatteryUsageStats; +import android.content.Context; import android.os.SystemBatteryConsumer; import android.os.UidBatteryConsumer; import android.os.UserBatteryConsumer; @@ -138,6 +139,7 @@ public final class ConvertUtils { /** Gets indexed battery usage data for each corresponding time slot. */ public static Map> getIndexedUsageMap( + final Context context, final int timeSlotSize, final long[] batteryHistoryKeys, final Map> batteryHistoryMap) { @@ -234,6 +236,7 @@ public final class ConvertUtils { } batteryDiffEntryList.add( new BatteryDiffEntry( + context, foregroundUsageTimeInMs, backgroundUsageTimeInMs, consumePower, diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryDiffEntryTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryDiffEntryTest.java index 07e00fc9ed5..afbfe84883a 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryDiffEntryTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryDiffEntryTest.java @@ -17,17 +17,45 @@ package com.android.settings.fuelgauge; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; + +import android.content.Context; +import android.content.ContentValues; +import android.os.SystemBatteryConsumer; +import android.os.UserManager; + +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; @RunWith(RobolectricTestRunner.class) public final class BatteryDiffEntryTest { + private Context mContext; + @Mock + private UserManager mockUserManager; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = spy(RuntimeEnvironment.application); + doReturn(mockUserManager).when(mContext).getSystemService(UserManager.class); + } + @Test public void testSetTotalConsumePower_returnExpectedResult() { final BatteryDiffEntry entry = new BatteryDiffEntry( + mContext, /*foregroundUsageTimeInMs=*/ 10001L, /*backgroundUsageTimeInMs=*/ 20002L, /*consumePower=*/ 22.0, @@ -41,6 +69,7 @@ public final class BatteryDiffEntryTest { public void testSetTotalConsumePower_setZeroValue_returnsZeroValue() { final BatteryDiffEntry entry = new BatteryDiffEntry( + mContext, /*foregroundUsageTimeInMs=*/ 10001L, /*backgroundUsageTimeInMs=*/ 20002L, /*consumePower=*/ 22.0, @@ -49,4 +78,61 @@ public final class BatteryDiffEntryTest { assertThat(entry.getPercentOfTotal()).isEqualTo(0); } + + @Test + public void testComparator_sortCollectionsInDescOrder() { + final List entryList = new ArrayList<>(); + // Generates fake testing data. + entryList.add(createBatteryDiffEntry(30, /*batteryHistEntry=*/ null)); + entryList.add(createBatteryDiffEntry(20, /*batteryHistEntry=*/ null)); + entryList.add(createBatteryDiffEntry(10, /*batteryHistEntry=*/ null)); + Collections.sort(entryList, BatteryDiffEntry.COMPARATOR); + + assertThat(entryList.get(0).getPercentOfTotal()).isEqualTo(30); + assertThat(entryList.get(1).getPercentOfTotal()).isEqualTo(20); + assertThat(entryList.get(2).getPercentOfTotal()).isEqualTo(10); + } + + @Test + public void testLoadLabelAndIcon_forSystemBattery_returnExpectedResult() { + // Generates fake testing data. + final ContentValues values = new ContentValues(); + values.put("consumerType", + Integer.valueOf(ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY)); + values.put("drainType", + Integer.valueOf(SystemBatteryConsumer.DRAIN_TYPE_AMBIENT_DISPLAY)); + final BatteryHistEntry batteryHistEntry = new BatteryHistEntry(values); + + final BatteryDiffEntry entry = createBatteryDiffEntry(10, batteryHistEntry); + + assertThat(entry.getAppLabel()).isEqualTo("Ambient display"); + } + + @Test + public void testLoadLabelAndIcon_forUserBattery_returnExpectedResult() { + doReturn(null).when(mockUserManager).getUserInfo(1001); + // Generates fake testing data. + final ContentValues values = new ContentValues(); + values.put("consumerType", + Integer.valueOf(ConvertUtils.CONSUMER_TYPE_USER_BATTERY)); + values.put("userId", Integer.valueOf(1001)); + final BatteryHistEntry batteryHistEntry = new BatteryHistEntry(values); + + final BatteryDiffEntry entry = createBatteryDiffEntry(10, batteryHistEntry); + + assertThat(entry.getAppLabel()).isEqualTo("Removed user"); + assertThat(entry.getAppIcon()).isNull(); + } + + private BatteryDiffEntry createBatteryDiffEntry( + double consumePower, BatteryHistEntry batteryHistEntry) { + final BatteryDiffEntry entry = new BatteryDiffEntry( + mContext, + /*foregroundUsageTimeInMs=*/ 0, + /*backgroundUsageTimeInMs=*/ 0, + consumePower, + batteryHistEntry); + entry.setTotalConsumePower(100.0); + return entry; + } } diff --git a/tests/robotests/src/com/android/settings/fuelgauge/ConvertUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/ConvertUtilsTest.java index 681fce69086..7ce488d765c 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/ConvertUtilsTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/ConvertUtilsTest.java @@ -19,8 +19,10 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.when; +import static org.mockito.Mockito.spy; import android.content.ContentValues; +import android.content.Context; import android.os.BatteryConsumer; import android.os.BatteryManager; import android.os.BatteryUsageStats; @@ -47,6 +49,7 @@ import java.util.TimeZone; @RunWith(RobolectricTestRunner.class) public final class ConvertUtilsTest { + private Context mContext; @Mock private BatteryUsageStats mBatteryUsageStats; @Mock @@ -63,6 +66,7 @@ public final class ConvertUtilsTest { @Before public void setUp() { MockitoAnnotations.initMocks(this); + mContext = spy(RuntimeEnvironment.application); } @Test @@ -208,7 +212,7 @@ public final class ConvertUtilsTest { final Map> resultMap = ConvertUtils.getIndexedUsageMap( - timeSlotSize, batteryHistoryKeys, batteryHistoryMap); + mContext, timeSlotSize, batteryHistoryKeys, batteryHistoryMap); assertThat(resultMap).hasSize(3); // Verifies the first timestamp result.