From 59da7ab7b1e4e87a82c7b6c1251e10908a4d5c81 Mon Sep 17 00:00:00 2001 From: ykhung Date: Wed, 14 Apr 2021 17:19:32 +0800 Subject: [PATCH] Load application icon and label for UID battery consumer type Bug: 185187669 Test: make SettingsRoboTests Test: make SettingsGoogleRoboTests Change-Id: Idb77a1bd48f7f4b66b86ff12c166a204d17bd9ec --- .../settings/fuelgauge/BatteryDiffEntry.java | 74 ++++++++++++-- .../settings/fuelgauge/BatteryEntry.java | 10 +- .../fuelgauge/BatteryDiffEntryTest.java | 98 +++++++++++++++++-- 3 files changed, 164 insertions(+), 18 deletions(-) diff --git a/src/com/android/settings/fuelgauge/BatteryDiffEntry.java b/src/com/android/settings/fuelgauge/BatteryDiffEntry.java index 1f61b8b2e1e..efc55545e36 100644 --- a/src/com/android/settings/fuelgauge/BatteryDiffEntry.java +++ b/src/com/android/settings/fuelgauge/BatteryDiffEntry.java @@ -22,6 +22,8 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.graphics.drawable.Drawable; import android.util.Log; +import androidx.annotation.VisibleForTesting; + import java.time.Duration; import java.util.Comparator; @@ -42,9 +44,11 @@ public final class BatteryDiffEntry { private double mPercentOfTotal; private Context mContext; - private String mAppLabel = null; - private Drawable mAppIcon = null; - private boolean mIsLoaded = false; + private String mDefaultPackageName = null; + + @VisibleForTesting String mAppLabel = null; + @VisibleForTesting Drawable mAppIcon = null; + @VisibleForTesting boolean mIsLoaded = false; public BatteryDiffEntry( Context context, @@ -84,13 +88,28 @@ public final class BatteryDiffEntry { /** Gets the app label name for this entry. */ public String getAppLabel() { loadLabelAndIcon(); - return mAppLabel; + // Returns default applicationn label if we cannot find it. + return mAppLabel == null || mAppLabel.length() == 0 + ? mBatteryHistEntry.mAppLabel + : mAppLabel; } /** Gets the app icon {@link Drawable} for this entry. */ public Drawable getAppIcon() { loadLabelAndIcon(); - return mAppIcon; + if (mBatteryHistEntry.mConsumerType != + ConvertUtils.CONSUMER_TYPE_UID_BATTERY) { + return mAppIcon; + } + // Returns default application icon if UID_BATTERY icon is null. + return mAppIcon == null + ? mContext.getPackageManager().getDefaultActivityIcon() + : mAppIcon; + } + + /** Gets the searching package name for UID battery type. */ + public String getPackageName() { + return mDefaultPackageName; } private void loadLabelAndIcon() { @@ -127,7 +146,46 @@ public final class BatteryDiffEntry { } private void loadNameAndIconForUid() { - // TODO(b/185187669) fetch label and icon for UID battery type + final String packageName = mBatteryHistEntry.mPackageName; + final PackageManager packageManager = mContext.getPackageManager(); + // Gets the application label from PackageManager. + if (packageName != null && packageName.length() != 0) { + try { + final ApplicationInfo appInfo = + packageManager.getApplicationInfo(packageName, /*no flags*/ 0); + mAppLabel = packageManager.getApplicationLabel(appInfo).toString(); + } catch (NameNotFoundException e) { + Log.e(TAG, "failed to retrieve ApplicationInfo for: " + packageName); + mAppLabel = packageName; + } + } + + final int uid = (int) mBatteryHistEntry.mUid; + final String[] packages = packageManager.getPackagesForUid(uid); + // Loads special defined application label and icon if available. + if (packages == null || packages.length == 0) { + final BatteryEntry.NameAndIcon nameAndIcon = + BatteryEntry.getNameAndIconFromUid(mContext, mAppLabel, uid); + mAppLabel = nameAndIcon.name; + mAppIcon = nameAndIcon.icon; + } + + final BatteryEntry.NameAndIcon nameAndIcon = + BatteryEntry.loadNameAndIcon( + mContext, uid, /*uid=*/ null, /*batteryEntry=*/ null, + packageName, mAppLabel, mAppIcon); + // 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); + mDefaultPackageName = nameAndIcon.packageName; + if (mDefaultPackageName != null + && !mDefaultPackageName.equals(nameAndIcon.packageName)) { + Log.w(TAG, String.format("found different package: %s | %s", + mDefaultPackageName, nameAndIcon.packageName)); + } + } } @Override @@ -144,4 +202,8 @@ public final class BatteryDiffEntry { mBatteryHistEntry.mPackageName, mBatteryHistEntry.mUid)); return builder.toString(); } + + private static 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 6cb0d120a2e..e5d28b06d6c 100644 --- a/src/com/android/settings/fuelgauge/BatteryEntry.java +++ b/src/com/android/settings/fuelgauge/BatteryEntry.java @@ -111,7 +111,8 @@ public class BatteryEntry { } final NameAndIcon nameAndIcon = BatteryEntry.loadNameAndIcon( - be.mContext, be.getUid(), sHandler, be, be.mDefaultPackageName); + 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); @@ -274,6 +275,7 @@ public class BatteryEntry { icon = mContext.getPackageManager().getDefaultActivityIcon(); } + // Avoids post the loading icon and label in the background request. if (sHandler != null && loadDataInBackground) { synchronized (sRequestQueue) { sRequestQueue.add(this); @@ -289,9 +291,9 @@ public class BatteryEntry { int uid, Handler handler, BatteryEntry batteryEntry, - String defaultPackageName) { - String name = null; - Drawable icon = null; + String defaultPackageName, + String name, + Drawable icon) { // Bail out if the current sipper is not an App sipper. if (uid == 0 || uid == Process.INVALID_UID) { return null; diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryDiffEntryTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryDiffEntryTest.java index afbfe84883a..0f7a40732f2 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryDiffEntryTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryDiffEntryTest.java @@ -22,6 +22,9 @@ import static org.mockito.Mockito.spy; import android.content.Context; import android.content.ContentValues; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.graphics.drawable.Drawable; import android.os.SystemBatteryConsumer; import android.os.UserManager; @@ -41,14 +44,18 @@ import java.util.List; public final class BatteryDiffEntryTest { private Context mContext; - @Mock - private UserManager mockUserManager; + + @Mock private ApplicationInfo mockAppInfo; + @Mock private PackageManager mockPackageManager; + @Mock private UserManager mockUserManager; + @Mock private Drawable mockDrawable; @Before public void setUp() { MockitoAnnotations.initMocks(this); mContext = spy(RuntimeEnvironment.application); doReturn(mockUserManager).when(mContext).getSystemService(UserManager.class); + doReturn(mockPackageManager).when(mContext).getPackageManager(); } @Test @@ -96,9 +103,8 @@ public final class BatteryDiffEntryTest { @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)); + final ContentValues values = getContentValuesWithType( + ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY); values.put("drainType", Integer.valueOf(SystemBatteryConsumer.DRAIN_TYPE_AMBIENT_DISPLAY)); final BatteryHistEntry batteryHistEntry = new BatteryHistEntry(values); @@ -112,9 +118,8 @@ public final class BatteryDiffEntryTest { 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)); + final ContentValues values = getContentValuesWithType( + ConvertUtils.CONSUMER_TYPE_USER_BATTERY); values.put("userId", Integer.valueOf(1001)); final BatteryHistEntry batteryHistEntry = new BatteryHistEntry(values); @@ -124,6 +129,77 @@ public final class BatteryDiffEntryTest { assertThat(entry.getAppIcon()).isNull(); } + @Test + public void testGetAppLabel_loadDataFromApplicationInfo() throws Exception { + final String expectedAppLabel = "fake app label"; + final String fakePackageName = "com.fake.google.com"; + final ContentValues values = getContentValuesWithType( + ConvertUtils.CONSUMER_TYPE_UID_BATTERY); + values.put("uid", /*invalid uid*/ 10001); + values.put("packageName", fakePackageName); + doReturn(mockAppInfo).when(mockPackageManager) + .getApplicationInfo(fakePackageName, 0); + doReturn(expectedAppLabel).when(mockPackageManager) + .getApplicationLabel(mockAppInfo); + final BatteryHistEntry batteryHistEntry = new BatteryHistEntry(values); + + final BatteryDiffEntry entry = createBatteryDiffEntry(10, batteryHistEntry); + + assertThat(entry.getAppLabel()).isEqualTo(expectedAppLabel); + } + + @Test + public void testGetAppLabel_loadDataFromPreDefinedNameAndUid() { + final ContentValues values = getContentValuesWithType( + ConvertUtils.CONSUMER_TYPE_UID_BATTERY); + final BatteryHistEntry batteryHistEntry = new BatteryHistEntry(values); + + final BatteryDiffEntry entry = createBatteryDiffEntry(10, batteryHistEntry); + + assertThat(entry.getAppLabel()).isEqualTo("Android OS"); + } + + @Test + public void testGetAppLabel_nullAppLabel_returnAppLabelInBatteryHistEntry() { + final String expectedAppLabel = "fake app label"; + final ContentValues values = getContentValuesWithType( + ConvertUtils.CONSUMER_TYPE_UID_BATTERY); + values.put("appLabel", expectedAppLabel); + final BatteryHistEntry batteryHistEntry = new BatteryHistEntry(values); + + final BatteryDiffEntry entry = createBatteryDiffEntry(10, batteryHistEntry); + + entry.mIsLoaded = true; + assertThat(entry.getAppLabel()).isEqualTo(expectedAppLabel); + } + + @Test + public void testGetAppIcon_nonUidConsumer_returnAppIconInBatteryDiffEntry() { + final ContentValues values = getContentValuesWithType( + ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY); + final BatteryHistEntry batteryHistEntry = new BatteryHistEntry(values); + + final BatteryDiffEntry entry = createBatteryDiffEntry(10, batteryHistEntry); + + entry.mIsLoaded = true; + entry.mAppIcon = mockDrawable; + assertThat(entry.getAppIcon()).isEqualTo(mockDrawable); + } + + @Test + public void testGetAppIcon_uidConsumerWithNullIcon_returnDefaultActivityIcon() { + final ContentValues values = getContentValuesWithType( + ConvertUtils.CONSUMER_TYPE_UID_BATTERY); + final BatteryHistEntry batteryHistEntry = new BatteryHistEntry(values); + doReturn(mockDrawable).when(mockPackageManager).getDefaultActivityIcon(); + + final BatteryDiffEntry entry = createBatteryDiffEntry(10, batteryHistEntry); + + entry.mIsLoaded = true; + entry.mAppIcon = null; + assertThat(entry.getAppIcon()).isEqualTo(mockDrawable); + } + private BatteryDiffEntry createBatteryDiffEntry( double consumePower, BatteryHistEntry batteryHistEntry) { final BatteryDiffEntry entry = new BatteryDiffEntry( @@ -135,4 +211,10 @@ public final class BatteryDiffEntryTest { entry.setTotalConsumePower(100.0); return entry; } + + private static ContentValues getContentValuesWithType(int consumerType) { + final ContentValues values = new ContentValues(); + values.put("consumerType", Integer.valueOf(consumerType)); + return values; + } }