diff --git a/res/values/strings.xml b/res/values/strings.xml index f5c6d82b8b4..9b1cdb26942 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -6361,7 +6361,14 @@ am pm - + + Total: less than a min + + Background: less than a min + + Total: %s + + Background: %s diff --git a/src/com/android/settings/fuelgauge/BatteryChartPreferenceController.java b/src/com/android/settings/fuelgauge/BatteryChartPreferenceController.java index 54591af4bd0..c676bd36bc8 100644 --- a/src/com/android/settings/fuelgauge/BatteryChartPreferenceController.java +++ b/src/com/android/settings/fuelgauge/BatteryChartPreferenceController.java @@ -22,6 +22,7 @@ import android.graphics.drawable.Drawable; import android.os.Handler; import android.os.Looper; import android.text.TextUtils; +import android.text.format.DateUtils; import android.util.Log; import androidx.annotation.VisibleForTesting; @@ -38,6 +39,7 @@ import com.android.settingslib.core.lifecycle.Lifecycle; import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.events.OnDestroy; import com.android.settingslib.core.lifecycle.events.OnPause; +import com.android.settingslib.utils.StringUtil; import java.util.Arrays; import java.util.ArrayList; @@ -70,6 +72,7 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll private final SettingsActivity mActivity; private final InstrumentedPreferenceFragment mFragment; private final Handler mHandler = new Handler(Looper.getMainLooper()); + private final CharSequence[] mNotAllowShowSummaryPackages; // Preference cache to avoid create new instance each time. @VisibleForTesting @@ -83,6 +86,8 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll mActivity = activity; mFragment = fragment; mPreferenceKey = preferenceKey; + mNotAllowShowSummaryPackages = context.getResources() + .getTextArray(R.array.allowlist_hide_summary_in_battery_usage); if (lifecycle != null) { lifecycle.addObserver(this); } @@ -139,8 +144,9 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll 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)); + Log.d(TAG, String.format("handleClick() label=%s key=%s isValid:%b %s", + diffEntry.getAppLabel(), histEntry.getKey(), isValidPackage, + histEntry.mPackageName)); if (isValidPackage) { AdvancedPowerUsageDetail.startBatteryDetailPage( mActivity, mFragment, diffEntry, powerPref.getPercent()); @@ -299,8 +305,10 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll pref.setTitle(appLabel); pref.setOrder(prefIndex); pref.setPercent(entry.getPercentOfTotal()); + pref.setSingleLineTitle(true); // Sets the BatteryDiffEntry to preference for launching detailed page. pref.setBatteryDiffEntry(entry); + setPreferenceSummary(pref, entry); mAppListPrefGroup.addPreference(pref); prefIndex++; } @@ -322,6 +330,57 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll mAppListPrefGroup.removeAll(); } + @VisibleForTesting + void setPreferenceSummary( + PowerGaugePreference preference, BatteryDiffEntry entry) { + final long foregroundUsageTimeInMs = entry.mForegroundUsageTimeInMs; + final long backgroundUsageTimeInMs = entry.mBackgroundUsageTimeInMs; + final long totalUsageTimeInMs = foregroundUsageTimeInMs + backgroundUsageTimeInMs; + // Checks whether the package is allowed to show summary or not. + for (CharSequence notAllowPackageName : mNotAllowShowSummaryPackages) { + if (TextUtils.equals(entry.getPackageName(), notAllowPackageName)) { + preference.setSummary(null); + return; + } + } + String usageTimeSummary = null; + // Not shows summary for some system components without usage time. + if (totalUsageTimeInMs == 0) { + preference.setSummary(null); + // Shows background summary only if we don't have foreground usage time. + } else if (foregroundUsageTimeInMs == 0 && backgroundUsageTimeInMs != 0) { + usageTimeSummary = buildUsageTimeInfo(backgroundUsageTimeInMs, true); + // Shows total usage summary only if total usage time is small. + } else if (totalUsageTimeInMs < DateUtils.MINUTE_IN_MILLIS) { + usageTimeSummary = buildUsageTimeInfo(totalUsageTimeInMs, false); + } else { + usageTimeSummary = buildUsageTimeInfo(totalUsageTimeInMs, false); + // Shows background usage time if it is larger than a minute. + if (backgroundUsageTimeInMs >= DateUtils.MINUTE_IN_MILLIS) { + usageTimeSummary += + "\n" + buildUsageTimeInfo(backgroundUsageTimeInMs, true); + } + } + preference.setSummary(usageTimeSummary); + } + + private String buildUsageTimeInfo(long usageTimeInMs, boolean isBackground) { + if (usageTimeInMs < DateUtils.MINUTE_IN_MILLIS) { + return mPrefContext.getString( + isBackground + ? R.string.battery_usage_background_less_than_one_minute + : R.string.battery_usage_total_less_than_one_minute); + } + final CharSequence timeSequence = + StringUtil.formatElapsedTime(mPrefContext, usageTimeInMs, + /*withSeconds=*/ false, /*collapseTimeUnit=*/ false); + final int resourceId = + isBackground + ? R.string.battery_usage_for_background_time + : R.string.battery_usage_for_total_time; + return mPrefContext.getString(resourceId, timeSequence); + } + private static String utcToLocalTime(long[] timestamps) { final StringBuilder builder = new StringBuilder(); for (int index = 0; index < timestamps.length; index++) { diff --git a/src/com/android/settings/fuelgauge/BatteryDiffEntry.java b/src/com/android/settings/fuelgauge/BatteryDiffEntry.java index 92731b75d38..d48c92f6cf0 100644 --- a/src/com/android/settings/fuelgauge/BatteryDiffEntry.java +++ b/src/com/android/settings/fuelgauge/BatteryDiffEntry.java @@ -210,12 +210,17 @@ public class BatteryDiffEntry { packageManager.getApplicationInfo(packageName, /*no flags*/ 0); if (appInfo != null) { mAppLabel = packageManager.getApplicationLabel(appInfo).toString(); + mAppIcon = packageManager.getApplicationIcon(appInfo); } } catch (NameNotFoundException e) { Log.e(TAG, "failed to retrieve ApplicationInfo for: " + packageName); mAppLabel = packageName; } } + // Early return if we found the app label and icon resource. + if (mAppLabel != null && mAppIcon != null) { + return; + } final int uid = (int) mBatteryHistEntry.mUid; final String[] packages = packageManager.getPackagesForUid(uid); diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryChartPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryChartPreferenceControllerTest.java index bef250b1ca9..d811726c1b6 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryChartPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryChartPreferenceControllerTest.java @@ -30,7 +30,9 @@ import android.content.Context; import android.content.ContentValues; import android.content.pm.PackageManager; import android.graphics.drawable.Drawable; +import android.text.format.DateUtils; +import androidx.preference.Preference; import androidx.preference.PreferenceGroup; import com.android.settings.R; @@ -274,6 +276,7 @@ public final class BatteryChartPreferenceControllerTest { assertThat(pref.getIcon()).isEqualTo(mDrawable); assertThat(pref.getOrder()).isEqualTo(1); assertThat(pref.getBatteryDiffEntry()).isSameInstanceAs(mBatteryDiffEntry); + assertThat(pref.isSingleLineTitle()).isTrue(); } @Test @@ -303,7 +306,82 @@ public final class BatteryChartPreferenceControllerTest { mPowerGaugePreference)).isFalse(); } - private Map> createBatteryHistoryMap(int size) { + @Test + public void testSetPreferenceSummary_setNullContentIfTotalUsageTimeIsZero() { + final PowerGaugePreference pref = new PowerGaugePreference(mContext); + pref.setSummary("fake preference summary"); + + mBatteryChartPreferenceController.setPreferenceSummary( + pref, createBatteryDiffEntry( + /*foregroundUsageTimeInMs=*/ 0, + /*backgroundUsageTimeInMs=*/ 0)); + assertThat(pref.getSummary()).isNull(); + } + + @Test + public void testSetPreferenceSummary_setBackgroundUsageTimeOnly() { + final PowerGaugePreference pref = new PowerGaugePreference(mContext); + pref.setSummary("fake preference summary"); + + mBatteryChartPreferenceController.setPreferenceSummary( + pref, createBatteryDiffEntry( + /*foregroundUsageTimeInMs=*/ 0, + /*backgroundUsageTimeInMs=*/ DateUtils.MINUTE_IN_MILLIS)); + assertThat(pref.getSummary()).isEqualTo("Background: 1 min"); + } + + @Test + public void testSetPreferenceSummary_setTotalUsageTimeLessThanAMinute() { + final PowerGaugePreference pref = new PowerGaugePreference(mContext); + pref.setSummary("fake preference summary"); + + mBatteryChartPreferenceController.setPreferenceSummary( + pref, createBatteryDiffEntry( + /*foregroundUsageTimeInMs=*/ 100, + /*backgroundUsageTimeInMs=*/ 200)); + assertThat(pref.getSummary()).isEqualTo("Total: less than a min"); + } + + @Test + public void testSetPreferenceSummary_setTotalTimeIfBackgroundTimeLessThanAMinute() { + final PowerGaugePreference pref = new PowerGaugePreference(mContext); + pref.setSummary("fake preference summary"); + + mBatteryChartPreferenceController.setPreferenceSummary( + pref, createBatteryDiffEntry( + /*foregroundUsageTimeInMs=*/ DateUtils.MINUTE_IN_MILLIS, + /*backgroundUsageTimeInMs=*/ 200)); + assertThat(pref.getSummary()).isEqualTo("Total: 1 min"); + } + + @Test + public void testSetPreferenceSummary_setTotalAndBackgroundUsageTime() { + final PowerGaugePreference pref = new PowerGaugePreference(mContext); + pref.setSummary("fake preference summary"); + + mBatteryChartPreferenceController.setPreferenceSummary( + pref, createBatteryDiffEntry( + /*foregroundUsageTimeInMs=*/ DateUtils.MINUTE_IN_MILLIS, + /*backgroundUsageTimeInMs=*/ DateUtils.MINUTE_IN_MILLIS)); + assertThat(pref.getSummary()).isEqualTo("Total: 2 min\nBackground: 1 min"); + } + + @Test + public void testSetPreferenceSummary_notAllowShownPackage_setSummayAsNull() { + final PowerGaugePreference pref = new PowerGaugePreference(mContext); + pref.setSummary("fake preference summary"); + final BatteryDiffEntry batteryDiffEntry = + spy(createBatteryDiffEntry( + /*foregroundUsageTimeInMs=*/ DateUtils.MINUTE_IN_MILLIS, + /*backgroundUsageTimeInMs=*/ DateUtils.MINUTE_IN_MILLIS)); + doReturn("com.google.android.googlequicksearchbox").when(batteryDiffEntry) + .getPackageName(); + + mBatteryChartPreferenceController.setPreferenceSummary(pref, batteryDiffEntry); + assertThat(pref.getSummary()).isNull(); + } + + private static Map> createBatteryHistoryMap(int size) { final Map> batteryHistoryMap = new HashMap<>(); for (int index = 0; index < size; index++) { final ContentValues values = new ContentValues(); @@ -313,4 +391,11 @@ public final class BatteryChartPreferenceControllerTest { } return batteryHistoryMap; } + + private BatteryDiffEntry createBatteryDiffEntry( + long foregroundUsageTimeInMs, long backgroundUsageTimeInMs) { + return new BatteryDiffEntry( + mContext, foregroundUsageTimeInMs, backgroundUsageTimeInMs, + /*consumePower=*/ 0, mBatteryHistEntry); + } }