Merge "Query usage event for a longer time period and then trim the usage events outside the expected period to make sure the app usage calculation near the boundaries are correct."
This commit is contained in:
committed by
Android (Google) Code Review
commit
30317dd2b9
@@ -376,7 +376,7 @@ public class DataProcessManager {
|
|||||||
// Generates the indexed AppUsagePeriod list data for each corresponding time slot for
|
// Generates the indexed AppUsagePeriod list data for each corresponding time slot for
|
||||||
// further use.
|
// further use.
|
||||||
mAppUsagePeriodMap = DataProcessor.generateAppUsagePeriodMap(
|
mAppUsagePeriodMap = DataProcessor.generateAppUsagePeriodMap(
|
||||||
mHourlyBatteryLevelsPerDay, mAppUsageEventList, mStartTimestampOfLevelData);
|
mHourlyBatteryLevelsPerDay, mAppUsageEventList);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void tryToGenerateFinalDataAndApplyCallback() {
|
private void tryToGenerateFinalDataAndApplyCallback() {
|
||||||
|
@@ -72,7 +72,6 @@ import java.util.stream.Stream;
|
|||||||
* usage UI.
|
* usage UI.
|
||||||
*/
|
*/
|
||||||
public final class DataProcessor {
|
public final class DataProcessor {
|
||||||
private static final boolean DEBUG = false;
|
|
||||||
private static final String TAG = "DataProcessor";
|
private static final String TAG = "DataProcessor";
|
||||||
private static final int POWER_COMPONENT_SYSTEM_SERVICES = 7;
|
private static final int POWER_COMPONENT_SYSTEM_SERVICES = 7;
|
||||||
private static final int POWER_COMPONENT_WAKELOCK = 12;
|
private static final int POWER_COMPONENT_WAKELOCK = 12;
|
||||||
@@ -98,6 +97,9 @@ public final class DataProcessor {
|
|||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
static long sFakeCurrentTimeMillis = 0;
|
static long sFakeCurrentTimeMillis = 0;
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
static boolean sDebug = false;
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
static IUsageStatsManager sUsageStatsManager =
|
static IUsageStatsManager sUsageStatsManager =
|
||||||
IUsageStatsManager.Stub.asInterface(
|
IUsageStatsManager.Stub.asInterface(
|
||||||
@@ -250,8 +252,7 @@ public final class DataProcessor {
|
|||||||
public static Map<Integer, Map<Integer, Map<Long, Map<String, List<AppUsagePeriod>>>>>
|
public static Map<Integer, Map<Integer, Map<Long, Map<String, List<AppUsagePeriod>>>>>
|
||||||
generateAppUsagePeriodMap(
|
generateAppUsagePeriodMap(
|
||||||
final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay,
|
final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay,
|
||||||
final List<AppUsageEvent> appUsageEventList,
|
final List<AppUsageEvent> appUsageEventList) {
|
||||||
final long startTimestampOfLevelData) {
|
|
||||||
if (appUsageEventList.isEmpty()) {
|
if (appUsageEventList.isEmpty()) {
|
||||||
Log.w(TAG, "appUsageEventList is empty");
|
Log.w(TAG, "appUsageEventList is empty");
|
||||||
return null;
|
return null;
|
||||||
@@ -261,12 +262,8 @@ public final class DataProcessor {
|
|||||||
Collections.sort(appUsageEventList, TIMESTAMP_COMPARATOR);
|
Collections.sort(appUsageEventList, TIMESTAMP_COMPARATOR);
|
||||||
final Map<Integer, Map<Integer, Map<Long, Map<String, List<AppUsagePeriod>>>>> resultMap =
|
final Map<Integer, Map<Integer, Map<Long, Map<String, List<AppUsagePeriod>>>>> resultMap =
|
||||||
new HashMap<>();
|
new HashMap<>();
|
||||||
// Starts from the first index within expected time range. The events before the time range
|
|
||||||
// will be bypassed directly.
|
|
||||||
int currentAppUsageEventIndex =
|
|
||||||
getFirstUsageEventIndex(appUsageEventList, startTimestampOfLevelData);
|
|
||||||
final int appUsageEventSize = appUsageEventList.size();
|
|
||||||
|
|
||||||
|
final long dailySize = hourlyBatteryLevelsPerDay.size();
|
||||||
for (int dailyIndex = 0; dailyIndex < hourlyBatteryLevelsPerDay.size(); dailyIndex++) {
|
for (int dailyIndex = 0; dailyIndex < hourlyBatteryLevelsPerDay.size(); dailyIndex++) {
|
||||||
final Map<Integer, Map<Long, Map<String, List<AppUsagePeriod>>>> dailyMap =
|
final Map<Integer, Map<Long, Map<String, List<AppUsagePeriod>>>> dailyMap =
|
||||||
new HashMap<>();
|
new HashMap<>();
|
||||||
@@ -275,32 +272,21 @@ public final class DataProcessor {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
final List<Long> timestamps = hourlyBatteryLevelsPerDay.get(dailyIndex).getTimestamps();
|
final List<Long> timestamps = hourlyBatteryLevelsPerDay.get(dailyIndex).getTimestamps();
|
||||||
|
final long hourlySize = timestamps.size() - 1;
|
||||||
for (int hourlyIndex = 0; hourlyIndex < timestamps.size() - 1; hourlyIndex++) {
|
for (int hourlyIndex = 0; hourlyIndex < timestamps.size() - 1; hourlyIndex++) {
|
||||||
// The start and end timestamps of this slot should be the adjacent timestamps.
|
// The start and end timestamps of this slot should be the adjacent timestamps.
|
||||||
final long startTimestamp = timestamps.get(hourlyIndex);
|
final long startTimestamp = timestamps.get(hourlyIndex);
|
||||||
final long endTimestamp = timestamps.get(hourlyIndex + 1);
|
// The final slot is to show the data from last even hour until now but the
|
||||||
|
// timestamp in hourlyBatteryLevelsPerDay is not the real value. So use current
|
||||||
|
// timestamp instead of reading the timestamp from hourlyBatteryLevelsPerDay here.
|
||||||
|
final long endTimestamp =
|
||||||
|
dailyIndex == dailySize - 1 && hourlyIndex == hourlySize - 1 && !sDebug
|
||||||
|
? System.currentTimeMillis() : timestamps.get(hourlyIndex + 1);
|
||||||
|
|
||||||
// Gets the app usage event list for this hourly slot first.
|
// Gets the app usage event list for this hourly slot first.
|
||||||
final List<AppUsageEvent> hourlyAppUsageEventList = new ArrayList<>();
|
final List<AppUsageEvent> hourlyAppUsageEventList =
|
||||||
while (currentAppUsageEventIndex < appUsageEventSize) {
|
getAppUsageEventListWithinTimeRangeWithBuffer(
|
||||||
// If current event is null, go for next directly.
|
appUsageEventList, startTimestamp, endTimestamp);
|
||||||
if (appUsageEventList.get(currentAppUsageEventIndex) == null) {
|
|
||||||
currentAppUsageEventIndex++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
final long timestamp =
|
|
||||||
appUsageEventList.get(currentAppUsageEventIndex).getTimestamp();
|
|
||||||
// If the timestamp is already later than the end time, stop the loop.
|
|
||||||
if (timestamp >= endTimestamp) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// If timestamp is within the time range, add it into the list.
|
|
||||||
if (timestamp >= startTimestamp) {
|
|
||||||
hourlyAppUsageEventList.add(
|
|
||||||
appUsageEventList.get(currentAppUsageEventIndex));
|
|
||||||
}
|
|
||||||
currentAppUsageEventIndex++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The value could be null when there is no data in the hourly slot.
|
// The value could be null when there is no data in the hourly slot.
|
||||||
dailyMap.put(
|
dailyMap.put(
|
||||||
@@ -785,13 +771,11 @@ public final class DataProcessor {
|
|||||||
final List<AppUsageEvent> usageEvents, final long startTime, final long endTime) {
|
final List<AppUsageEvent> usageEvents, final long startTime, final long endTime) {
|
||||||
final List<AppUsagePeriod> usagePeriodList = new ArrayList<>();
|
final List<AppUsagePeriod> usagePeriodList = new ArrayList<>();
|
||||||
AppUsagePeriod.Builder pendingUsagePeriod = AppUsagePeriod.newBuilder();
|
AppUsagePeriod.Builder pendingUsagePeriod = AppUsagePeriod.newBuilder();
|
||||||
boolean hasMetStartEvent = false;
|
|
||||||
|
|
||||||
for (final AppUsageEvent event : usageEvents) {
|
for (final AppUsageEvent event : usageEvents) {
|
||||||
final long eventTime = event.getTimestamp();
|
final long eventTime = event.getTimestamp();
|
||||||
|
|
||||||
if (event.getType() == AppUsageEventType.ACTIVITY_RESUMED) {
|
if (event.getType() == AppUsageEventType.ACTIVITY_RESUMED) {
|
||||||
hasMetStartEvent = true;
|
|
||||||
// If there is an existing start time, simply ignore this start event.
|
// If there is an existing start time, simply ignore this start event.
|
||||||
// If there was no start time, then start a new period.
|
// If there was no start time, then start a new period.
|
||||||
if (!pendingUsagePeriod.hasStartTime()) {
|
if (!pendingUsagePeriod.hasStartTime()) {
|
||||||
@@ -800,37 +784,31 @@ public final class DataProcessor {
|
|||||||
} else if (event.getType() == AppUsageEventType.ACTIVITY_STOPPED) {
|
} else if (event.getType() == AppUsageEventType.ACTIVITY_STOPPED) {
|
||||||
pendingUsagePeriod.setEndTime(eventTime);
|
pendingUsagePeriod.setEndTime(eventTime);
|
||||||
if (!pendingUsagePeriod.hasStartTime()) {
|
if (!pendingUsagePeriod.hasStartTime()) {
|
||||||
// If we haven't met start event in this list, the start event might happen
|
pendingUsagePeriod.setStartTime(
|
||||||
// in the previous time slot. use the startTime for this period.
|
getStartTimeForIncompleteUsagePeriod(pendingUsagePeriod));
|
||||||
// Otherwise, add one for the default duration.
|
|
||||||
if (!hasMetStartEvent) {
|
|
||||||
hasMetStartEvent = true;
|
|
||||||
pendingUsagePeriod.setStartTime(startTime);
|
|
||||||
} else {
|
|
||||||
pendingUsagePeriod.setStartTime(
|
|
||||||
getStartTimeForIncompleteUsagePeriod(pendingUsagePeriod));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// If we already have start time, add it directly.
|
// If we already have start time, add it directly.
|
||||||
addToPeriodList(usagePeriodList, pendingUsagePeriod.build());
|
validateAndAddToPeriodList(
|
||||||
|
usagePeriodList, pendingUsagePeriod.build(), startTime, endTime);
|
||||||
pendingUsagePeriod.clear();
|
pendingUsagePeriod.clear();
|
||||||
} else if (event.getType() == AppUsageEventType.DEVICE_SHUTDOWN) {
|
} else if (event.getType() == AppUsageEventType.DEVICE_SHUTDOWN) {
|
||||||
hasMetStartEvent = true;
|
|
||||||
// The end event might be lost when device is shutdown. Use the estimated end
|
// The end event might be lost when device is shutdown. Use the estimated end
|
||||||
// time for the period.
|
// time for the period.
|
||||||
if (pendingUsagePeriod.hasStartTime()) {
|
if (pendingUsagePeriod.hasStartTime()) {
|
||||||
pendingUsagePeriod.setEndTime(
|
pendingUsagePeriod.setEndTime(
|
||||||
getEndTimeForIncompleteUsagePeriod(pendingUsagePeriod, eventTime));
|
getEndTimeForIncompleteUsagePeriod(pendingUsagePeriod, eventTime));
|
||||||
addToPeriodList(usagePeriodList, pendingUsagePeriod.build());
|
validateAndAddToPeriodList(
|
||||||
|
usagePeriodList, pendingUsagePeriod.build(), startTime, endTime);
|
||||||
pendingUsagePeriod.clear();
|
pendingUsagePeriod.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If there exists unclosed period, the stop event might happen in the next time
|
// If there exists unclosed period, the stop event might happen in the next time
|
||||||
// slot. Use the endTime for the period.
|
// slot. Use the endTime for the period.
|
||||||
if (pendingUsagePeriod.hasStartTime()) {
|
if (pendingUsagePeriod.hasStartTime() && pendingUsagePeriod.getStartTime() < endTime) {
|
||||||
pendingUsagePeriod.setEndTime(endTime);
|
pendingUsagePeriod.setEndTime(endTime);
|
||||||
addToPeriodList(usagePeriodList, pendingUsagePeriod.build());
|
validateAndAddToPeriodList(
|
||||||
|
usagePeriodList, pendingUsagePeriod.build(), startTime, endTime);
|
||||||
pendingUsagePeriod.clear();
|
pendingUsagePeriod.clear();
|
||||||
}
|
}
|
||||||
return usagePeriodList;
|
return usagePeriodList;
|
||||||
@@ -881,12 +859,56 @@ public final class DataProcessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void addToPeriodList(
|
/**
|
||||||
final List<AppUsagePeriod> appUsagePeriodList, final AppUsagePeriod appUsagePeriod) {
|
* Generates the list of {@link AppUsageEvent} within the specific time range.
|
||||||
// Only when the period is valid, add it into the list.
|
* The buffer is added to make sure the app usage calculation near the boundaries is correct.
|
||||||
if (appUsagePeriod.getStartTime() < appUsagePeriod.getEndTime()) {
|
*
|
||||||
appUsagePeriodList.add(appUsagePeriod);
|
* Note: The appUsageEventList should have been sorted when calling this function.
|
||||||
|
*/
|
||||||
|
private static List<AppUsageEvent> getAppUsageEventListWithinTimeRangeWithBuffer(
|
||||||
|
final List<AppUsageEvent> appUsageEventList, final long startTime, final long endTime) {
|
||||||
|
final long start = startTime - DatabaseUtils.USAGE_QUERY_BUFFER_HOURS;
|
||||||
|
final long end = endTime + DatabaseUtils.USAGE_QUERY_BUFFER_HOURS;
|
||||||
|
final List<AppUsageEvent> resultList = new ArrayList<>();
|
||||||
|
for (final AppUsageEvent event : appUsageEventList) {
|
||||||
|
final long eventTime = event.getTimestamp();
|
||||||
|
// Because the appUsageEventList has been sorted, if any event is already after the end
|
||||||
|
// time, all the following events should be able to drop directly.
|
||||||
|
if (eventTime > end) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// If the event timestamp is in [start, end], add it into the result list.
|
||||||
|
if (eventTime >= start) {
|
||||||
|
resultList.add(event);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return resultList;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void validateAndAddToPeriodList(
|
||||||
|
final List<AppUsagePeriod> appUsagePeriodList,
|
||||||
|
final AppUsagePeriod appUsagePeriod,
|
||||||
|
final long startTime,
|
||||||
|
final long endTime) {
|
||||||
|
final long periodStartTime =
|
||||||
|
trimPeriodTime(appUsagePeriod.getStartTime(), startTime, endTime);
|
||||||
|
final long periodEndTime = trimPeriodTime(appUsagePeriod.getEndTime(), startTime, endTime);
|
||||||
|
// Only when the period is valid, add it into the list.
|
||||||
|
if (periodStartTime < periodEndTime) {
|
||||||
|
final AppUsagePeriod period =
|
||||||
|
AppUsagePeriod.newBuilder()
|
||||||
|
.setStartTime(periodStartTime)
|
||||||
|
.setEndTime(periodEndTime)
|
||||||
|
.build();
|
||||||
|
appUsagePeriodList.add(period);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long trimPeriodTime(
|
||||||
|
final long originalTime, final long startTime, final long endTime) {
|
||||||
|
long finalTime = Math.max(originalTime, startTime);
|
||||||
|
finalTime = Math.min(finalTime, endTime);
|
||||||
|
return finalTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void addToUsagePeriodMap(
|
private static void addToUsagePeriodMap(
|
||||||
@@ -918,19 +940,6 @@ public final class DataProcessor {
|
|||||||
eventTime);
|
eventTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int getFirstUsageEventIndex(
|
|
||||||
final List<AppUsageEvent> appUsageEventList,
|
|
||||||
final long startTimestampOfLevelData) {
|
|
||||||
int currentIndex = 0;
|
|
||||||
while (currentIndex < appUsageEventList.size()
|
|
||||||
&& (appUsageEventList.get(currentIndex) == null
|
|
||||||
|| appUsageEventList.get(currentIndex).getTimestamp()
|
|
||||||
< startTimestampOfLevelData)) {
|
|
||||||
currentIndex++;
|
|
||||||
}
|
|
||||||
return currentIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void insertHourlyDeviceScreenOnTime(
|
private static void insertHourlyDeviceScreenOnTime(
|
||||||
final Map<Integer, Map<Integer, Map<Long, Map<String, List<AppUsagePeriod>>>>>
|
final Map<Integer, Map<Integer, Map<Long, Map<String, List<AppUsagePeriod>>>>>
|
||||||
appUsagePeriodMap,
|
appUsagePeriodMap,
|
||||||
@@ -1520,7 +1529,7 @@ public final class DataProcessor {
|
|||||||
foregroundUsageTimeInMs + backgroundUsageTimeInMs;
|
foregroundUsageTimeInMs + backgroundUsageTimeInMs;
|
||||||
if (totalUsageTimeInMs > TOTAL_HOURLY_TIME_THRESHOLD) {
|
if (totalUsageTimeInMs > TOTAL_HOURLY_TIME_THRESHOLD) {
|
||||||
final float ratio = TOTAL_HOURLY_TIME_THRESHOLD / totalUsageTimeInMs;
|
final float ratio = TOTAL_HOURLY_TIME_THRESHOLD / totalUsageTimeInMs;
|
||||||
if (DEBUG) {
|
if (sDebug) {
|
||||||
Log.w(TAG, String.format("abnormal usage time %d|%d for:\n%s",
|
Log.w(TAG, String.format("abnormal usage time %d|%d for:\n%s",
|
||||||
Duration.ofMillis(foregroundUsageTimeInMs).getSeconds(),
|
Duration.ofMillis(foregroundUsageTimeInMs).getSeconds(),
|
||||||
Duration.ofMillis(backgroundUsageTimeInMs).getSeconds(),
|
Duration.ofMillis(backgroundUsageTimeInMs).getSeconds(),
|
||||||
@@ -1876,7 +1885,7 @@ public final class DataProcessor {
|
|||||||
|
|
||||||
private static void log(Context context, final String content, final long timestamp,
|
private static void log(Context context, final String content, final long timestamp,
|
||||||
final BatteryHistEntry entry) {
|
final BatteryHistEntry entry) {
|
||||||
if (DEBUG) {
|
if (sDebug) {
|
||||||
Log.d(TAG, String.format(entry != null ? "%s %s:\n%s" : "%s %s:%s",
|
Log.d(TAG, String.format(entry != null ? "%s %s:\n%s" : "%s %s:%s",
|
||||||
utcToLocalTime(context, timestamp), content, entry));
|
utcToLocalTime(context, timestamp), content, entry));
|
||||||
}
|
}
|
||||||
|
@@ -74,6 +74,11 @@ public final class DatabaseUtils {
|
|||||||
public static final String QUERY_KEY_USERID = "userid";
|
public static final String QUERY_KEY_USERID = "userid";
|
||||||
|
|
||||||
public static final long INVALID_USER_ID = Integer.MIN_VALUE;
|
public static final long INVALID_USER_ID = Integer.MIN_VALUE;
|
||||||
|
/**
|
||||||
|
* The buffer hours to query app usage events that may have begun or ended out of the final
|
||||||
|
* desired time frame.
|
||||||
|
*/
|
||||||
|
public static final long USAGE_QUERY_BUFFER_HOURS = Duration.ofHours(3).toMillis();
|
||||||
|
|
||||||
/** A content URI to access battery usage states data. */
|
/** A content URI to access battery usage states data. */
|
||||||
public static final Uri BATTERY_CONTENT_URI =
|
public static final Uri BATTERY_CONTENT_URI =
|
||||||
@@ -138,7 +143,10 @@ public final class DatabaseUtils {
|
|||||||
final long startTimestampOfLevelData) {
|
final long startTimestampOfLevelData) {
|
||||||
final long startTime = System.currentTimeMillis();
|
final long startTime = System.currentTimeMillis();
|
||||||
final long sixDaysAgoTimestamp = getTimestampSixDaysAgo(calendar);
|
final long sixDaysAgoTimestamp = getTimestampSixDaysAgo(calendar);
|
||||||
final long queryTimestamp = Math.max(startTimestampOfLevelData, sixDaysAgoTimestamp);
|
// Query a longer time period and then trim to the original time period in order to make
|
||||||
|
// sure the app usage calculation near the boundaries is correct.
|
||||||
|
final long queryTimestamp =
|
||||||
|
Math.max(startTimestampOfLevelData, sixDaysAgoTimestamp) - USAGE_QUERY_BUFFER_HOURS;
|
||||||
Log.d(TAG, "sixDayAgoTimestamp: " + sixDaysAgoTimestamp);
|
Log.d(TAG, "sixDayAgoTimestamp: " + sixDaysAgoTimestamp);
|
||||||
final String queryUserIdString = userIds.stream()
|
final String queryUserIdString = userIds.stream()
|
||||||
.map(userId -> String.valueOf(userId))
|
.map(userId -> String.valueOf(userId))
|
||||||
|
@@ -178,22 +178,22 @@ public final class DataProcessorTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void generateAppUsagePeriodMap_returnExpectedResult() {
|
public void generateAppUsagePeriodMap_returnExpectedResult() {
|
||||||
|
DataProcessor.sDebug = true;
|
||||||
final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay =
|
final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay =
|
||||||
new ArrayList<>();
|
new ArrayList<>();
|
||||||
final String packageName = "com.android.settings";
|
final String packageName = "com.android.settings";
|
||||||
// Adds the day 1 data.
|
// Adds the day 1 data.
|
||||||
final List<Long> timestamps1 = List.of(10000L, 20000L, 30000L);
|
final List<Long> timestamps1 = List.of(14400000L, 18000000L, 21600000L);
|
||||||
final List<Integer> levels1 = List.of(100, 100, 100);
|
final List<Integer> levels1 = List.of(100, 100, 100);
|
||||||
hourlyBatteryLevelsPerDay.add(
|
hourlyBatteryLevelsPerDay.add(
|
||||||
new BatteryLevelData.PeriodBatteryLevelData(timestamps1, levels1));
|
new BatteryLevelData.PeriodBatteryLevelData(timestamps1, levels1));
|
||||||
// Adds the day 2 data.
|
// Adds the day 2 data.
|
||||||
hourlyBatteryLevelsPerDay.add(null);
|
hourlyBatteryLevelsPerDay.add(null);
|
||||||
// Adds the day 3 data.
|
// Adds the day 3 data.
|
||||||
final List<Long> timestamps2 = List.of(40000L, 50000L);
|
final List<Long> timestamps2 = List.of(45200000L, 48800000L);
|
||||||
final List<Integer> levels2 = List.of(100, 100);
|
final List<Integer> levels2 = List.of(100, 100);
|
||||||
hourlyBatteryLevelsPerDay.add(
|
hourlyBatteryLevelsPerDay.add(
|
||||||
new BatteryLevelData.PeriodBatteryLevelData(timestamps2, levels2));
|
new BatteryLevelData.PeriodBatteryLevelData(timestamps2, levels2));
|
||||||
final long startTimestampOfLevelData = 10000L;
|
|
||||||
final List<AppUsageEvent> appUsageEventList = new ArrayList<>();
|
final List<AppUsageEvent> appUsageEventList = new ArrayList<>();
|
||||||
// Adds some events before the start timestamp.
|
// Adds some events before the start timestamp.
|
||||||
appUsageEventList.add(buildAppUsageEvent(
|
appUsageEventList.add(buildAppUsageEvent(
|
||||||
@@ -204,39 +204,48 @@ public final class DataProcessorTest {
|
|||||||
/*instanceId=*/ 2, packageName));
|
/*instanceId=*/ 2, packageName));
|
||||||
// Adds the valid app usage events.
|
// Adds the valid app usage events.
|
||||||
appUsageEventList.add(buildAppUsageEvent(
|
appUsageEventList.add(buildAppUsageEvent(
|
||||||
AppUsageEventType.ACTIVITY_RESUMED, /*timestamp=*/ 10000L, /*userId=*/ 1,
|
AppUsageEventType.ACTIVITY_RESUMED, /*timestamp=*/ 4200000L, /*userId=*/ 1,
|
||||||
/*instanceId=*/ 2, packageName));
|
/*instanceId=*/ 2, packageName));
|
||||||
appUsageEventList.add(buildAppUsageEvent(
|
appUsageEventList.add(buildAppUsageEvent(
|
||||||
AppUsageEventType.ACTIVITY_STOPPED, /*timestamp=*/ 15000L, /*userId=*/ 1,
|
AppUsageEventType.ACTIVITY_STOPPED, /*timestamp=*/ 4500000L, /*userId=*/ 1,
|
||||||
/*instanceId=*/ 2, packageName));
|
/*instanceId=*/ 2, packageName));
|
||||||
appUsageEventList.add(buildAppUsageEvent(
|
appUsageEventList.add(buildAppUsageEvent(
|
||||||
AppUsageEventType.ACTIVITY_RESUMED, /*timestamp=*/ 12000L, /*userId=*/ 2,
|
AppUsageEventType.ACTIVITY_RESUMED, /*timestamp=*/ 12600000L, /*userId=*/ 2,
|
||||||
/*instanceId=*/ 3, packageName));
|
/*instanceId=*/ 3, packageName));
|
||||||
appUsageEventList.add(buildAppUsageEvent(
|
appUsageEventList.add(buildAppUsageEvent(
|
||||||
AppUsageEventType.ACTIVITY_STOPPED, /*timestamp=*/ 18000L, /*userId=*/ 2,
|
AppUsageEventType.ACTIVITY_STOPPED, /*timestamp=*/ 15600000L, /*userId=*/ 2,
|
||||||
/*instanceId=*/ 3, packageName));
|
/*instanceId=*/ 3, packageName));
|
||||||
appUsageEventList.add(buildAppUsageEvent(
|
appUsageEventList.add(buildAppUsageEvent(
|
||||||
AppUsageEventType.ACTIVITY_RESUMED, /*timestamp=*/ 35000L, /*userId=*/ 1,
|
AppUsageEventType.ACTIVITY_RESUMED, /*timestamp=*/ 16200000L, /*userId=*/ 2,
|
||||||
|
/*instanceId=*/ 3, packageName));
|
||||||
|
appUsageEventList.add(buildAppUsageEvent(
|
||||||
|
AppUsageEventType.ACTIVITY_STOPPED, /*timestamp=*/ 18000000L, /*userId=*/ 2,
|
||||||
|
/*instanceId=*/ 3, packageName));
|
||||||
|
appUsageEventList.add(buildAppUsageEvent(
|
||||||
|
AppUsageEventType.ACTIVITY_RESUMED, /*timestamp=*/ 17200000L, /*userId=*/ 1,
|
||||||
/*instanceId=*/ 2, packageName));
|
/*instanceId=*/ 2, packageName));
|
||||||
appUsageEventList.add(buildAppUsageEvent(
|
appUsageEventList.add(buildAppUsageEvent(
|
||||||
AppUsageEventType.ACTIVITY_STOPPED, /*timestamp=*/ 45000L, /*userId=*/ 1,
|
AppUsageEventType.ACTIVITY_STOPPED, /*timestamp=*/ 17800000L, /*userId=*/ 1,
|
||||||
/*instanceId=*/ 2, packageName));
|
/*instanceId=*/ 2, packageName));
|
||||||
appUsageEventList.add(buildAppUsageEvent(
|
appUsageEventList.add(buildAppUsageEvent(
|
||||||
AppUsageEventType.ACTIVITY_RESUMED, /*timestamp=*/ 42000L, /*userId=*/ 1,
|
AppUsageEventType.ACTIVITY_STOPPED, /*timestamp=*/ 46000000L, /*userId=*/ 1,
|
||||||
|
/*instanceId=*/ 2, packageName));
|
||||||
|
appUsageEventList.add(buildAppUsageEvent(
|
||||||
|
AppUsageEventType.ACTIVITY_RESUMED, /*timestamp=*/ 47800000L, /*userId=*/ 1,
|
||||||
|
/*instanceId=*/ 2, packageName));
|
||||||
|
appUsageEventList.add(buildAppUsageEvent(
|
||||||
|
AppUsageEventType.ACTIVITY_STOPPED, /*timestamp=*/ 49000000L, /*userId=*/ 1,
|
||||||
|
/*instanceId=*/ 2, packageName));
|
||||||
|
appUsageEventList.add(buildAppUsageEvent(
|
||||||
|
AppUsageEventType.ACTIVITY_RESUMED, /*timestamp=*/ 59600000L, /*userId=*/ 1,
|
||||||
/*instanceId=*/ 4, packageName));
|
/*instanceId=*/ 4, packageName));
|
||||||
appUsageEventList.add(buildAppUsageEvent(
|
appUsageEventList.add(buildAppUsageEvent(
|
||||||
AppUsageEventType.ACTIVITY_STOPPED, /*timestamp=*/ 52000L, /*userId=*/ 1,
|
AppUsageEventType.ACTIVITY_STOPPED, /*timestamp=*/ 61200000L, /*userId=*/ 1,
|
||||||
/*instanceId=*/ 4, packageName));
|
|
||||||
appUsageEventList.add(buildAppUsageEvent(
|
|
||||||
AppUsageEventType.ACTIVITY_RESUMED, /*timestamp=*/ 55000L, /*userId=*/ 1,
|
|
||||||
/*instanceId=*/ 4, packageName));
|
|
||||||
appUsageEventList.add(buildAppUsageEvent(
|
|
||||||
AppUsageEventType.ACTIVITY_STOPPED, /*timestamp=*/ 58000L, /*userId=*/ 1,
|
|
||||||
/*instanceId=*/ 4, packageName));
|
/*instanceId=*/ 4, packageName));
|
||||||
|
|
||||||
final Map<Integer, Map<Integer, Map<Long, Map<String, List<AppUsagePeriod>>>>> periodMap =
|
final Map<Integer, Map<Integer, Map<Long, Map<String, List<AppUsagePeriod>>>>> periodMap =
|
||||||
DataProcessor.generateAppUsagePeriodMap(
|
DataProcessor.generateAppUsagePeriodMap(
|
||||||
hourlyBatteryLevelsPerDay, appUsageEventList, startTimestampOfLevelData);
|
hourlyBatteryLevelsPerDay, appUsageEventList);
|
||||||
|
|
||||||
assertThat(periodMap.size()).isEqualTo(3);
|
assertThat(periodMap.size()).isEqualTo(3);
|
||||||
// Day 1
|
// Day 1
|
||||||
@@ -246,11 +255,12 @@ public final class DataProcessorTest {
|
|||||||
Map<String, List<AppUsagePeriod>> userMap = hourlyMap.get(1L);
|
Map<String, List<AppUsagePeriod>> userMap = hourlyMap.get(1L);
|
||||||
assertThat(userMap.size()).isEqualTo(1);
|
assertThat(userMap.size()).isEqualTo(1);
|
||||||
assertThat(userMap.get(packageName).size()).isEqualTo(1);
|
assertThat(userMap.get(packageName).size()).isEqualTo(1);
|
||||||
assertAppUsagePeriod(userMap.get(packageName).get(0), 10000, 15000);
|
assertAppUsagePeriod(userMap.get(packageName).get(0), 17200000L, 17800000L);
|
||||||
userMap = hourlyMap.get(2L);
|
userMap = hourlyMap.get(2L);
|
||||||
assertThat(userMap.size()).isEqualTo(1);
|
assertThat(userMap.size()).isEqualTo(1);
|
||||||
assertThat(userMap.get(packageName).size()).isEqualTo(1);
|
assertThat(userMap.get(packageName).size()).isEqualTo(2);
|
||||||
assertAppUsagePeriod(userMap.get(packageName).get(0), 12000, 18000);
|
assertAppUsagePeriod(userMap.get(packageName).get(0), 14400000L, 15600000L);
|
||||||
|
assertAppUsagePeriod(userMap.get(packageName).get(1), 16200000L, 18000000L);
|
||||||
hourlyMap = periodMap.get(0).get(1);
|
hourlyMap = periodMap.get(0).get(1);
|
||||||
assertThat(hourlyMap).isNull();
|
assertThat(hourlyMap).isNull();
|
||||||
// Day 2
|
// Day 2
|
||||||
@@ -262,8 +272,8 @@ public final class DataProcessorTest {
|
|||||||
userMap = hourlyMap.get(1L);
|
userMap = hourlyMap.get(1L);
|
||||||
assertThat(userMap.size()).isEqualTo(1);
|
assertThat(userMap.size()).isEqualTo(1);
|
||||||
assertThat(userMap.get(packageName).size()).isEqualTo(2);
|
assertThat(userMap.get(packageName).size()).isEqualTo(2);
|
||||||
assertAppUsagePeriod(userMap.get(packageName).get(0), 40000, 45000);
|
assertAppUsagePeriod(userMap.get(packageName).get(0), 45970000L, 46000000L);
|
||||||
assertAppUsagePeriod(userMap.get(packageName).get(1), 42000, 50000);
|
assertAppUsagePeriod(userMap.get(packageName).get(1), 47800000L, 48800000L);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -273,7 +283,7 @@ public final class DataProcessorTest {
|
|||||||
hourlyBatteryLevelsPerDay.add(
|
hourlyBatteryLevelsPerDay.add(
|
||||||
new BatteryLevelData.PeriodBatteryLevelData(new ArrayList<>(), new ArrayList<>()));
|
new BatteryLevelData.PeriodBatteryLevelData(new ArrayList<>(), new ArrayList<>()));
|
||||||
assertThat(DataProcessor.generateAppUsagePeriodMap(
|
assertThat(DataProcessor.generateAppUsagePeriodMap(
|
||||||
hourlyBatteryLevelsPerDay, new ArrayList<>(), 0)).isNull();
|
hourlyBatteryLevelsPerDay, new ArrayList<>())).isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -1508,9 +1518,19 @@ public final class DataProcessorTest {
|
|||||||
@Test
|
@Test
|
||||||
public void buildAppUsagePeriodListPerInstance_returnExpectedResult() {
|
public void buildAppUsagePeriodListPerInstance_returnExpectedResult() {
|
||||||
final List<AppUsageEvent> appUsageEvents = new ArrayList<>();
|
final List<AppUsageEvent> appUsageEvents = new ArrayList<>();
|
||||||
|
// Fake data earlier than time range.
|
||||||
|
appUsageEvents.add(buildAppUsageEvent(
|
||||||
|
AppUsageEventType.ACTIVITY_RESUMED, /*timestamp=*/ 1));
|
||||||
|
appUsageEvents.add(buildAppUsageEvent(
|
||||||
|
AppUsageEventType.ACTIVITY_STOPPED, /*timestamp=*/ 2));
|
||||||
|
// Fake resume event earlier than time range.
|
||||||
|
appUsageEvents.add(buildAppUsageEvent(
|
||||||
|
AppUsageEventType.ACTIVITY_RESUMED, /*timestamp=*/ 3));
|
||||||
|
appUsageEvents.add(buildAppUsageEvent(
|
||||||
|
AppUsageEventType.ACTIVITY_STOPPED, /*timestamp=*/ 120000));
|
||||||
// Fake normal data.
|
// Fake normal data.
|
||||||
appUsageEvents.add(buildAppUsageEvent(
|
appUsageEvents.add(buildAppUsageEvent(
|
||||||
AppUsageEventType.ACTIVITY_RESUMED, /*timestamp=*/ 100000));
|
AppUsageEventType.ACTIVITY_RESUMED, /*timestamp=*/ 150000));
|
||||||
appUsageEvents.add(buildAppUsageEvent(
|
appUsageEvents.add(buildAppUsageEvent(
|
||||||
AppUsageEventType.ACTIVITY_STOPPED, /*timestamp=*/ 200000));
|
AppUsageEventType.ACTIVITY_STOPPED, /*timestamp=*/ 200000));
|
||||||
// Fake two adjacent resume events.
|
// Fake two adjacent resume events.
|
||||||
@@ -1540,29 +1560,16 @@ public final class DataProcessorTest {
|
|||||||
AppUsageEventType.ACTIVITY_RESUMED, /*timestamp=*/ 1000000));
|
AppUsageEventType.ACTIVITY_RESUMED, /*timestamp=*/ 1000000));
|
||||||
|
|
||||||
final List<AppUsagePeriod> appUsagePeriodList =
|
final List<AppUsagePeriod> appUsagePeriodList =
|
||||||
DataProcessor.buildAppUsagePeriodListPerInstance(appUsageEvents, 0, 1100000);
|
DataProcessor.buildAppUsagePeriodListPerInstance(appUsageEvents, 100000, 1100000);
|
||||||
|
|
||||||
assertThat(appUsagePeriodList.size()).isEqualTo(6);
|
assertThat(appUsagePeriodList.size()).isEqualTo(7);
|
||||||
assertAppUsagePeriod(appUsagePeriodList.get(0), 100000, 200000);
|
assertAppUsagePeriod(appUsagePeriodList.get(0), 100000, 120000);
|
||||||
assertAppUsagePeriod(appUsagePeriodList.get(1), 300000, 500000);
|
assertAppUsagePeriod(appUsagePeriodList.get(1), 150000, 200000);
|
||||||
assertAppUsagePeriod(appUsagePeriodList.get(2), 570000, 600000);
|
assertAppUsagePeriod(appUsagePeriodList.get(2), 300000, 500000);
|
||||||
assertAppUsagePeriod(appUsagePeriodList.get(3), 700000, 730000);
|
assertAppUsagePeriod(appUsagePeriodList.get(3), 570000, 600000);
|
||||||
assertAppUsagePeriod(appUsagePeriodList.get(4), 900000, 910000);
|
assertAppUsagePeriod(appUsagePeriodList.get(4), 700000, 730000);
|
||||||
assertAppUsagePeriod(appUsagePeriodList.get(5), 1000000, 1100000);
|
assertAppUsagePeriod(appUsagePeriodList.get(5), 900000, 910000);
|
||||||
}
|
assertAppUsagePeriod(appUsagePeriodList.get(6), 1000000, 1100000);
|
||||||
|
|
||||||
@Test
|
|
||||||
public void buildAppUsagePeriodListPerInstance_notMetStart_returnExpectedResult() {
|
|
||||||
final List<AppUsageEvent> appUsageEvents = new ArrayList<>();
|
|
||||||
// Start with stop event.
|
|
||||||
appUsageEvents.add(buildAppUsageEvent(
|
|
||||||
AppUsageEventType.ACTIVITY_STOPPED, /*timestamp=*/ 100000));
|
|
||||||
|
|
||||||
final List<AppUsagePeriod> appUsagePeriodList =
|
|
||||||
DataProcessor.buildAppUsagePeriodListPerInstance(appUsageEvents, 0, 200000);
|
|
||||||
|
|
||||||
assertThat(appUsageEvents.size()).isEqualTo(1);
|
|
||||||
assertAppUsagePeriod(appUsagePeriodList.get(0), 0, 100000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
Reference in New Issue
Block a user