Smear screen power usage based on activity time.
Bug: 38328636 Test: RunSettingsRoboTests Change-Id: I8e7baadcd88a8e9d674f5bc8d8e42e0f3953c98a
This commit is contained in:
@@ -22,7 +22,9 @@ import android.os.SystemClock;
|
|||||||
import android.support.annotation.IntDef;
|
import android.support.annotation.IntDef;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.annotation.VisibleForTesting;
|
import android.support.annotation.VisibleForTesting;
|
||||||
|
import android.text.format.DateUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.util.SparseLongArray;
|
||||||
|
|
||||||
import com.android.internal.os.BatterySipper;
|
import com.android.internal.os.BatterySipper;
|
||||||
import com.android.settings.overlay.FeatureFactory;
|
import com.android.settings.overlay.FeatureFactory;
|
||||||
@@ -115,25 +117,63 @@ public class BatteryUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove the {@link BatterySipper} that we should hide.
|
* Remove the {@link BatterySipper} that we should hide and smear the screen usage based on
|
||||||
|
* foreground activity time.
|
||||||
*
|
*
|
||||||
* @param sippers sipper list that need to check and remove
|
* @param sippers sipper list that need to check and remove
|
||||||
* @return the total power of the hidden items of {@link BatterySipper}
|
* @return the total power of the hidden items of {@link BatterySipper}
|
||||||
|
* for proportional smearing
|
||||||
*/
|
*/
|
||||||
public double removeHiddenBatterySippers(List<BatterySipper> sippers) {
|
public double removeHiddenBatterySippers(List<BatterySipper> sippers) {
|
||||||
double totalPowerMah = 0;
|
double proportionalSmearPowerMah = 0;
|
||||||
|
BatterySipper screenSipper = null;
|
||||||
for (int i = sippers.size() - 1; i >= 0; i--) {
|
for (int i = sippers.size() - 1; i >= 0; i--) {
|
||||||
final BatterySipper sipper = sippers.get(i);
|
final BatterySipper sipper = sippers.get(i);
|
||||||
if (shouldHideSipper(sipper)) {
|
if (shouldHideSipper(sipper)) {
|
||||||
sippers.remove(i);
|
sippers.remove(i);
|
||||||
if (sipper.drainType != BatterySipper.DrainType.OVERCOUNTED) {
|
if (sipper.drainType != BatterySipper.DrainType.OVERCOUNTED
|
||||||
// Don't add it if it is overcounted
|
&& sipper.drainType != BatterySipper.DrainType.SCREEN) {
|
||||||
totalPowerMah += sipper.totalPowerMah;
|
// Don't add it if it is overcounted or screen
|
||||||
}
|
proportionalSmearPowerMah += sipper.totalPowerMah;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return totalPowerMah;
|
if (sipper.drainType == BatterySipper.DrainType.SCREEN) {
|
||||||
|
screenSipper = sipper;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
smearScreenBatterySipper(sippers, screenSipper);
|
||||||
|
|
||||||
|
return proportionalSmearPowerMah;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Smear the screen on power usage among {@code sippers}, based on ratio of foreground activity
|
||||||
|
* time.
|
||||||
|
*/
|
||||||
|
@VisibleForTesting
|
||||||
|
void smearScreenBatterySipper(List<BatterySipper> sippers, BatterySipper screenSipper) {
|
||||||
|
final long rawRealtimeMs = SystemClock.elapsedRealtime();
|
||||||
|
long totalActivityTimeMs = 0;
|
||||||
|
final SparseLongArray activityTimeArray = new SparseLongArray();
|
||||||
|
for (int i = 0, size = sippers.size(); i < size; i++) {
|
||||||
|
final BatteryStats.Uid uid = sippers.get(i).uidObj;
|
||||||
|
if (uid != null) {
|
||||||
|
final long timeMs = getForegroundActivityTotalTimeMs(uid, rawRealtimeMs);
|
||||||
|
activityTimeArray.put(uid.getUid(), timeMs);
|
||||||
|
totalActivityTimeMs += timeMs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (totalActivityTimeMs >= 10 * DateUtils.MINUTE_IN_MILLIS) {
|
||||||
|
final double screenPowerMah = screenSipper.totalPowerMah;
|
||||||
|
for (int i = 0, size = sippers.size(); i < size; i++) {
|
||||||
|
final BatterySipper sipper = sippers.get(i);
|
||||||
|
sipper.totalPowerMah += screenPowerMah * activityTimeArray.get(sipper.getUid(), 0)
|
||||||
|
/ totalActivityTimeMs;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -186,5 +226,15 @@ public class BatteryUtils {
|
|||||||
return mPackageManager == null;
|
return mPackageManager == null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
long getForegroundActivityTotalTimeMs(BatteryStats.Uid uid, long rawRealtimeMs) {
|
||||||
|
final BatteryStats.Timer timer = uid.getForegroundActivityTimer();
|
||||||
|
if (timer != null) {
|
||||||
|
return timer.getTotalTimeLocked(rawRealtimeMs, BatteryStats.STATS_SINCE_CHARGED);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -57,7 +57,7 @@ public abstract class PowerUsageBase extends DashboardFragment
|
|||||||
|
|
||||||
mBatteryBroadcastReceiver = new BatteryBroadcastReceiver(getContext());
|
mBatteryBroadcastReceiver = new BatteryBroadcastReceiver(getContext());
|
||||||
mBatteryBroadcastReceiver.setBatteryChangedListener(() -> {
|
mBatteryBroadcastReceiver.setBatteryChangedListener(() -> {
|
||||||
getLoaderManager().restartLoader(0, null, this);
|
restartBatteryStatsLoader();
|
||||||
});
|
});
|
||||||
|
|
||||||
getLoaderManager().initLoader(0, icicle, this);
|
getLoaderManager().initLoader(0, icicle, this);
|
||||||
@@ -95,6 +95,10 @@ public abstract class PowerUsageBase extends DashboardFragment
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void restartBatteryStatsLoader() {
|
||||||
|
getLoaderManager().restartLoader(0, Bundle.EMPTY, this);
|
||||||
|
}
|
||||||
|
|
||||||
protected abstract void refreshUi();
|
protected abstract void refreshUi();
|
||||||
|
|
||||||
protected void updatePreference(BatteryHistoryPreference historyPref) {
|
protected void updatePreference(BatteryHistoryPreference historyPref) {
|
||||||
|
@@ -287,7 +287,7 @@ public class PowerUsageSummary extends PowerUsageBase {
|
|||||||
item.setTitle(mShowAllApps ? R.string.hide_extra_apps : R.string.show_all_apps);
|
item.setTitle(mShowAllApps ? R.string.hide_extra_apps : R.string.show_all_apps);
|
||||||
metricsFeatureProvider.action(context,
|
metricsFeatureProvider.action(context,
|
||||||
MetricsEvent.ACTION_SETTINGS_MENU_BATTERY_APPS_TOGGLE, mShowAllApps);
|
MetricsEvent.ACTION_SETTINGS_MENU_BATTERY_APPS_TOGGLE, mShowAllApps);
|
||||||
refreshUi();
|
restartBatteryStatsLoader();
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
return super.onOptionsItemSelected(item);
|
return super.onOptionsItemSelected(item);
|
||||||
|
@@ -18,6 +18,7 @@ package com.android.settings.fuelgauge;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.BatteryStats;
|
import android.os.BatteryStats;
|
||||||
import android.os.Process;
|
import android.os.Process;
|
||||||
|
import android.text.format.DateUtils;
|
||||||
|
|
||||||
import com.android.internal.os.BatterySipper;
|
import com.android.internal.os.BatterySipper;
|
||||||
import com.android.settings.SettingsRobolectricTestRunner;
|
import com.android.settings.SettingsRobolectricTestRunner;
|
||||||
@@ -47,8 +48,11 @@ import static com.google.common.truth.Truth.assertThat;
|
|||||||
import static org.mockito.Matchers.any;
|
import static org.mockito.Matchers.any;
|
||||||
import static org.mockito.Matchers.anyInt;
|
import static org.mockito.Matchers.anyInt;
|
||||||
import static org.mockito.Matchers.anyLong;
|
import static org.mockito.Matchers.anyLong;
|
||||||
|
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
|
||||||
|
import static org.mockito.Mockito.doNothing;
|
||||||
import static org.mockito.Mockito.doReturn;
|
import static org.mockito.Mockito.doReturn;
|
||||||
import static org.mockito.Matchers.eq;
|
import static org.mockito.Matchers.eq;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
import static org.mockito.Mockito.spy;
|
import static org.mockito.Mockito.spy;
|
||||||
|
|
||||||
@@ -62,6 +66,8 @@ public class BatteryUtilsTest {
|
|||||||
private static final long TIME_STATE_TOP_SLEEPING = 2500 * UNIT;
|
private static final long TIME_STATE_TOP_SLEEPING = 2500 * UNIT;
|
||||||
private static final long TIME_STATE_FOREGROUND = 3000 * UNIT;
|
private static final long TIME_STATE_FOREGROUND = 3000 * UNIT;
|
||||||
private static final long TIME_STATE_BACKGROUND = 6000 * UNIT;
|
private static final long TIME_STATE_BACKGROUND = 6000 * UNIT;
|
||||||
|
private static final long TIME_FOREGROUND_ACTIVITY_ZERO = 0;
|
||||||
|
private static final long TIME_FOREGROUND_ACTIVITY = 100 * DateUtils.MINUTE_IN_MILLIS;
|
||||||
|
|
||||||
private static final int UID = 123;
|
private static final int UID = 123;
|
||||||
private static final long TIME_EXPECTED_FOREGROUND = 1500;
|
private static final long TIME_EXPECTED_FOREGROUND = 1500;
|
||||||
@@ -71,6 +77,7 @@ public class BatteryUtilsTest {
|
|||||||
private static final double BATTERY_SYSTEM_USAGE = 600;
|
private static final double BATTERY_SYSTEM_USAGE = 600;
|
||||||
private static final double BATTERY_OVERACCOUNTED_USAGE = 500;
|
private static final double BATTERY_OVERACCOUNTED_USAGE = 500;
|
||||||
private static final double BATTERY_UNACCOUNTED_USAGE = 700;
|
private static final double BATTERY_UNACCOUNTED_USAGE = 700;
|
||||||
|
private static final double BATTERY_APP_USAGE = 100;
|
||||||
private static final double TOTAL_BATTERY_USAGE = 1000;
|
private static final double TOTAL_BATTERY_USAGE = 1000;
|
||||||
private static final double HIDDEN_USAGE = 200;
|
private static final double HIDDEN_USAGE = 200;
|
||||||
private static final int DISCHARGE_AMOUNT = 80;
|
private static final int DISCHARGE_AMOUNT = 80;
|
||||||
@@ -180,11 +187,13 @@ public class BatteryUtilsTest {
|
|||||||
sippers.add(mUnaccountedBatterySipper);
|
sippers.add(mUnaccountedBatterySipper);
|
||||||
when(mProvider.isTypeSystem(mSystemBatterySipper))
|
when(mProvider.isTypeSystem(mSystemBatterySipper))
|
||||||
.thenReturn(true);
|
.thenReturn(true);
|
||||||
|
doNothing().when(mBatteryUtils).smearScreenBatterySipper(any(), any());
|
||||||
|
|
||||||
final double totalUsage = mBatteryUtils.removeHiddenBatterySippers(sippers);
|
final double totalUsage = mBatteryUtils.removeHiddenBatterySippers(sippers);
|
||||||
|
|
||||||
assertThat(sippers).containsExactly(mNormalBatterySipper);
|
assertThat(sippers).containsExactly(mNormalBatterySipper);
|
||||||
assertThat(totalUsage).isWithin(PRECISION).of(
|
assertThat(totalUsage).isWithin(PRECISION).of(
|
||||||
BATTERY_SCREEN_USAGE + BATTERY_SYSTEM_USAGE + BATTERY_UNACCOUNTED_USAGE);
|
BATTERY_SYSTEM_USAGE + BATTERY_UNACCOUNTED_USAGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -259,4 +268,43 @@ public class BatteryUtilsTest {
|
|||||||
HIDDEN_USAGE, DISCHARGE_AMOUNT))
|
HIDDEN_USAGE, DISCHARGE_AMOUNT))
|
||||||
.isWithin(PRECISION).of(PERCENT_SYSTEM_USAGE);
|
.isWithin(PRECISION).of(PERCENT_SYSTEM_USAGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSmearScreenBatterySipper() {
|
||||||
|
final BatterySipper sipperNull = createTestSmearBatterySipper(TIME_FOREGROUND_ACTIVITY_ZERO,
|
||||||
|
BATTERY_APP_USAGE, 0 /* uid */, true /* isUidNull */);
|
||||||
|
final BatterySipper sipperBg = createTestSmearBatterySipper(TIME_FOREGROUND_ACTIVITY_ZERO,
|
||||||
|
BATTERY_APP_USAGE, 1 /* uid */, false /* isUidNull */);
|
||||||
|
final BatterySipper sipperFg = createTestSmearBatterySipper(TIME_FOREGROUND_ACTIVITY,
|
||||||
|
BATTERY_APP_USAGE, 2 /* uid */, false /* isUidNull */);
|
||||||
|
|
||||||
|
final List<BatterySipper> sippers = new ArrayList<>();
|
||||||
|
sippers.add(sipperNull);
|
||||||
|
sippers.add(sipperBg);
|
||||||
|
sippers.add(sipperFg);
|
||||||
|
|
||||||
|
mBatteryUtils.smearScreenBatterySipper(sippers, mScreenBatterySipper);
|
||||||
|
|
||||||
|
assertThat(sipperNull.totalPowerMah).isWithin(PRECISION).of(BATTERY_APP_USAGE);
|
||||||
|
assertThat(sipperBg.totalPowerMah).isWithin(PRECISION).of(BATTERY_APP_USAGE);
|
||||||
|
assertThat(sipperFg.totalPowerMah).isWithin(PRECISION).of(
|
||||||
|
BATTERY_APP_USAGE + BATTERY_SCREEN_USAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private BatterySipper createTestSmearBatterySipper(long activityTime, double totalPowerMah,
|
||||||
|
int uidCode, boolean isUidNull) {
|
||||||
|
final BatterySipper sipper = mock(BatterySipper.class);
|
||||||
|
sipper.drainType = BatterySipper.DrainType.APP;
|
||||||
|
sipper.totalPowerMah = totalPowerMah;
|
||||||
|
doReturn(uidCode).when(sipper).getUid();
|
||||||
|
if (!isUidNull) {
|
||||||
|
final BatteryStats.Uid uid = mock(BatteryStats.Uid.class, RETURNS_DEEP_STUBS);
|
||||||
|
doReturn(activityTime).when(mBatteryUtils).getForegroundActivityTotalTimeMs(eq(uid),
|
||||||
|
anyLong());
|
||||||
|
doReturn(uidCode).when(uid).getUid();
|
||||||
|
sipper.uidObj = uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sipper;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -68,6 +68,7 @@ import static org.mockito.Matchers.any;
|
|||||||
import static org.mockito.Matchers.anyLong;
|
import static org.mockito.Matchers.anyLong;
|
||||||
import static org.mockito.Matchers.anyString;
|
import static org.mockito.Matchers.anyString;
|
||||||
import static org.mockito.Matchers.eq;
|
import static org.mockito.Matchers.eq;
|
||||||
|
import static org.mockito.Mockito.doNothing;
|
||||||
import static org.mockito.Mockito.doReturn;
|
import static org.mockito.Mockito.doReturn;
|
||||||
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.never;
|
||||||
import static org.mockito.Mockito.spy;
|
import static org.mockito.Mockito.spy;
|
||||||
@@ -165,6 +166,7 @@ public class PowerUsageSummaryTest {
|
|||||||
mFragment.initFeatureProvider();
|
mFragment.initFeatureProvider();
|
||||||
mBatteryMeterView = spy(new BatteryMeterView(mRealContext));
|
mBatteryMeterView = spy(new BatteryMeterView(mRealContext));
|
||||||
mBatteryMeterView.mDrawable = new BatteryMeterView.BatteryMeterDrawable(mRealContext, 0);
|
mBatteryMeterView.mDrawable = new BatteryMeterView.BatteryMeterDrawable(mRealContext, 0);
|
||||||
|
doNothing().when(mFragment).restartBatteryStatsLoader();
|
||||||
|
|
||||||
when(mFragment.getActivity()).thenReturn(mSettingsActivity);
|
when(mFragment.getActivity()).thenReturn(mSettingsActivity);
|
||||||
when(mAdditionalBatteryInfoMenu.getItemId())
|
when(mAdditionalBatteryInfoMenu.getItemId())
|
||||||
|
Reference in New Issue
Block a user