Generate app and device screen-on time data and return back to UI for

rendering.

Test: make RunSettingsRoboTests + manually
Bug: 260964903
Change-Id: I2fd69b4686cc2e1413ad0eb43c07b6164e411411
This commit is contained in:
Kuan Wang
2022-12-26 16:33:18 +08:00
parent a3df41cacc
commit 1ce97c8ebe
11 changed files with 502 additions and 141 deletions

View File

@@ -0,0 +1,54 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.fuelgauge.batteryusage;
import androidx.annotation.Nullable;
import java.util.Locale;
import java.util.Map;
/** Wraps the battery usage data and device screen-on time data used for battery usage page. */
public class BatteryCallbackData {
// The usage app data used for rendering app list.
private final Map<Integer, Map<Integer, BatteryDiffData>> mBatteryUsageMap;
// The device screen-on time data.
private final Map<Integer, Map<Integer, Long>> mDeviceScreenOnTime;
public BatteryCallbackData(
@Nullable Map<Integer, Map<Integer, BatteryDiffData>> batteryUsageMap,
@Nullable Map<Integer, Map<Integer, Long>> deviceScreenOnTime) {
mBatteryUsageMap = batteryUsageMap;
mDeviceScreenOnTime = deviceScreenOnTime;
}
public Map<Integer, Map<Integer, BatteryDiffData>> getBatteryUsageMap() {
return mBatteryUsageMap;
}
public Map<Integer, Map<Integer, Long>> getDeviceScreenOnTime() {
return mDeviceScreenOnTime;
}
@Override
public String toString() {
return String.format(Locale.ENGLISH,
"batteryUsageMap: %s; deviceScreenOnTime: %s",
mBatteryUsageMap,
mDeviceScreenOnTime);
}
}

View File

@@ -210,8 +210,8 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
animateBatteryChartViewGroup(); animateBatteryChartViewGroup();
final BatteryLevelData batteryLevelData = final BatteryLevelData batteryLevelData =
DataProcessManager.getBatteryLevelData(mContext, mHandler, batteryHistoryMap, DataProcessManager.getBatteryLevelData(mContext, mHandler, batteryHistoryMap,
batteryUsageMap -> { batteryCallbackData -> {
mBatteryUsageMap = batteryUsageMap; mBatteryUsageMap = batteryCallbackData.getBatteryUsageMap();
refreshUi(); refreshUi();
}); });
Log.d(TAG, "getBatteryLevelData: " + batteryLevelData); Log.d(TAG, "getBatteryLevelData: " + batteryLevelData);

View File

