Add battery usage time summary to usage list item

Insert app foregound and background usage time information into the
preference item summary based on the different scenarios.

Bug: 177406865
Test: make SettingsRoboTests
Test: make SettingsGoogleRoboTests
Change-Id: I13ba357666adfb7b57f52ffae18d09aed8dd0773
This commit is contained in:
ykhung
2021-04-20 14:25:29 +08:00
committed by YUKAI HUNG
parent a30178221a
commit 7cc616e90f
4 changed files with 160 additions and 4 deletions

View File

@@ -6361,7 +6361,14 @@
<string name="battery_usage_time_am">am</string> <string name="battery_usage_time_am">am</string>
<!-- [CHAR_LIMIT=NONE] Battery usage section header for a specific time slot --> <!-- [CHAR_LIMIT=NONE] Battery usage section header for a specific time slot -->
<string name="battery_usage_time_pm">pm</string> <string name="battery_usage_time_pm">pm</string>
<!-- [CHAR_LIMIT=NONE] Battery usage item for total usage time less than a minute -->
<string name="battery_usage_total_less_than_one_minute">Total: less than a min</string>
<!-- [CHAR_LIMIT=NONE] Battery usage item for total background time less than a minute -->
<string name="battery_usage_background_less_than_one_minute">Background: less than a min</string>
<!-- [CHAR_LIMIT=NONE] Battery usage item for total usage time -->
<string name="battery_usage_for_total_time">Total: <xliff:g id="time">%s</xliff:g></string>
<!-- [CHAR_LIMIT=NONE] Battery usage item for background usage time -->
<string name="battery_usage_for_background_time">Background: <xliff:g id="time">%s</xliff:g></string>
<!-- Process Stats strings --> <!-- Process Stats strings -->
<skip /> <skip />

View File

@@ -22,6 +22,7 @@ import android.graphics.drawable.Drawable;
import android.os.Handler; import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import android.text.TextUtils; import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.Log; import android.util.Log;
import androidx.annotation.VisibleForTesting; 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.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnDestroy; import com.android.settingslib.core.lifecycle.events.OnDestroy;
import com.android.settingslib.core.lifecycle.events.OnPause; import com.android.settingslib.core.lifecycle.events.OnPause;
import com.android.settingslib.utils.StringUtil;
import java.util.Arrays; import java.util.Arrays;
import java.util.ArrayList; import java.util.ArrayList;
@@ -70,6 +72,7 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
private final SettingsActivity mActivity; private final SettingsActivity mActivity;
private final InstrumentedPreferenceFragment mFragment; private final InstrumentedPreferenceFragment mFragment;
private final Handler mHandler = new Handler(Looper.getMainLooper()); private final Handler mHandler = new Handler(Looper.getMainLooper());
private final CharSequence[] mNotAllowShowSummaryPackages;
// Preference cache to avoid create new instance each time. // Preference cache to avoid create new instance each time.
@VisibleForTesting @VisibleForTesting
@@ -83,6 +86,8 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
mActivity = activity; mActivity = activity;
mFragment = fragment; mFragment = fragment;
mPreferenceKey = preferenceKey; mPreferenceKey = preferenceKey;
mNotAllowShowSummaryPackages = context.getResources()
.getTextArray(R.array.allowlist_hide_summary_in_battery_usage);
if (lifecycle != null) { if (lifecycle != null) {
lifecycle.addObserver(this); lifecycle.addObserver(this);
} }
@@ -139,8 +144,9 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
isValidPackage = mBatteryUtils.getPackageUid(histEntry.mPackageName) isValidPackage = mBatteryUtils.getPackageUid(histEntry.mPackageName)
!= BatteryUtils.UID_NULL; != BatteryUtils.UID_NULL;
} }
Log.d(TAG, String.format("handleClick() label=%s key=%s isValid:%b", Log.d(TAG, String.format("handleClick() label=%s key=%s isValid:%b %s",
diffEntry.getAppLabel(), histEntry.getKey(), isValidPackage)); diffEntry.getAppLabel(), histEntry.getKey(), isValidPackage,
histEntry.mPackageName));
if (isValidPackage) { if (isValidPackage) {
AdvancedPowerUsageDetail.startBatteryDetailPage( AdvancedPowerUsageDetail.startBatteryDetailPage(
mActivity, mFragment, diffEntry, powerPref.getPercent()); mActivity, mFragment, diffEntry, powerPref.getPercent());
@@ -299,8 +305,10 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
pref.setTitle(appLabel); pref.setTitle(appLabel);
pref.setOrder(prefIndex); pref.setOrder(prefIndex);
pref.setPercent(entry.getPercentOfTotal()); pref.setPercent(entry.getPercentOfTotal());
pref.setSingleLineTitle(true);
// Sets the BatteryDiffEntry to preference for launching detailed page. // Sets the BatteryDiffEntry to preference for launching detailed page.
pref.setBatteryDiffEntry(entry); pref.setBatteryDiffEntry(entry);
setPreferenceSummary(pref, entry);
mAppListPrefGroup.addPreference(pref); mAppListPrefGroup.addPreference(pref);
prefIndex++; prefIndex++;
} }
@@ -322,6 +330,57 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
mAppListPrefGroup.removeAll(); 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) { private static String utcToLocalTime(long[] timestamps) {
final StringBuilder builder = new StringBuilder(); final StringBuilder builder = new StringBuilder();
for (int index = 0; index < timestamps.length; index++) { for (int index = 0; index < timestamps.length; index++) {

View File

@@ -210,12 +210,17 @@ public class BatteryDiffEntry {
packageManager.getApplicationInfo(packageName, /*no flags*/ 0); packageManager.getApplicationInfo(packageName, /*no flags*/ 0);
if (appInfo != null) { if (appInfo != null) {
mAppLabel = packageManager.getApplicationLabel(appInfo).toString(); mAppLabel = packageManager.getApplicationLabel(appInfo).toString();
mAppIcon = packageManager.getApplicationIcon(appInfo);
} }
} catch (NameNotFoundException e) { } catch (NameNotFoundException e) {
Log.e(TAG, "failed to retrieve ApplicationInfo for: " + packageName); Log.e(TAG, "failed to retrieve ApplicationInfo for: " + packageName);
mAppLabel = 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 int uid = (int) mBatteryHistEntry.mUid;
final String[] packages = packageManager.getPackagesForUid(uid); final String[] packages = packageManager.getPackagesForUid(uid);

View File

@@ -30,7 +30,9 @@ import android.content.Context;
import android.content.ContentValues; import android.content.ContentValues;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.text.format.DateUtils;
import androidx.preference.Preference;
import androidx.preference.PreferenceGroup; import androidx.preference.PreferenceGroup;
import com.android.settings.R; import com.android.settings.R;
@@ -274,6 +276,7 @@ public final class BatteryChartPreferenceControllerTest {
assertThat(pref.getIcon()).isEqualTo(mDrawable); assertThat(pref.getIcon()).isEqualTo(mDrawable);
assertThat(pref.getOrder()).isEqualTo(1); assertThat(pref.getOrder()).isEqualTo(1);
assertThat(pref.getBatteryDiffEntry()).isSameInstanceAs(mBatteryDiffEntry); assertThat(pref.getBatteryDiffEntry()).isSameInstanceAs(mBatteryDiffEntry);
assertThat(pref.isSingleLineTitle()).isTrue();
} }
@Test @Test
@@ -303,7 +306,82 @@ public final class BatteryChartPreferenceControllerTest {
mPowerGaugePreference)).isFalse(); mPowerGaugePreference)).isFalse();
} }
private Map<Long, List<BatteryHistEntry>> 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<Long, List<BatteryHistEntry>> createBatteryHistoryMap(int size) {
final Map<Long, List<BatteryHistEntry>> batteryHistoryMap = new HashMap<>(); final Map<Long, List<BatteryHistEntry>> batteryHistoryMap = new HashMap<>();
for (int index = 0; index < size; index++) { for (int index = 0; index < size; index++) {
final ContentValues values = new ContentValues(); final ContentValues values = new ContentValues();
@@ -313,4 +391,11 @@ public final class BatteryChartPreferenceControllerTest {
} }
return batteryHistoryMap; return batteryHistoryMap;
} }
private BatteryDiffEntry createBatteryDiffEntry(
long foregroundUsageTimeInMs, long backgroundUsageTimeInMs) {
return new BatteryDiffEntry(
mContext, foregroundUsageTimeInMs, backgroundUsageTimeInMs,
/*consumePower=*/ 0, mBatteryHistEntry);
}
} }