@@ -53,6 +53,7 @@ public class BatteryDiffEntry {
public long mForegroundUsageTimeInMs; public long mForegroundUsageTimeInMs;
public long mBackgroundUsageTimeInMs; public long mBackgroundUsageTimeInMs;
public long mScreenOnTimeInMs;
public double mConsumePower; public double mConsumePower;
public double mForegroundUsageConsumePower; public double mForegroundUsageConsumePower;
public double mForegroundServiceUsageConsumePower; public double mForegroundServiceUsageConsumePower;
@@ -83,6 +84,7 @@ public class BatteryDiffEntry {
Context context, Context context,
long foregroundUsageTimeInMs, long foregroundUsageTimeInMs,
long backgroundUsageTimeInMs, long backgroundUsageTimeInMs,
long screenOnTimeInMs,
double consumePower, double consumePower,
double foregroundUsageConsumePower, double foregroundUsageConsumePower,
double foregroundServiceUsageConsumePower, double foregroundServiceUsageConsumePower,
@@ -97,6 +99,7 @@ public class BatteryDiffEntry {
mCachedUsageConsumePower = cachedUsageConsumePower; mCachedUsageConsumePower = cachedUsageConsumePower;
mForegroundUsageTimeInMs = foregroundUsageTimeInMs; mForegroundUsageTimeInMs = foregroundUsageTimeInMs;
mBackgroundUsageTimeInMs = backgroundUsageTimeInMs; mBackgroundUsageTimeInMs = backgroundUsageTimeInMs;
mScreenOnTimeInMs = screenOnTimeInMs;
mBatteryHistEntry = batteryHistEntry; mBatteryHistEntry = batteryHistEntry;
mUserManager = context.getSystemService(UserManager.class); mUserManager = context.getSystemService(UserManager.class);
} }
@@ -119,6 +122,7 @@ public class BatteryDiffEntry {
this.mContext, this.mContext,
this.mForegroundUsageTimeInMs, this.mForegroundUsageTimeInMs,
this.mBackgroundUsageTimeInMs, this.mBackgroundUsageTimeInMs,
this.mScreenOnTimeInMs,
this.mConsumePower, this.mConsumePower,
this.mForegroundUsageConsumePower, this.mForegroundUsageConsumePower,
this.mForegroundServiceUsageConsumePower, this.mForegroundServiceUsageConsumePower,
@@ -367,10 +371,12 @@ public class BatteryDiffEntry {
mForegroundUsageConsumePower, mForegroundServiceUsageConsumePower)) mForegroundUsageConsumePower, mForegroundServiceUsageConsumePower))
.append(String.format("\n\tconsume power= background:%f cached:%f", .append(String.format("\n\tconsume power= background:%f cached:%f",
mBackgroundUsageConsumePower, mCachedUsageConsumePower)) mBackgroundUsageConsumePower, mCachedUsageConsumePower))
.append(String.format("\n\ttime= foreground:%s background:%s", .append(String.format("\n\ttime= foreground:%s background:%s screen-on:%s",
StringUtil.formatElapsedTime(mContext, (double) mForegroundUsageTimeInMs, StringUtil.formatElapsedTime(mContext, (double) mForegroundUsageTimeInMs,
/*withSeconds=*/ true, /*collapseTimeUnit=*/ false), /*withSeconds=*/ true, /*collapseTimeUnit=*/ false),
StringUtil.formatElapsedTime(mContext, (double) mBackgroundUsageTimeInMs, StringUtil.formatElapsedTime(mContext, (double) mBackgroundUsageTimeInMs,
/*withSeconds=*/ true, /*collapseTimeUnit=*/ false),
StringUtil.formatElapsedTime(mContext, (double) mScreenOnTimeInMs,
/*withSeconds=*/ true, /*collapseTimeUnit=*/ false))) /*withSeconds=*/ true, /*collapseTimeUnit=*/ false)))
.append(String.format("\n\tpackage:%s|%s uid:%d userId:%d", .append(String.format("\n\tpackage:%s|%s uid:%d userId:%d",
mBatteryHistEntry.mPackageName, getPackageName(), mBatteryHistEntry.mPackageName, getPackageName(),

View File

@@ -330,9 +330,9 @@ public class DataProcessManager {
} }
private void loadAndApplyBatteryMapFromServiceOnly() { private void loadAndApplyBatteryMapFromServiceOnly() {
new AsyncTask<Void, Void, Map<Integer, Map<Integer, BatteryDiffData>>>() { new AsyncTask<Void, Void, BatteryCallbackData>() {
@Override @Override
protected Map<Integer, Map<Integer, BatteryDiffData>> doInBackground(Void... voids) { protected BatteryCallbackData doInBackground(Void... voids) {
final long startTime = System.currentTimeMillis(); final long startTime = System.currentTimeMillis();
final Map<Integer, Map<Integer, BatteryDiffData>> batteryUsageMap = final Map<Integer, Map<Integer, BatteryDiffData>> batteryUsageMap =
DataProcessor.getBatteryUsageMapFromStatsService(mContext); DataProcessor.getBatteryUsageMapFromStatsService(mContext);
@@ -340,18 +340,18 @@ public class DataProcessManager {
Log.d(TAG, String.format( Log.d(TAG, String.format(
"execute loadAndApplyBatteryMapFromServiceOnly size=%d in %d/ms", "execute loadAndApplyBatteryMapFromServiceOnly size=%d in %d/ms",
batteryUsageMap.size(), (System.currentTimeMillis() - startTime))); batteryUsageMap.size(), (System.currentTimeMillis() - startTime)));
return batteryUsageMap; return new BatteryCallbackData(batteryUsageMap, /*deviceScreenOnTime=*/ null);
} }
@Override @Override
protected void onPostExecute( protected void onPostExecute(
final Map<Integer, Map<Integer, BatteryDiffData>> batteryUsageMap) { final BatteryCallbackData batteryCallbackData) {
// Set the unused variables to null. // Set the unused variables to null.
mContext = null; mContext = null;
// Post results back to main thread to refresh UI. // Post results back to main thread to refresh UI.
if (mHandler != null && mCallbackFunction != null) { if (mHandler != null && mCallbackFunction != null) {
mHandler.post(() -> { mHandler.post(() -> {
mCallbackFunction.onBatteryUsageMapLoaded(batteryUsageMap); mCallbackFunction.onBatteryCallbackDataLoaded(batteryCallbackData);
}); });
} }
} }
@@ -391,12 +391,36 @@ public class DataProcessManager {
} }
private void generateFinalDataAndApplyCallback() { private void generateFinalDataAndApplyCallback() {
// TODO: generate the final data including battery usage map and device screen-on time and new AsyncTask<Void, Void, BatteryCallbackData>() {
// then apply the callback function. @Override
protected BatteryCallbackData doInBackground(Void... voids) {
final long startTime = System.currentTimeMillis();
final Map<Integer, Map<Integer, BatteryDiffData>> batteryUsageMap =
DataProcessor.getBatteryUsageMap(
mContext, mHourlyBatteryLevelsPerDay, mBatteryHistoryMap,
mAppUsagePeriodMap);
final Map<Integer, Map<Integer, Long>> deviceScreenOnTime =
DataProcessor.getDeviceScreenOnTime(mAppUsagePeriodMap);
DataProcessor.loadLabelAndIcon(batteryUsageMap);
Log.d(TAG, String.format("execute generateFinalDataAndApplyCallback in %d/ms",
(System.currentTimeMillis() - startTime)));
return new BatteryCallbackData(batteryUsageMap, deviceScreenOnTime);
}
@Override
protected void onPostExecute(final BatteryCallbackData batteryCallbackData) {
// Set the unused variables to null. // Set the unused variables to null.
mContext = null; mContext = null;
mHourlyBatteryLevelsPerDay = null; mHourlyBatteryLevelsPerDay = null;
mBatteryHistoryMap = null; mBatteryHistoryMap = null;
// Post results back to main thread to refresh UI.
if (mHandler != null && mCallbackFunction != null) {
mHandler.post(() -> {
mCallbackFunction.onBatteryCallbackDataLoaded(batteryCallbackData);
});
}
}
}.execute();
} }
// Whether we should load app usage data from service or database. // Whether we should load app usage data from service or database.
@@ -465,15 +489,13 @@ public class DataProcessManager {
return null; return null;
} }
// TODO: replace the task below with new DataProcessManager(...).start() after
// DataProcessManager is completed;
// Start the async task to compute diff usage data and load labels and icons. // Start the async task to compute diff usage data and load labels and icons.
new DataProcessor.ComputeUsageMapAndLoadItemsTask( new DataProcessManager(
context, context,
handler, handler,
asyncResponseDelegate, asyncResponseDelegate,
batteryLevelData.getHourlyBatteryLevelsPerDay(), batteryLevelData.getHourlyBatteryLevelsPerDay(),
processedBatteryHistoryMap).execute(); processedBatteryHistoryMap).start();
return batteryLevelData; return batteryLevelData;
} }

View File

@@ -27,12 +27,10 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.UserInfo; import android.content.pm.UserInfo;
import android.os.AsyncTask;
import android.os.BatteryConsumer; import android.os.BatteryConsumer;
import android.os.BatteryStatsManager; import android.os.BatteryStatsManager;
import android.os.BatteryUsageStats; import android.os.BatteryUsageStats;
import android.os.BatteryUsageStatsQuery; import android.os.BatteryUsageStatsQuery;
import android.os.Handler;
import android.os.Process; import android.os.Process;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.ServiceManager; import android.os.ServiceManager;
@@ -68,6 +66,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream;
/** /**
* A utility class to process data loaded from database and make the data easy to use for battery * A utility class to process data loaded from database and make the data easy to use for battery
@@ -111,8 +110,7 @@ public final class DataProcessor {
/** A callback listener when battery usage loading async task is executed. */ /** A callback listener when battery usage loading async task is executed. */
public interface UsageMapAsyncResponse { public interface UsageMapAsyncResponse {
/** The callback function when batteryUsageMap is loaded. */ /** The callback function when batteryUsageMap is loaded. */
void onBatteryUsageMapLoaded( void onBatteryCallbackDataLoaded(BatteryCallbackData batteryCallbackData);
Map<Integer, Map<Integer, BatteryDiffData>> batteryUsageMap);
} }
private DataProcessor() { private DataProcessor() {
@@ -141,7 +139,8 @@ public final class DataProcessor {
: getBatteryUsageMap( : getBatteryUsageMap(
context, context,
batteryLevelData.getHourlyBatteryLevelsPerDay(), batteryLevelData.getHourlyBatteryLevelsPerDay(),
processedBatteryHistoryMap); processedBatteryHistoryMap,
/*appUsagePeriodMap=*/ null);
} }
/** /**
@@ -364,6 +363,35 @@ public final class DataProcessor {
return appUsageEventList; return appUsageEventList;
} }
/**
* @return Returns the device screen-on time data.
*
* <p>There could be 2 cases of the returned value:</p>
* <ul>
* <li>null: empty or invalid data.</li>
* <li>non-null: must be a 2d map and composed by 3 parts:</li>
* <p> 1 - [SELECTED_INDEX_ALL][SELECTED_INDEX_ALL]</p>
* <p> 2 - [0][SELECTED_INDEX_ALL] ~ [maxDailyIndex][SELECTED_INDEX_ALL]</p>
* <p> 3 - [0][0] ~ [maxDailyIndex][maxHourlyIndex]</p>
* </ul>
*
* <p>The structure is consistent with the battery usage map returned by
* {@code getBatteryUsageMap}.</p>
*/
@Nullable
public static Map<Integer, Map<Integer, Long>> getDeviceScreenOnTime(
final Map<Integer, Map<Integer, Map<Long, Map<String, List<AppUsagePeriod>>>>>
appUsagePeriodMap) {
if (appUsagePeriodMap == null) {
return null;
}
final Map<Integer, Map<Integer, Long>> deviceScreenOnTime = new HashMap<>();
insertHourlyDeviceScreenOnTime(appUsagePeriodMap, deviceScreenOnTime);
insertDailyDeviceScreenOnTime(appUsagePeriodMap, deviceScreenOnTime);
insertAllDeviceScreenOnTime(deviceScreenOnTime);
return deviceScreenOnTime;
}
/** /**
* Generates the list of {@link BatteryEntry} from the supplied {@link BatteryUsageStats}. * Generates the list of {@link BatteryEntry} from the supplied {@link BatteryUsageStats}.
*/ */
@@ -597,19 +625,21 @@ public final class DataProcessor {
* <p> 3 - [0][0] ~ [maxDailyIndex][maxHourlyIndex]</p> * <p> 3 - [0][0] ~ [maxDailyIndex][maxHourlyIndex]</p>
* </ul> * </ul>
*/ */
@VisibleForTesting
@Nullable @Nullable
static Map<Integer, Map<Integer, BatteryDiffData>> getBatteryUsageMap( static Map<Integer, Map<Integer, BatteryDiffData>> getBatteryUsageMap(
final Context context, final Context context,
final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay, final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay,
final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap) { final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap,
final Map<Integer, Map<Integer, Map<Long, Map<String, List<AppUsagePeriod>>>>>
appUsagePeriodMap) {
if (batteryHistoryMap.isEmpty()) { if (batteryHistoryMap.isEmpty()) {
return null; return null;
} }
final Map<Integer, Map<Integer, BatteryDiffData>> resultMap = new HashMap<>(); final Map<Integer, Map<Integer, BatteryDiffData>> resultMap = new HashMap<>();
// Insert diff data from [0][0] to [maxDailyIndex][maxHourlyIndex]. // Insert diff data from [0][0] to [maxDailyIndex][maxHourlyIndex].
insertHourlyUsageDiffData( insertHourlyUsageDiffData(
context, hourlyBatteryLevelsPerDay, batteryHistoryMap, resultMap); context, hourlyBatteryLevelsPerDay, batteryHistoryMap, appUsagePeriodMap,
resultMap);
// Insert diff data from [0][SELECTED_INDEX_ALL] to [maxDailyIndex][SELECTED_INDEX_ALL]. // Insert diff data from [0][SELECTED_INDEX_ALL] to [maxDailyIndex][SELECTED_INDEX_ALL].
insertDailyUsageDiffData(hourlyBatteryLevelsPerDay, resultMap); insertDailyUsageDiffData(hourlyBatteryLevelsPerDay, resultMap);
// Insert diff data [SELECTED_INDEX_ALL][SELECTED_INDEX_ALL]. // Insert diff data [SELECTED_INDEX_ALL][SELECTED_INDEX_ALL].
@@ -649,6 +679,7 @@ public final class DataProcessor {
context, context,
entry.mForegroundUsageTimeInMs, entry.mForegroundUsageTimeInMs,
entry.mBackgroundUsageTimeInMs, entry.mBackgroundUsageTimeInMs,
/*screenOnTimeInMs=*/ 0,
entry.mConsumePower, entry.mConsumePower,
entry.mForegroundUsageConsumePower, entry.mForegroundUsageConsumePower,
entry.mForegroundServiceUsageConsumePower, entry.mForegroundServiceUsageConsumePower,
@@ -805,6 +836,18 @@ public final class DataProcessor {
return usagePeriodList; return usagePeriodList;
} }
@VisibleForTesting
static long getScreenOnTime(
final Map<Long, Map<String, List<AppUsagePeriod>>> appUsageMap,
final long userId,
final String packageName) {
if (appUsageMap == null || appUsageMap.get(userId) == null) {
return 0;
}
return getScreenOnTime(appUsageMap.get(userId).get(packageName));
}
/** /**
* @return Returns the overall battery usage data from battery stats service directly. * @return Returns the overall battery usage data from battery stats service directly.
* *
@@ -889,6 +932,84 @@ public final class DataProcessor {
return currentIndex; return currentIndex;
} }
private static void insertHourlyDeviceScreenOnTime(
final Map<Integer, Map<Integer, Map<Long, Map<String, List<AppUsagePeriod>>>>>
appUsagePeriodMap,
final Map<Integer, Map<Integer, Long>> resultMap) {
for (final int dailyIndex : appUsagePeriodMap.keySet()) {
final Map<Integer, Map<Long, Map<String, List<AppUsagePeriod>>>> dailyAppUsageMap =
appUsagePeriodMap.get(dailyIndex);
final Map<Integer, Long> dailyScreenOnTime = new HashMap<>();
resultMap.put(dailyIndex, dailyScreenOnTime);
if (dailyAppUsageMap == null) {
continue;
}
for (final int hourlyIndex : dailyAppUsageMap.keySet()) {
final Map<Long, Map<String, List<AppUsagePeriod>>> appUsageMap =
dailyAppUsageMap.get(hourlyIndex);
if (appUsageMap == null || appUsageMap.isEmpty()) {
dailyScreenOnTime.put(hourlyIndex, 0L);
} else {
final List<AppUsagePeriod> flatUsageList = new ArrayList<>();
for (final long userId: appUsageMap.keySet()) {
if (appUsageMap.get(userId) == null) {
continue;
}
for (final String packageName: appUsageMap.get(userId).keySet()) {
final List<AppUsagePeriod> appUsagePeriodList =
appUsageMap.get(userId).get(packageName);
if (appUsagePeriodList != null && !appUsagePeriodList.isEmpty()) {
flatUsageList.addAll(appUsagePeriodList);
}
}
}
// Compute the screen on time and make sure it won't exceed the threshold.
final long screenOnTime = Math.min(
(long) TOTAL_HOURLY_TIME_THRESHOLD, getScreenOnTime(flatUsageList));
dailyScreenOnTime.put(hourlyIndex, screenOnTime);
}
}
}
}
private static void insertDailyDeviceScreenOnTime(
final Map<Integer, Map<Integer, Map<Long, Map<String, List<AppUsagePeriod>>>>>
appUsagePeriodMap,
final Map<Integer, Map<Integer, Long>> resultMap) {
for (final int dailyIndex : appUsagePeriodMap.keySet()) {
Map<Integer, Long> dailyResultMap = resultMap.get(dailyIndex);
if (dailyResultMap == null) {
dailyResultMap = new HashMap<>();
resultMap.put(dailyIndex, dailyResultMap);
}
dailyResultMap.put(
SELECTED_INDEX_ALL,
getAccumulatedScreenOnTime(dailyResultMap));
}
}
private static void insertAllDeviceScreenOnTime(
final Map<Integer, Map<Integer, Long>> resultMap) {
final Map<Integer, Long> dailyAllMap = new HashMap<>();
resultMap.keySet().forEach(
key -> dailyAllMap.put(key, resultMap.get(key).get(SELECTED_INDEX_ALL)));
final Map<Integer, Long> allUsageMap = new HashMap<>();
allUsageMap.put(SELECTED_INDEX_ALL, getAccumulatedScreenOnTime(dailyAllMap));
resultMap.put(SELECTED_INDEX_ALL, allUsageMap);
}
private static long getAccumulatedScreenOnTime(final Map<Integer, Long> screenOnTimeMap) {
if (screenOnTimeMap == null || screenOnTimeMap.isEmpty()) {
return 0;
}
long sum = 0;
for (final int index : screenOnTimeMap.keySet()) {
sum += screenOnTimeMap.get(index) == null ? 0 : screenOnTimeMap.get(index);
}
return sum;
}
@Nullable @Nullable
private static UsageEvents getAppUsageEventsForUser( private static UsageEvents getAppUsageEventsForUser(
Context context, final UserManager userManager, final int userID, Context context, final UserManager userManager, final int userID,
@@ -1226,6 +1347,8 @@ public final class DataProcessor {
Context context, Context context,
final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay, final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay,
final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap, final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap,
final Map<Integer, Map<Integer, Map<Long, Map<String, List<AppUsagePeriod>>>>>
appUsagePeriodMap,
final Map<Integer, Map<Integer, BatteryDiffData>> resultMap) { final Map<Integer, Map<Integer, BatteryDiffData>> resultMap) {
final int currentUserId = context.getUserId(); final int currentUserId = context.getUserId();
final UserHandle userHandle = final UserHandle userHandle =
@@ -1251,6 +1374,10 @@ public final class DataProcessor {
workProfileUserId, workProfileUserId,
hourlyIndex, hourlyIndex,
timestamps, timestamps,
appUsagePeriodMap == null
|| appUsagePeriodMap.get(dailyIndex) == null
? null
: appUsagePeriodMap.get(dailyIndex).get(hourlyIndex),
batteryHistoryMap); batteryHistoryMap);
dailyDiffMap.put(hourlyIndex, hourlyBatteryDiffData); dailyDiffMap.put(hourlyIndex, hourlyBatteryDiffData);
} }
@@ -1289,6 +1416,7 @@ public final class DataProcessor {
final int workProfileUserId, final int workProfileUserId,
final int currentIndex, final int currentIndex,
final List<Long> timestamps, final List<Long> timestamps,
final Map<Long, Map<String, List<AppUsagePeriod>>> appUsageMap,
final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap) { final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap) {
final List<BatteryDiffEntry> appEntries = new ArrayList<>(); final List<BatteryDiffEntry> appEntries = new ArrayList<>();
final List<BatteryDiffEntry> systemEntries = new ArrayList<>(); final List<BatteryDiffEntry> systemEntries = new ArrayList<>();
@@ -1405,10 +1533,18 @@ public final class DataProcessor {
cachedUsageConsumePower = cachedUsageConsumePower * ratio; cachedUsageConsumePower = cachedUsageConsumePower * ratio;
} }
// Compute the screen on time and make sure it won't exceed the threshold.
final long screenOnTime = Math.min(
(long) TOTAL_HOURLY_TIME_THRESHOLD,
getScreenOnTime(
appUsageMap,
selectedBatteryEntry.mUserId,
selectedBatteryEntry.mPackageName));
final BatteryDiffEntry currentBatteryDiffEntry = new BatteryDiffEntry( final BatteryDiffEntry currentBatteryDiffEntry = new BatteryDiffEntry(
context, context,
foregroundUsageTimeInMs, foregroundUsageTimeInMs,
backgroundUsageTimeInMs, backgroundUsageTimeInMs,
screenOnTime,
consumePower, consumePower,
foregroundUsageConsumePower, foregroundUsageConsumePower,
foregroundServiceUsageConsumePower, foregroundServiceUsageConsumePower,
@@ -1430,6 +1566,49 @@ public final class DataProcessor {
return new BatteryDiffData(appEntries, systemEntries); return new BatteryDiffData(appEntries, systemEntries);
} }
private static long getScreenOnTime(@Nullable final List<AppUsagePeriod> appUsagePeriodList) {
if (appUsagePeriodList == null || appUsagePeriodList.isEmpty()) {
return 0;
}
// Create a list of endpoints (the beginning or the end) of usage periods and order the list
// chronologically.
final List<AppUsageEndPoint> endPoints =
appUsagePeriodList.stream()
.flatMap(
foregroundUsage ->
Stream.of(
AppUsageEndPoint.newBuilder()
.setTimestamp(
foregroundUsage.getStartTime())
.setType(AppUsageEndPointType.START)
.build(),
AppUsageEndPoint.newBuilder()
.setTimestamp(foregroundUsage.getEndTime())
.setType(AppUsageEndPointType.END)
.build()))
.sorted((x, y) -> (int) (x.getTimestamp() - y.getTimestamp()))
.collect(Collectors.toList());
// Traverse the list of endpoints in order to determine the non-overlapping usage duration.
int numberOfActiveAppUsagePeriods = 0;
long startOfCurrentContiguousAppUsagePeriod = 0;
long totalScreenOnTime = 0;
for (final AppUsageEndPoint endPoint : endPoints) {
if (endPoint.getType() == AppUsageEndPointType.START) {
if (numberOfActiveAppUsagePeriods++ == 0) {
startOfCurrentContiguousAppUsagePeriod = endPoint.getTimestamp();
}
} else {
if (--numberOfActiveAppUsagePeriods == 0) {
totalScreenOnTime +=
(endPoint.getTimestamp() - startOfCurrentContiguousAppUsagePeriod);
}
}
}
return totalScreenOnTime;
}
private static boolean isConsumedFromOtherUsers( private static boolean isConsumedFromOtherUsers(
final int currentUserId, final int currentUserId,
final int workProfileUserId, final int workProfileUserId,
@@ -1484,6 +1663,8 @@ public final class DataProcessor {
entry.mForegroundUsageTimeInMs; entry.mForegroundUsageTimeInMs;
oldBatteryDiffEntry.mBackgroundUsageTimeInMs += oldBatteryDiffEntry.mBackgroundUsageTimeInMs +=
entry.mBackgroundUsageTimeInMs; entry.mBackgroundUsageTimeInMs;
oldBatteryDiffEntry.mScreenOnTimeInMs +=
entry.mScreenOnTimeInMs;
oldBatteryDiffEntry.mConsumePower += entry.mConsumePower; oldBatteryDiffEntry.mConsumePower += entry.mConsumePower;
oldBatteryDiffEntry.mForegroundUsageConsumePower += entry.mForegroundUsageConsumePower; oldBatteryDiffEntry.mForegroundUsageConsumePower += entry.mForegroundUsageConsumePower;
oldBatteryDiffEntry.mForegroundServiceUsageConsumePower oldBatteryDiffEntry.mForegroundServiceUsageConsumePower
@@ -1752,73 +1933,4 @@ public final class DataProcessor {
utcToLocalTime(context, timestamp), content, entry)); utcToLocalTime(context, timestamp), content, entry));
} }
} }
// Compute diff map and loads all items (icon and label) in the background.
static class ComputeUsageMapAndLoadItemsTask
extends AsyncTask<Void, Void, Map<Integer, Map<Integer, BatteryDiffData>>> {
Context mApplicationContext;
final Handler mHandler;
final UsageMapAsyncResponse mAsyncResponseDelegate;
private List<BatteryLevelData.PeriodBatteryLevelData> mHourlyBatteryLevelsPerDay;
private Map<Long, Map<String, BatteryHistEntry>> mBatteryHistoryMap;
ComputeUsageMapAndLoadItemsTask(
Context context,
Handler handler,
final UsageMapAsyncResponse asyncResponseDelegate,
final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay,
final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap) {
mApplicationContext = context.getApplicationContext();
mHandler = handler;
mAsyncResponseDelegate = asyncResponseDelegate;
mHourlyBatteryLevelsPerDay = hourlyBatteryLevelsPerDay;
mBatteryHistoryMap = batteryHistoryMap;
}
@Override
protected Map<Integer, Map<Integer, BatteryDiffData>> doInBackground(Void... voids) {
if (mApplicationContext == null
|| mHandler == null
|| mAsyncResponseDelegate == null
|| mBatteryHistoryMap == null
|| mHourlyBatteryLevelsPerDay == null) {
Log.e(TAG, "invalid input for ComputeUsageMapAndLoadItemsTask()");
return null;
}
final long startTime = System.currentTimeMillis();
// Loads the current battery usage data from the battery stats service and replaces the
// placeholder in mBatteryHistoryMap.
Map<String, BatteryHistEntry> currentBatteryHistoryMap =
getCurrentBatteryHistoryMapFromStatsService(mApplicationContext);
for (Map.Entry<Long, Map<String, BatteryHistEntry>> mapEntry
: mBatteryHistoryMap.entrySet()) {
if (mapEntry.getValue().containsKey(CURRENT_TIME_BATTERY_HISTORY_PLACEHOLDER)) {
mapEntry.setValue(currentBatteryHistoryMap);
}
}
final Map<Integer, Map<Integer, BatteryDiffData>> batteryUsageMap =
getBatteryUsageMap(
mApplicationContext, mHourlyBatteryLevelsPerDay, mBatteryHistoryMap);
loadLabelAndIcon(batteryUsageMap);
Log.d(TAG, String.format("execute ComputeUsageMapAndLoadItemsTask in %d/ms",
(System.currentTimeMillis() - startTime)));
return batteryUsageMap;
}
@Override
protected void onPostExecute(
final Map<Integer, Map<Integer, BatteryDiffData>> batteryUsageMap) {
mApplicationContext = null;
mHourlyBatteryLevelsPerDay = null;
mBatteryHistoryMap = null;
// Post results back to main thread to refresh UI.
if (mHandler != null && mAsyncResponseDelegate != null) {
mHandler.post(() -> {
mAsyncResponseDelegate.onBatteryUsageMapLoaded(batteryUsageMap);
});
}
}
}
} }

View File

@@ -40,3 +40,16 @@ message AppUsagePeriod {
// End of the usage period. // End of the usage period.
optional int64 end_time = 2; optional int64 end_time = 2;
} }
enum AppUsageEndPointType {
START = 1;
END = 2;
}
// The endpoint (the beginning or the end) of an AppUsagePeriod.
message AppUsageEndPoint {
// Type of the end point.
optional AppUsageEndPointType type = 1;
// Timestamp of the end point.
optional int64 timestamp = 2;
}

View File

@@ -37,6 +37,7 @@ import android.content.res.Resources;
import android.os.BatteryManager; import android.os.BatteryManager;
import android.os.Bundle; import android.os.Bundle;
import android.os.LocaleList; import android.os.LocaleList;
import android.os.UserManager;
import android.text.format.DateUtils; import android.text.format.DateUtils;
import android.view.View; import android.view.View;
import android.view.ViewPropertyAnimator; import android.view.ViewPropertyAnimator;
@@ -65,9 +66,9 @@ public final class BatteryChartPreferenceControllerTest {
@Mock @Mock
private Intent mIntent; private Intent mIntent;
@Mock @Mock
private SettingsActivity mSettingsActivity; private UserManager mUserManager;
@Mock @Mock
private BatteryHistEntry mBatteryHistEntry; private SettingsActivity mSettingsActivity;
@Mock @Mock
private BatteryChartView mDailyChartView; private BatteryChartView mDailyChartView;
@Mock @Mock
@@ -79,7 +80,6 @@ public final class BatteryChartPreferenceControllerTest {
private Context mContext; private Context mContext;
private FakeFeatureFactory mFeatureFactory; private FakeFeatureFactory mFeatureFactory;
private BatteryDiffEntry mBatteryDiffEntry;
private BatteryChartPreferenceController mBatteryChartPreferenceController; private BatteryChartPreferenceController mBatteryChartPreferenceController;
@Before @Before
@@ -90,6 +90,11 @@ public final class BatteryChartPreferenceControllerTest {
TimeZone.setDefault(TimeZone.getTimeZone("UTC")); TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
mFeatureFactory = FakeFeatureFactory.setupForTest(); mFeatureFactory = FakeFeatureFactory.setupForTest();
mContext = spy(RuntimeEnvironment.application); mContext = spy(RuntimeEnvironment.application);
doReturn(mContext).when(mContext).getApplicationContext();
doReturn(mUserManager)
.when(mContext)
.getSystemService(UserManager.class);
doReturn(true).when(mUserManager).isUserUnlocked(anyInt());
final Resources resources = spy(mContext.getResources()); final Resources resources = spy(mContext.getResources());
resources.getConfiguration().setLocales(new LocaleList(new Locale("en_US"))); resources.getConfiguration().setLocales(new LocaleList(new Locale("en_US")));
doReturn(resources).when(mContext).getResources(); doReturn(resources).when(mContext).getResources();
@@ -105,17 +110,6 @@ public final class BatteryChartPreferenceControllerTest {
mBatteryChartPreferenceController.mPrefContext = mContext; mBatteryChartPreferenceController.mPrefContext = mContext;
mBatteryChartPreferenceController.mDailyChartView = mDailyChartView; mBatteryChartPreferenceController.mDailyChartView = mDailyChartView;
mBatteryChartPreferenceController.mHourlyChartView = mHourlyChartView; mBatteryChartPreferenceController.mHourlyChartView = mHourlyChartView;
mBatteryDiffEntry = new BatteryDiffEntry(
mContext,
/*foregroundUsageTimeInMs=*/ 1,
/*backgroundUsageTimeInMs=*/ 2,
/*consumePower=*/ 3,
/*foregroundUsageConsumePower=*/ 0,
/*foregroundServiceUsageConsumePower=*/ 1,
/*backgroundUsageConsumePower=*/ 2,
/*cachedUsageConsumePower=*/ 0,
mBatteryHistEntry);
mBatteryDiffEntry = spy(mBatteryDiffEntry);
// Adds fake testing data. // Adds fake testing data.
BatteryDiffEntry.sResourceCache.put( BatteryDiffEntry.sResourceCache.put(
"fakeBatteryDiffEntryKey", "fakeBatteryDiffEntryKey",
@@ -403,6 +397,7 @@ public final class BatteryChartPreferenceControllerTest {
.build(); .build();
values.put(BatteryHistEntry.KEY_BATTERY_INFORMATION, values.put(BatteryHistEntry.KEY_BATTERY_INFORMATION,
ConvertUtils.convertBatteryInformationToString(batteryInformation)); ConvertUtils.convertBatteryInformationToString(batteryInformation));
values.put(BatteryHistEntry.KEY_PACKAGE_NAME, "package" + index);
final BatteryHistEntry entry = new BatteryHistEntry(values); final BatteryHistEntry entry = new BatteryHistEntry(values);
final Map<String, BatteryHistEntry> entryMap = new HashMap<>(); final Map<String, BatteryHistEntry> entryMap = new HashMap<>();
entryMap.put("fake_entry_key" + index, entry); entryMap.put("fake_entry_key" + index, entry);

View File

@@ -97,6 +97,7 @@ public final class BatteryDiffEntryTest {
mContext, mContext,
/*foregroundUsageTimeInMs=*/ 10001L, /*foregroundUsageTimeInMs=*/ 10001L,
/*backgroundUsageTimeInMs=*/ 20002L, /*backgroundUsageTimeInMs=*/ 20002L,
/*screenOnTimeInMs=*/ 30003L,
/*consumePower=*/ 22.0, /*consumePower=*/ 22.0,
/*foregroundUsageConsumePower=*/ 10.0, /*foregroundUsageConsumePower=*/ 10.0,
/*foregroundServiceUsageConsumePower=*/ 10.0, /*foregroundServiceUsageConsumePower=*/ 10.0,
@@ -115,6 +116,7 @@ public final class BatteryDiffEntryTest {
mContext, mContext,
/*foregroundUsageTimeInMs=*/ 10001L, /*foregroundUsageTimeInMs=*/ 10001L,
/*backgroundUsageTimeInMs=*/ 20002L, /*backgroundUsageTimeInMs=*/ 20002L,
/*screenOnTimeInMs=*/ 30003L,
/*consumePower=*/ 22.0, /*consumePower=*/ 22.0,
/*foregroundUsageConsumePower=*/ 10.0, /*foregroundUsageConsumePower=*/ 10.0,
/*foregroundServiceUsageConsumePower=*/ 10.0, /*foregroundServiceUsageConsumePower=*/ 10.0,
@@ -479,6 +481,7 @@ public final class BatteryDiffEntryTest {
mContext, mContext,
/*foregroundUsageTimeInMs=*/ 0, /*foregroundUsageTimeInMs=*/ 0,
/*backgroundUsageTimeInMs=*/ 0, /*backgroundUsageTimeInMs=*/ 0,
/*screenOnTimeInMs=*/ 0,
/*consumePower=*/ 0, /*consumePower=*/ 0,
/*foregroundUsageConsumePower=*/ 0, /*foregroundUsageConsumePower=*/ 0,
/*foregroundServiceUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0,
@@ -493,6 +496,7 @@ public final class BatteryDiffEntryTest {
mContext, mContext,
/*foregroundUsageTimeInMs=*/ 0, /*foregroundUsageTimeInMs=*/ 0,
/*backgroundUsageTimeInMs=*/ 0, /*backgroundUsageTimeInMs=*/ 0,
/*screenOnTimeInMs=*/ 0,
consumePower, consumePower,
/*foregroundUsageConsumePower=*/ 0, /*foregroundUsageConsumePower=*/ 0,
/*foregroundServiceUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0,

View File

@@ -96,6 +96,7 @@ public final class BatteryUsageBreakdownControllerTest {
mContext, mContext,
/*foregroundUsageTimeInMs=*/ 1, /*foregroundUsageTimeInMs=*/ 1,
/*backgroundUsageTimeInMs=*/ 2, /*backgroundUsageTimeInMs=*/ 2,
/*screenOnTimeInMs=*/ 0,
/*consumePower=*/ 3, /*consumePower=*/ 3,
/*foregroundUsageConsumePower=*/ 0, /*foregroundUsageConsumePower=*/ 0,
/*foregroundServiceUsageConsumePower=*/ 1, /*foregroundServiceUsageConsumePower=*/ 1,
@@ -297,10 +298,10 @@ public final class BatteryUsageBreakdownControllerTest {
private BatteryDiffEntry createBatteryDiffEntry( private BatteryDiffEntry createBatteryDiffEntry(
long foregroundUsageTimeInMs, long backgroundUsageTimeInMs) { long foregroundUsageTimeInMs, long backgroundUsageTimeInMs) {
return new BatteryDiffEntry( return new BatteryDiffEntry(
mContext, foregroundUsageTimeInMs, backgroundUsageTimeInMs, /*consumePower=*/ 0, mContext, foregroundUsageTimeInMs, backgroundUsageTimeInMs, /*screenOnTimeInMs=*/ 0,
/*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0, /*consumePower=*/ 0, /*foregroundUsageConsumePower=*/ 0,
/*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0, /*backgroundUsageConsumePower=*/ 0,
mBatteryHistEntry); /*cachedUsageConsumePower=*/ 0, mBatteryHistEntry);
} }
private BatteryUsageBreakdownController createController() { private BatteryUsageBreakdownController createController() {

View File

@@ -83,7 +83,8 @@ public final class DataProcessManagerTest {
mDataProcessManager = new DataProcessManager( mDataProcessManager = new DataProcessManager(
mContext, /*handler=*/ null, /*callbackFunction=*/ null, mContext, /*handler=*/ null, /*callbackFunction=*/ null,
/*hourlyBatteryLevelsPerDay=*/ new ArrayList<>(), /*batteryHistoryMap=*/ null); /*hourlyBatteryLevelsPerDay=*/ new ArrayList<>(),
/*batteryHistoryMap=*/ new HashMap<>());
} }
@Test @Test
@@ -174,7 +175,7 @@ public final class DataProcessManagerTest {
final DataProcessManager dataProcessManager = new DataProcessManager( final DataProcessManager dataProcessManager = new DataProcessManager(
mContext, /*handler=*/ null, /*callbackFunction=*/ null, mContext, /*handler=*/ null, /*callbackFunction=*/ null,
hourlyBatteryLevelsPerDay, /*batteryHistoryMap=*/ null); hourlyBatteryLevelsPerDay, /*batteryHistoryMap=*/ new HashMap<>());
dataProcessManager.start(); dataProcessManager.start();
assertThat(dataProcessManager.getIsCurrentAppUsageLoaded()).isTrue(); assertThat(dataProcessManager.getIsCurrentAppUsageLoaded()).isTrue();

View File

@@ -310,6 +310,62 @@ public final class DataProcessorTest {
appUsageEventList.get(2), AppUsageEventType.DEVICE_SHUTDOWN, /*timestamp=*/ 4); appUsageEventList.get(2), AppUsageEventType.DEVICE_SHUTDOWN, /*timestamp=*/ 4);
} }
@Test
public void getDeviceScreenOnTime_returnExpectedResult() {
final Map<Integer, Map<Integer, Map<Long, Map<String, List<AppUsagePeriod>>>>>
appUsagePeriodMap = new HashMap<>();
appUsagePeriodMap.put(0, new HashMap<>());
appUsagePeriodMap.put(1, new HashMap<>());
appUsagePeriodMap.put(2, null);
final long userId1 = 1;
final long userId2 = 2;
// Adds the index [0][0].
Map<Long, Map<String, List<AppUsagePeriod>>> appUsageMap = new HashMap<>();
Map<String, List<AppUsagePeriod>> userPeriodMap = new HashMap<>();
appUsageMap.put(userId1, userPeriodMap);
userPeriodMap.put(
"package1", List.of(buildAppUsagePeriod(0, 5), buildAppUsagePeriod(5, 7)));
userPeriodMap.put("package2", List.of(buildAppUsagePeriod(10, 25)));
userPeriodMap = new HashMap<>();
appUsageMap.put(userId2, userPeriodMap);
userPeriodMap.put("package3", List.of(buildAppUsagePeriod(15, 45)));
appUsagePeriodMap.get(0).put(0, appUsageMap);
// Adds the index [0][1].
appUsageMap = new HashMap<>();
userPeriodMap = new HashMap<>();
appUsageMap.put(userId1, userPeriodMap);
userPeriodMap.put(
"package1", List.of(buildAppUsagePeriod(50, 60), buildAppUsagePeriod(70, 80)));
appUsagePeriodMap.get(0).put(1, appUsageMap);
// Adds the index [1][0].
appUsageMap = new HashMap<>();
userPeriodMap = new HashMap<>();
appUsageMap.put(userId1, userPeriodMap);
userPeriodMap.put("package2", List.of(buildAppUsagePeriod(0, 8000000L)));
userPeriodMap.put("package3",
List.of(buildAppUsagePeriod(10, 15), buildAppUsagePeriod(25, 29)));
appUsagePeriodMap.get(1).put(0, appUsageMap);
final Map<Integer, Map<Integer, Long>> deviceScreenOnTime =
DataProcessor.getDeviceScreenOnTime(appUsagePeriodMap);
assertThat(deviceScreenOnTime.get(0).get(0)).isEqualTo(42);
assertThat(deviceScreenOnTime.get(0).get(1)).isEqualTo(20);
assertThat(deviceScreenOnTime.get(1).get(0)).isEqualTo(7200000);
assertThat(deviceScreenOnTime.get(0).get(DataProcessor.SELECTED_INDEX_ALL)).isEqualTo(62);
assertThat(deviceScreenOnTime.get(1).get(DataProcessor.SELECTED_INDEX_ALL))
.isEqualTo(7200000);
assertThat(deviceScreenOnTime
.get(DataProcessor.SELECTED_INDEX_ALL)
.get(DataProcessor.SELECTED_INDEX_ALL))
.isEqualTo(7200062);
}
@Test
public void getDeviceScreenOnTime_nullUsageMap_returnNull() {
assertThat(DataProcessor.getDeviceScreenOnTime(null)).isNull();
}
@Test @Test
public void getHistoryMapWithExpectedTimestamps_emptyHistoryMap_returnEmptyMap() { public void getHistoryMapWithExpectedTimestamps_emptyHistoryMap_returnEmptyMap() {
assertThat(DataProcessor assertThat(DataProcessor
@@ -493,12 +549,12 @@ public final class DataProcessorTest {
final Calendar startCalendar = Calendar.getInstance(); final Calendar startCalendar = Calendar.getInstance();
startCalendar.set(2022, 6, 5, 5, 0, 50); // 2022-07-05 05:00:50 startCalendar.set(2022, 6, 5, 5, 0, 50); // 2022-07-05 05:00:50
final Calendar endCalendar = Calendar.getInstance(); final Calendar endCalendar = Calendar.getInstance();
endCalendar.set(2022, 6, 6, 21, 00, 50); // 2022-07-06 21:00:50 endCalendar.set(2022, 6, 6, 21, 0, 50); // 2022-07-06 21:00:50
final Calendar expectedStartCalendar = Calendar.getInstance(); final Calendar expectedStartCalendar = Calendar.getInstance();
expectedStartCalendar.set(2022, 6, 5, 6, 00, 00); // 2022-07-05 06:00:00 expectedStartCalendar.set(2022, 6, 5, 6, 0, 0); // 2022-07-05 06:00:00
final Calendar expectedEndCalendar = Calendar.getInstance(); final Calendar expectedEndCalendar = Calendar.getInstance();
expectedEndCalendar.set(2022, 6, 6, 22, 00, 00); // 2022-07-06 20:00:00 expectedEndCalendar.set(2022, 6, 6, 22, 0, 0); // 2022-07-06 20:00:00
verifyExpectedTimestampSlots( verifyExpectedTimestampSlots(
startCalendar, endCalendar, expectedStartCalendar, expectedEndCalendar); startCalendar, endCalendar, expectedStartCalendar, expectedEndCalendar);
} }
@@ -692,7 +748,8 @@ public final class DataProcessorTest {
new BatteryLevelData.PeriodBatteryLevelData(new ArrayList<>(), new ArrayList<>())); new BatteryLevelData.PeriodBatteryLevelData(new ArrayList<>(), new ArrayList<>()));
assertThat(DataProcessor.getBatteryUsageMap( assertThat(DataProcessor.getBatteryUsageMap(
mContext, hourlyBatteryLevelsPerDay, new HashMap<>())).isNull(); mContext, hourlyBatteryLevelsPerDay, new HashMap<>(), /*appUsagePeriodMap=*/ null))
.isNull();
} }
@Test @Test
@@ -751,7 +808,7 @@ public final class DataProcessorTest {
/*backgroundUsageTimeInMs=*/ 35L); /*backgroundUsageTimeInMs=*/ 35L);
entryMap.put(entry.getKey(), entry); entryMap.put(entry.getKey(), entry);
entry = createBatteryHistEntry( entry = createBatteryHistEntry(
"package2", "label2", /*consumePower=*/ 10.0, "package3", "label3", /*consumePower=*/ 10.0,
/*foregroundUsageConsumePower=*/ 4, /*foregroundServiceUsageConsumePower=*/ 2, /*foregroundUsageConsumePower=*/ 4, /*foregroundServiceUsageConsumePower=*/ 2,
/*backgroundUsageConsumePower=*/ 2, /*cachedUsageConsumePower=*/ 2, /*backgroundUsageConsumePower=*/ 2, /*cachedUsageConsumePower=*/ 2,
/*uid=*/ 3L, currentUserId, /*uid=*/ 3L, currentUserId,
@@ -759,7 +816,7 @@ public final class DataProcessorTest {
/*backgroundUsageTimeInMs=*/ 50L); /*backgroundUsageTimeInMs=*/ 50L);
entryMap.put(entry.getKey(), entry); entryMap.put(entry.getKey(), entry);
entry = createBatteryHistEntry( entry = createBatteryHistEntry(
"package3", "label3", /*consumePower=*/ 15.0, "package4", "label3", /*consumePower=*/ 15.0,
/*foregroundUsageConsumePower=*/ 6, /*foregroundServiceUsageConsumePower=*/ 3, /*foregroundUsageConsumePower=*/ 6, /*foregroundServiceUsageConsumePower=*/ 3,
/*backgroundUsageConsumePower=*/ 3, /*cachedUsageConsumePower=*/ 3, /*backgroundUsageConsumePower=*/ 3, /*cachedUsageConsumePower=*/ 3,
/*uid=*/ 4L, currentUserId, /*uid=*/ 4L, currentUserId,
@@ -779,7 +836,7 @@ public final class DataProcessorTest {
/*backgroundUsageTimeInMs=*/ 40L); /*backgroundUsageTimeInMs=*/ 40L);
entryMap.put(entry.getKey(), entry); entryMap.put(entry.getKey(), entry);
entry = createBatteryHistEntry( entry = createBatteryHistEntry(
"package2", "label2", /*consumePower=*/ 20.0, "package3", "label3", /*consumePower=*/ 20.0,
/*foregroundUsageConsumePower=*/ 5, /*foregroundServiceUsageConsumePower=*/ 5, /*foregroundUsageConsumePower=*/ 5, /*foregroundServiceUsageConsumePower=*/ 5,
/*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 5, /*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 5,
/*uid=*/ 3L, currentUserId, /*uid=*/ 3L, currentUserId,
@@ -787,7 +844,7 @@ public final class DataProcessorTest {
/*backgroundUsageTimeInMs=*/ 60L); /*backgroundUsageTimeInMs=*/ 60L);
entryMap.put(entry.getKey(), entry); entryMap.put(entry.getKey(), entry);
entry = createBatteryHistEntry( entry = createBatteryHistEntry(
"package3", "label3", /*consumePower=*/ 40.0, "package4", "label4", /*consumePower=*/ 40.0,
/*foregroundUsageConsumePower=*/ 8, /*foregroundServiceUsageConsumePower=*/ 8, /*foregroundUsageConsumePower=*/ 8, /*foregroundServiceUsageConsumePower=*/ 8,
/*backgroundUsageConsumePower=*/ 8, /*cachedUsageConsumePower=*/ 8, /*backgroundUsageConsumePower=*/ 8, /*cachedUsageConsumePower=*/ 8,
/*uid=*/ 4L, currentUserId, /*uid=*/ 4L, currentUserId,
@@ -809,9 +866,31 @@ public final class DataProcessorTest {
hourlyBatteryLevelsPerDay.add( hourlyBatteryLevelsPerDay.add(
new BatteryLevelData.PeriodBatteryLevelData(timestamps, levels)); new BatteryLevelData.PeriodBatteryLevelData(timestamps, levels));
// Adds app usage data to test screen on time.
final Map<Integer, Map<Integer, Map<Long, Map<String, List<AppUsagePeriod>>>>>
appUsagePeriodMap = new HashMap<>();
appUsagePeriodMap.put(0, new HashMap<>());
appUsagePeriodMap.put(1, new HashMap<>());
// Adds the index [0][0].
Map<Long, Map<String, List<AppUsagePeriod>>> appUsageMap = new HashMap<>();
Map<String, List<AppUsagePeriod>> userPeriodMap = new HashMap<>();
appUsageMap.put(Long.valueOf(currentUserId), userPeriodMap);
userPeriodMap.put("package2", List.of(buildAppUsagePeriod(0, 5)));
userPeriodMap.put("package3", List.of(buildAppUsagePeriod(10, 25)));
appUsagePeriodMap.get(0).put(0, appUsageMap);
// Adds the index [1][0].
appUsageMap = new HashMap<>();
userPeriodMap = new HashMap<>();
appUsageMap.put(Long.valueOf(currentUserId), userPeriodMap);
userPeriodMap.put("package2",
List.of(buildAppUsagePeriod(2, 7), buildAppUsagePeriod(5, 9)));
userPeriodMap.put("package3",
List.of(buildAppUsagePeriod(10, 15), buildAppUsagePeriod(25, 29)));
appUsagePeriodMap.get(1).put(0, appUsageMap);
final Map<Integer, Map<Integer, BatteryDiffData>> resultMap = final Map<Integer, Map<Integer, BatteryDiffData>> resultMap =
DataProcessor.getBatteryUsageMap( DataProcessor.getBatteryUsageMap(
mContext, hourlyBatteryLevelsPerDay, batteryHistoryMap); mContext, hourlyBatteryLevelsPerDay, batteryHistoryMap, appUsagePeriodMap);
BatteryDiffData resultDiffData = BatteryDiffData resultDiffData =
resultMap resultMap
@@ -822,45 +901,52 @@ public final class DataProcessorTest {
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*consumePercentage=*/ 50.0, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*consumePercentage=*/ 50.0,
/*foregroundUsageConsumePower=*/ 14, /*foregroundServiceUsageConsumePower=*/ 9, /*foregroundUsageConsumePower=*/ 14, /*foregroundServiceUsageConsumePower=*/ 9,
/*backgroundUsageConsumePower=*/ 9, /*cachedUsageConsumePower=*/ 8, /*backgroundUsageConsumePower=*/ 9, /*cachedUsageConsumePower=*/ 8,
/*foregroundUsageTimeInMs=*/ 30, /*backgroundUsageTimeInMs=*/ 40); /*foregroundUsageTimeInMs=*/ 30, /*backgroundUsageTimeInMs=*/ 40,
/*screenOnTimeInMs=*/ 12);
assertBatteryDiffEntry( assertBatteryDiffEntry(
resultDiffData.getAppDiffEntryList().get(1), currentUserId, /*uid=*/ 4L, resultDiffData.getAppDiffEntryList().get(1), currentUserId, /*uid=*/ 4L,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*consumePercentage=*/ 50.0, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*consumePercentage=*/ 50.0,
/*foregroundUsageConsumePower=*/ 8, /*foregroundServiceUsageConsumePower=*/ 8, /*foregroundUsageConsumePower=*/ 8, /*foregroundServiceUsageConsumePower=*/ 8,
/*backgroundUsageConsumePower=*/ 8, /*cachedUsageConsumePower=*/ 8, /*backgroundUsageConsumePower=*/ 8, /*cachedUsageConsumePower=*/ 8,
/*foregroundUsageTimeInMs=*/ 5, /*backgroundUsageTimeInMs=*/ 5); /*foregroundUsageTimeInMs=*/ 5, /*backgroundUsageTimeInMs=*/ 5,
/*screenOnTimeInMs=*/ 0);
assertBatteryDiffEntry( assertBatteryDiffEntry(
resultDiffData.getSystemDiffEntryList().get(0), currentUserId, /*uid=*/ 3L, resultDiffData.getSystemDiffEntryList().get(0), currentUserId, /*uid=*/ 3L,
ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY, /*consumePercentage=*/ 100.0, ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY, /*consumePercentage=*/ 100.0,
/*foregroundUsageConsumePower=*/ 5, /*foregroundServiceUsageConsumePower=*/ 5, /*foregroundUsageConsumePower=*/ 5, /*foregroundServiceUsageConsumePower=*/ 5,
/*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 5, /*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 5,
/*foregroundUsageTimeInMs=*/ 50, /*backgroundUsageTimeInMs=*/ 60); /*foregroundUsageTimeInMs=*/ 50, /*backgroundUsageTimeInMs=*/ 60,
/*screenOnTimeInMs=*/ 9);
resultDiffData = resultMap.get(0).get(DataProcessor.SELECTED_INDEX_ALL); resultDiffData = resultMap.get(0).get(DataProcessor.SELECTED_INDEX_ALL);
assertBatteryDiffEntry( assertBatteryDiffEntry(
resultDiffData.getAppDiffEntryList().get(0), currentUserId, /*uid=*/ 2L, resultDiffData.getAppDiffEntryList().get(0), currentUserId, /*uid=*/ 2L,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*consumePercentage=*/ 100.0, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*consumePercentage=*/ 100.0,
/*foregroundUsageConsumePower=*/ 5, /*foregroundServiceUsageConsumePower=*/ 5, /*foregroundUsageConsumePower=*/ 5, /*foregroundServiceUsageConsumePower=*/ 5,
/*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 5, /*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 5,
/*foregroundUsageTimeInMs=*/ 15, /*backgroundUsageTimeInMs=*/ 25); /*foregroundUsageTimeInMs=*/ 15, /*backgroundUsageTimeInMs=*/ 25,
/*screenOnTimeInMs=*/ 5);
resultDiffData = resultMap.get(1).get(DataProcessor.SELECTED_INDEX_ALL); resultDiffData = resultMap.get(1).get(DataProcessor.SELECTED_INDEX_ALL);
assertBatteryDiffEntry( assertBatteryDiffEntry(
resultDiffData.getAppDiffEntryList().get(0), currentUserId, /*uid=*/ 4L, resultDiffData.getAppDiffEntryList().get(0), currentUserId, /*uid=*/ 4L,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*consumePercentage=*/ 66.66666666666666, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*consumePercentage=*/ 66.66666666666666,
/*foregroundUsageConsumePower=*/ 8, /*foregroundServiceUsageConsumePower=*/ 8, /*foregroundUsageConsumePower=*/ 8, /*foregroundServiceUsageConsumePower=*/ 8,
/*backgroundUsageConsumePower=*/ 8, /*cachedUsageConsumePower=*/ 8, /*backgroundUsageConsumePower=*/ 8, /*cachedUsageConsumePower=*/ 8,
/*foregroundUsageTimeInMs=*/ 5, /*backgroundUsageTimeInMs=*/ 5); /*foregroundUsageTimeInMs=*/ 5, /*backgroundUsageTimeInMs=*/ 5,
/*screenOnTimeInMs=*/ 0);
assertBatteryDiffEntry( assertBatteryDiffEntry(
resultDiffData.getAppDiffEntryList().get(1), currentUserId, /*uid=*/ 2L, resultDiffData.getAppDiffEntryList().get(1), currentUserId, /*uid=*/ 2L,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*consumePercentage=*/ 33.33333333333333, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*consumePercentage=*/ 33.33333333333333,
/*foregroundUsageConsumePower=*/ 9, /*foregroundServiceUsageConsumePower=*/ 4, /*foregroundUsageConsumePower=*/ 9, /*foregroundServiceUsageConsumePower=*/ 4,
/*backgroundUsageConsumePower=*/ 4, /*cachedUsageConsumePower=*/ 3, /*backgroundUsageConsumePower=*/ 4, /*cachedUsageConsumePower=*/ 3,
/*foregroundUsageTimeInMs=*/ 15, /*backgroundUsageTimeInMs=*/ 15); /*foregroundUsageTimeInMs=*/ 15, /*backgroundUsageTimeInMs=*/ 15,
/*screenOnTimeInMs=*/ 7);
assertBatteryDiffEntry( assertBatteryDiffEntry(
resultDiffData.getSystemDiffEntryList().get(0), currentUserId, /*uid=*/ 3L, resultDiffData.getSystemDiffEntryList().get(0), currentUserId, /*uid=*/ 3L,
ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY, /*consumePercentage=*/ 100.0, ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY, /*consumePercentage=*/ 100.0,
/*foregroundUsageConsumePower=*/ 5, /*foregroundServiceUsageConsumePower=*/ 5, /*foregroundUsageConsumePower=*/ 5, /*foregroundServiceUsageConsumePower=*/ 5,
/*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 5, /*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 5,
/*foregroundUsageTimeInMs=*/ 50, /*backgroundUsageTimeInMs=*/ 60); /*foregroundUsageTimeInMs=*/ 50, /*backgroundUsageTimeInMs=*/ 60,
/*screenOnTimeInMs=*/ 9);
} }
@Test @Test
@@ -962,7 +1048,8 @@ public final class DataProcessorTest {
final Map<Integer, Map<Integer, BatteryDiffData>> resultMap = final Map<Integer, Map<Integer, BatteryDiffData>> resultMap =
DataProcessor.getBatteryUsageMap( DataProcessor.getBatteryUsageMap(
mContext, hourlyBatteryLevelsPerDay, batteryHistoryMap); mContext, hourlyBatteryLevelsPerDay, batteryHistoryMap,
/*appUsagePeriodMap=*/ null);
final BatteryDiffData resultDiffData = final BatteryDiffData resultDiffData =
resultMap resultMap
@@ -973,7 +1060,8 @@ public final class DataProcessorTest {
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*consumePercentage=*/ 100.0, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*consumePercentage=*/ 100.0,
/*foregroundUsageConsumePower=*/ 5, /*foregroundServiceUsageConsumePower=*/ 5, /*foregroundUsageConsumePower=*/ 5, /*foregroundServiceUsageConsumePower=*/ 5,
/*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 5, /*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 5,
/*foregroundUsageTimeInMs=*/ 10, /*backgroundUsageTimeInMs=*/ 10); /*foregroundUsageTimeInMs=*/ 10, /*backgroundUsageTimeInMs=*/ 10,
/*screenOnTimeInMs=*/ 0);
assertThat(resultDiffData.getSystemDiffEntryList()).isEmpty(); assertThat(resultDiffData.getSystemDiffEntryList()).isEmpty();
assertThat(resultMap.get(0).get(0)).isNotNull(); assertThat(resultMap.get(0).get(0)).isNotNull();
assertThat(resultMap.get(0).get(DataProcessor.SELECTED_INDEX_ALL)).isNotNull(); assertThat(resultMap.get(0).get(DataProcessor.SELECTED_INDEX_ALL)).isNotNull();
@@ -1028,9 +1116,20 @@ public final class DataProcessorTest {
hourlyBatteryLevelsPerDay.add( hourlyBatteryLevelsPerDay.add(
new BatteryLevelData.PeriodBatteryLevelData(timestamps, levels)); new BatteryLevelData.PeriodBatteryLevelData(timestamps, levels));
// Adds app usage data to test screen on time.
final Map<Integer, Map<Integer, Map<Long, Map<String, List<AppUsagePeriod>>>>>
appUsagePeriodMap = new HashMap<>();
appUsagePeriodMap.put(0, new HashMap<>());
// Adds the index [0][0].
final Map<Long, Map<String, List<AppUsagePeriod>>> appUsageMap = new HashMap<>();
final Map<String, List<AppUsagePeriod>> userPeriodMap = new HashMap<>();
appUsageMap.put(Long.valueOf(currentUserId), userPeriodMap);
userPeriodMap.put("package1", List.of(buildAppUsagePeriod(0, 8000000)));
appUsagePeriodMap.get(0).put(0, appUsageMap);
final Map<Integer, Map<Integer, BatteryDiffData>> resultMap = final Map<Integer, Map<Integer, BatteryDiffData>> resultMap =
DataProcessor.getBatteryUsageMap( DataProcessor.getBatteryUsageMap(
mContext, hourlyBatteryLevelsPerDay, batteryHistoryMap); mContext, hourlyBatteryLevelsPerDay, batteryHistoryMap, appUsagePeriodMap);
final BatteryDiffData resultDiffData = final BatteryDiffData resultDiffData =
resultMap resultMap
@@ -1053,6 +1152,7 @@ public final class DataProcessorTest {
.isEqualTo(entry.mBackgroundUsageConsumePower * ratio); .isEqualTo(entry.mBackgroundUsageConsumePower * ratio);
assertThat(resultEntry.mCachedUsageConsumePower) assertThat(resultEntry.mCachedUsageConsumePower)
.isEqualTo(entry.mCachedUsageConsumePower * ratio); .isEqualTo(entry.mCachedUsageConsumePower * ratio);
assertThat(resultEntry.mScreenOnTimeInMs).isEqualTo(7200000L);
assertThat(resultMap.get(0).get(0)).isNotNull(); assertThat(resultMap.get(0).get(0)).isNotNull();
assertThat(resultMap.get(0).get(DataProcessor.SELECTED_INDEX_ALL)).isNotNull(); assertThat(resultMap.get(0).get(DataProcessor.SELECTED_INDEX_ALL)).isNotNull();
} }
@@ -1134,7 +1234,8 @@ public final class DataProcessorTest {
final Map<Integer, Map<Integer, BatteryDiffData>> resultMap = final Map<Integer, Map<Integer, BatteryDiffData>> resultMap =
DataProcessor.getBatteryUsageMap( DataProcessor.getBatteryUsageMap(
mContext, hourlyBatteryLevelsPerDay, batteryHistoryMap); mContext, hourlyBatteryLevelsPerDay, batteryHistoryMap,
/*appUsagePeriodMap=*/ null);
final BatteryDiffData resultDiffData = final BatteryDiffData resultDiffData =
resultMap resultMap
@@ -1145,7 +1246,8 @@ public final class DataProcessorTest {
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*consumePercentage=*/ 100.0, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*consumePercentage=*/ 100.0,
/*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0, /*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0,
/*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 5, /*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 5,
/*foregroundUsageTimeInMs=*/ 10, /*backgroundUsageTimeInMs=*/ 20); /*foregroundUsageTimeInMs=*/ 10, /*backgroundUsageTimeInMs=*/ 20,
/*screenOnTimeInMs=*/ 0);
} }
@Test @Test
@@ -1225,7 +1327,8 @@ public final class DataProcessorTest {
final Map<Integer, Map<Integer, BatteryDiffData>> resultMap = final Map<Integer, Map<Integer, BatteryDiffData>> resultMap =
DataProcessor.getBatteryUsageMap( DataProcessor.getBatteryUsageMap(
mContext, hourlyBatteryLevelsPerDay, batteryHistoryMap); mContext, hourlyBatteryLevelsPerDay, batteryHistoryMap,
/*appUsagePeriodMap=*/ null);
final BatteryDiffData resultDiffData = final BatteryDiffData resultDiffData =
resultMap resultMap
@@ -1300,19 +1403,22 @@ public final class DataProcessorTest {
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*consumePercentage=*/ 100.0, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*consumePercentage=*/ 100.0,
/*foregroundUsageConsumePower=*/ 0.5, /*foregroundServiceUsageConsumePower=*/ 0, /*foregroundUsageConsumePower=*/ 0.5, /*foregroundServiceUsageConsumePower=*/ 0,
/*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0, /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
/*foregroundUsageTimeInMs=*/ 20, /*backgroundUsageTimeInMs=*/ 20); /*foregroundUsageTimeInMs=*/ 20, /*backgroundUsageTimeInMs=*/ 20,
/*screenOnTimeInMs=*/ 0);
assertBatteryDiffEntry( assertBatteryDiffEntry(
batteryDiffData.getAppDiffEntryList().get(1), 0, /*uid=*/ 1L, batteryDiffData.getAppDiffEntryList().get(1), 0, /*uid=*/ 1L,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*consumePercentage=*/ 0.0, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*consumePercentage=*/ 0.0,
/*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0, /*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0,
/*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0, /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
/*foregroundUsageTimeInMs=*/ 30, /*backgroundUsageTimeInMs=*/ 40); /*foregroundUsageTimeInMs=*/ 30, /*backgroundUsageTimeInMs=*/ 40,
/*screenOnTimeInMs=*/ 0);
assertBatteryDiffEntry( assertBatteryDiffEntry(
batteryDiffData.getSystemDiffEntryList().get(0), 0, /*uid=*/ 4L, batteryDiffData.getSystemDiffEntryList().get(0), 0, /*uid=*/ 4L,
ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY, /*consumePercentage=*/ 100.0, ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY, /*consumePercentage=*/ 100.0,
/*foregroundUsageConsumePower=*/ 0.9, /*foregroundServiceUsageConsumePower=*/ 0.2, /*foregroundUsageConsumePower=*/ 0.9, /*foregroundServiceUsageConsumePower=*/ 0.2,
/*backgroundUsageConsumePower=*/ 0.3, /*cachedUsageConsumePower=*/ 0.1, /*backgroundUsageConsumePower=*/ 0.3, /*cachedUsageConsumePower=*/ 0.1,
/*foregroundUsageTimeInMs=*/ 10, /*backgroundUsageTimeInMs=*/ 10); /*foregroundUsageTimeInMs=*/ 10, /*backgroundUsageTimeInMs=*/ 10,
/*screenOnTimeInMs=*/ 0);
} }
@Test @Test
@@ -1459,6 +1565,44 @@ public final class DataProcessorTest {
assertAppUsagePeriod(appUsagePeriodList.get(0), 0, 100000); assertAppUsagePeriod(appUsagePeriodList.get(0), 0, 100000);
} }
@Test
public void getScreenOnTime_returnExpectedResult() {
final long userId = 1;
final String packageName = "com.android.settings";
final Map<Long, Map<String, List<AppUsagePeriod>>> appUsageMap = new HashMap<>();
final List<AppUsagePeriod> appUsagePeriodList = new ArrayList<>();
appUsageMap.put(userId, new HashMap<>());
appUsageMap.get(userId).put(packageName, appUsagePeriodList);
// Fake overlapped case.
appUsagePeriodList.add(buildAppUsagePeriod(0, 5));
appUsagePeriodList.add(buildAppUsagePeriod(2, 3));
appUsagePeriodList.add(buildAppUsagePeriod(2, 4));
appUsagePeriodList.add(buildAppUsagePeriod(5, 7));
// Fake same case.
appUsagePeriodList.add(buildAppUsagePeriod(10, 12));
appUsagePeriodList.add(buildAppUsagePeriod(10, 12));
appUsagePeriodList.add(buildAppUsagePeriod(10, 12));
// Fake normal case.
appUsagePeriodList.add(buildAppUsagePeriod(15, 20));
appUsagePeriodList.add(buildAppUsagePeriod(35, 40));
appUsagePeriodList.add(buildAppUsagePeriod(25, 30));
assertThat(DataProcessor.getScreenOnTime(appUsageMap, userId, packageName)).isEqualTo(24);
}
@Test
public void getScreenOnTime_nullInput_returnZero() {
final long userId = 1;
final String packageName = "com.android.settings";
final Map<Long, Map<String, List<AppUsagePeriod>>> appUsageMap = new HashMap<>();
appUsageMap.put(userId, new HashMap<>());
assertThat(DataProcessor.getScreenOnTime(null, userId, packageName)).isEqualTo(0);
assertThat(DataProcessor.getScreenOnTime(new HashMap<>(), userId, packageName))
.isEqualTo(0);
assertThat(DataProcessor.getScreenOnTime(appUsageMap, userId, packageName)).isEqualTo(0);
}
private static Map<Long, Map<String, BatteryHistEntry>> createHistoryMap( private static Map<Long, Map<String, BatteryHistEntry>> createHistoryMap(
final long[] timestamps, final int[] levels) { final long[] timestamps, final int[] levels) {
final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap = new HashMap<>(); final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap = new HashMap<>();
@@ -1558,6 +1702,13 @@ public final class DataProcessorTest {
.build(); .build();
} }
private AppUsagePeriod buildAppUsagePeriod(final long start, final long end) {
return AppUsagePeriod.newBuilder()
.setStartTime(start)
.setEndTime(end)
.build();
}
private void assertAppUsageEvent( private void assertAppUsageEvent(
final AppUsageEvent event, final AppUsageEventType eventType, final long timestamp) { final AppUsageEvent event, final AppUsageEventType eventType, final long timestamp) {
assertThat(event.getType()).isEqualTo(eventType); assertThat(event.getType()).isEqualTo(eventType);
@@ -1635,7 +1786,8 @@ public final class DataProcessorTest {
final double foregroundUsageConsumePower, final double foregroundUsageConsumePower,
final double foregroundServiceUsageConsumePower, final double foregroundServiceUsageConsumePower,
final double backgroundUsageConsumePower, final double cachedUsageConsumePower, final double backgroundUsageConsumePower, final double cachedUsageConsumePower,
final long foregroundUsageTimeInMs, final long backgroundUsageTimeInMs) { final long foregroundUsageTimeInMs, final long backgroundUsageTimeInMs,
final long screenOnTimeInMs) {
assertThat(entry.mBatteryHistEntry.mUserId).isEqualTo(userId); assertThat(entry.mBatteryHistEntry.mUserId).isEqualTo(userId);
assertThat(entry.mBatteryHistEntry.mUid).isEqualTo(uid); assertThat(entry.mBatteryHistEntry.mUid).isEqualTo(uid);
assertThat(entry.mBatteryHistEntry.mConsumerType).isEqualTo(consumerType); assertThat(entry.mBatteryHistEntry.mConsumerType).isEqualTo(consumerType);
@@ -1647,5 +1799,6 @@ public final class DataProcessorTest {
assertThat(entry.mCachedUsageConsumePower).isEqualTo(cachedUsageConsumePower); assertThat(entry.mCachedUsageConsumePower).isEqualTo(cachedUsageConsumePower);
assertThat(entry.mForegroundUsageTimeInMs).isEqualTo(foregroundUsageTimeInMs); assertThat(entry.mForegroundUsageTimeInMs).isEqualTo(foregroundUsageTimeInMs);
assertThat(entry.mBackgroundUsageTimeInMs).isEqualTo(backgroundUsageTimeInMs); assertThat(entry.mBackgroundUsageTimeInMs).isEqualTo(backgroundUsageTimeInMs);
assertThat(entry.mScreenOnTimeInMs).isEqualTo(screenOnTimeInMs);
} }
} }