Add cache strategy for getUsageSource().

Cache usage source into SharedPreferences when phone is booting to avoid
calling it too frequently.
It should be safe because the usage source can only change on reboot.

Bug: 293366011
Test: make RunSettingsRoboTests
Change-Id: I35c07539d294737c5764b03b746cfb39f4ce008d
This commit is contained in:
Kuan Wang
2023-07-28 13:31:31 +08:00
parent 98df5bcde2
commit 64177774e2
10 changed files with 190 additions and 85 deletions

View File

@@ -83,6 +83,10 @@ public final class BootBroadcastReceiver extends BroadcastReceiver {
recheckIntent.setClass(context, BootBroadcastReceiver.class); recheckIntent.setClass(context, BootBroadcastReceiver.class);
final long delayedTime = getRescheduleTimeForBootAction(context); final long delayedTime = getRescheduleTimeForBootAction(context);
mHandler.postDelayed(() -> context.sendBroadcast(recheckIntent), delayedTime); mHandler.postDelayed(() -> context.sendBroadcast(recheckIntent), delayedTime);
// Refreshes the usage source from UsageStatsManager when booting.
DatabaseUtils.removeUsageSource(context);
BatteryUsageLogUtils.writeLog(context, Action.RECHECK_JOB, "delay:" + delayedTime); BatteryUsageLogUtils.writeLog(context, Action.RECHECK_JOB, "delay:" + delayedTime);
} else if (ACTION_SETUP_WIZARD_FINISHED.equals(action)) { } else if (ACTION_SETUP_WIZARD_FINISHED.equals(action)) {
ElapsedTimeUtils.storeSuwFinishedTimestamp(context, System.currentTimeMillis()); ElapsedTimeUtils.storeSuwFinishedTimestamp(context, System.currentTimeMillis());

View File

@@ -17,7 +17,6 @@ package com.android.settings.fuelgauge.batteryusage;
import android.annotation.IntDef; import android.annotation.IntDef;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.app.usage.IUsageStatsManager;
import android.app.usage.UsageEvents.Event; import android.app.usage.UsageEvents.Event;
import android.app.usage.UsageStatsManager; import android.app.usage.UsageStatsManager;
import android.content.ContentValues; import android.content.ContentValues;
@@ -27,7 +26,6 @@ import android.database.Cursor;
import android.os.BatteryUsageStats; import android.os.BatteryUsageStats;
import android.os.Build; import android.os.Build;
import android.os.LocaleList; import android.os.LocaleList;
import android.os.RemoteException;
import android.os.UserHandle; import android.os.UserHandle;
import android.text.TextUtils; import android.text.TextUtils;
import android.text.format.DateFormat; import android.text.format.DateFormat;
@@ -67,6 +65,12 @@ public final class ConvertUtils {
public static final int CONSUMER_TYPE_USER_BATTERY = 2; public static final int CONSUMER_TYPE_USER_BATTERY = 2;
public static final int CONSUMER_TYPE_SYSTEM_BATTERY = 3; public static final int CONSUMER_TYPE_SYSTEM_BATTERY = 3;
public static final int DEFAULT_USAGE_SOURCE = UsageStatsManager.USAGE_SOURCE_CURRENT_ACTIVITY;
public static final int EMPTY_USAGE_SOURCE = -1;
@VisibleForTesting
static int sUsageSource = EMPTY_USAGE_SOURCE;
private ConvertUtils() { private ConvertUtils() {
} }
@@ -181,8 +185,7 @@ public final class ConvertUtils {
/** Converts to {@link AppUsageEvent} from {@link Event} */ /** Converts to {@link AppUsageEvent} from {@link Event} */
@Nullable @Nullable
public static AppUsageEvent convertToAppUsageEvent( public static AppUsageEvent convertToAppUsageEvent(
Context context, final IUsageStatsManager usageStatsManager, final Event event, Context context, final Event event, final long userId) {
final long userId) {
final String packageName = event.getPackageName(); final String packageName = event.getPackageName();
if (packageName == null) { if (packageName == null) {
// See b/190609174: Event package names should never be null, but sometimes they are. // See b/190609174: Event package names should never be null, but sometimes they are.
@@ -207,7 +210,7 @@ public final class ConvertUtils {
} }
final String effectivePackageName = final String effectivePackageName =
getEffectivePackageName(usageStatsManager, packageName, taskRootPackageName); getEffectivePackageName(context, packageName, taskRootPackageName);
try { try {
final long uid = context final long uid = context
.getPackageManager() .getPackageManager()
@@ -323,9 +326,8 @@ public final class ConvertUtils {
*/ */
@VisibleForTesting @VisibleForTesting
static String getEffectivePackageName( static String getEffectivePackageName(
final IUsageStatsManager usageStatsManager, final String packageName, Context context, final String packageName, final String taskRootPackageName) {
final String taskRootPackageName) { final int usageSource = getUsageSource(context);
int usageSource = getUsageSource(usageStatsManager);
switch (usageSource) { switch (usageSource) {
case UsageStatsManager.USAGE_SOURCE_TASK_ROOT_ACTIVITY: case UsageStatsManager.USAGE_SOURCE_TASK_ROOT_ACTIVITY:
return !TextUtils.isEmpty(taskRootPackageName) return !TextUtils.isEmpty(taskRootPackageName)
@@ -370,18 +372,11 @@ public final class ConvertUtils {
} }
} }
/** private static int getUsageSource(Context context) {
* Returns what App Usage Observers will consider the source of usage for an activity. if (sUsageSource == EMPTY_USAGE_SOURCE) {
* sUsageSource = DatabaseUtils.getUsageSource(context);
* @see UsageStatsManager#getUsageSource()
*/
private static int getUsageSource(final IUsageStatsManager usageStatsManager) {
try {
return usageStatsManager.getUsageSource();
} catch (RemoteException e) {
Log.e(TAG, "Failed to getUsageSource", e);
return UsageStatsManager.USAGE_SOURCE_CURRENT_ACTIVITY;
} }
return sUsageSource;
} }
private static AppUsageEventType getAppUsageEventType(final int eventType) { private static AppUsageEventType getAppUsageEventType(final int eventType) {

View File

@@ -397,8 +397,8 @@ 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(mRawStartTimestamp, mAppUsagePeriodMap = DataProcessor.generateAppUsagePeriodMap(
mHourlyBatteryLevelsPerDay, mAppUsageEventList, mBatteryEventList); mContext, mHourlyBatteryLevelsPerDay, mAppUsageEventList, mBatteryEventList);
} }
private void tryToGenerateFinalDataAndApplyCallback() { private void tryToGenerateFinalDataAndApplyCallback() {

View File

@@ -32,7 +32,6 @@ import android.os.BatteryUsageStats;
import android.os.BatteryUsageStatsQuery; import android.os.BatteryUsageStatsQuery;
import android.os.Process; import android.os.Process;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UidBatteryConsumer; import android.os.UidBatteryConsumer;
import android.os.UserBatteryConsumer; import android.os.UserBatteryConsumer;
import android.os.UserHandle; import android.os.UserHandle;
@@ -78,8 +77,6 @@ public final class DataProcessor {
private static final int MIN_DAILY_DATA_SIZE = 2; private static final int MIN_DAILY_DATA_SIZE = 2;
private static final int MIN_TIMESTAMP_DATA_SIZE = 2; private static final int MIN_TIMESTAMP_DATA_SIZE = 2;
private static final int MAX_DIFF_SECONDS_OF_UPPER_TIMESTAMP = 5; private static final int MAX_DIFF_SECONDS_OF_UPPER_TIMESTAMP = 5;
// Maximum total time value for each hourly slot cumulative data at most 2 hours.
private static final float TOTAL_HOURLY_TIME_THRESHOLD = DateUtils.HOUR_IN_MILLIS * 2;
private static final long MIN_TIME_SLOT = DateUtils.HOUR_IN_MILLIS * 2; private static final long MIN_TIME_SLOT = DateUtils.HOUR_IN_MILLIS * 2;
private static final String MEDIASERVER_PACKAGE_NAME = "mediaserver"; private static final String MEDIASERVER_PACKAGE_NAME = "mediaserver";
private static final String ANDROID_CORE_APPS_SHARED_USER_ID = "android.uid.shared"; private static final String ANDROID_CORE_APPS_SHARED_USER_ID = "android.uid.shared";
@@ -111,11 +108,6 @@ public final class DataProcessor {
@VisibleForTesting @VisibleForTesting
static Set<String> sTestSystemAppsPackageNames; static Set<String> sTestSystemAppsPackageNames;
@VisibleForTesting
static IUsageStatsManager sUsageStatsManager =
IUsageStatsManager.Stub.asInterface(
ServiceManager.getService(Context.USAGE_STATS_SERVICE));
public static final String CURRENT_TIME_BATTERY_HISTORY_PLACEHOLDER = public static final String CURRENT_TIME_BATTERY_HISTORY_PLACEHOLDER =
"CURRENT_TIME_BATTERY_HISTORY_PLACEHOLDER"; "CURRENT_TIME_BATTERY_HISTORY_PLACEHOLDER";
@@ -271,7 +263,7 @@ public final class DataProcessor {
@Nullable @Nullable
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 long rawStartTimestamp, Context context,
final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay, final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay,
final List<AppUsageEvent> appUsageEventList, final List<AppUsageEvent> appUsageEventList,
final List<BatteryEvent> batteryEventList) { final List<BatteryEvent> batteryEventList) {
@@ -305,7 +297,7 @@ public final class DataProcessor {
// 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(
hourlyIndex, hourlyIndex,
buildAppUsagePeriodList(hourlyAppUsageEventList, batteryEventList, buildAppUsagePeriodList(context, hourlyAppUsageEventList, batteryEventList,
startTimestamp, endTimestamp)); startTimestamp, endTimestamp));
} }
} }
@@ -346,8 +338,7 @@ public final class DataProcessor {
break; break;
} }
final AppUsageEvent appUsageEvent = final AppUsageEvent appUsageEvent =
ConvertUtils.convertToAppUsageEvent( ConvertUtils.convertToAppUsageEvent(context, event, userId);
context, sUsageStatsManager, event, userId);
if (appUsageEvent != null) { if (appUsageEvent != null) {
numEventsFetched++; numEventsFetched++;
appUsageEventList.add(appUsageEvent); appUsageEventList.add(appUsageEvent);
@@ -661,8 +652,8 @@ public final class DataProcessor {
@VisibleForTesting @VisibleForTesting
@Nullable @Nullable
static Map<Long, Map<String, List<AppUsagePeriod>>> buildAppUsagePeriodList( static Map<Long, Map<String, List<AppUsagePeriod>>> buildAppUsagePeriodList(
final List<AppUsageEvent> appUsageEvents, final List<BatteryEvent> batteryEventList, Context context, final List<AppUsageEvent> appUsageEvents,
final long startTime, final long endTime) { final List<BatteryEvent> batteryEventList, final long startTime, final long endTime) {
if (appUsageEvents.isEmpty()) { if (appUsageEvents.isEmpty()) {
return null; return null;
} }
@@ -702,7 +693,7 @@ public final class DataProcessor {
final AppUsageEvent firstEvent = usageEvents.get(0); final AppUsageEvent firstEvent = usageEvents.get(0);
final long eventUserId = firstEvent.getUserId(); final long eventUserId = firstEvent.getUserId();
final String packageName = getEffectivePackageName( final String packageName = getEffectivePackageName(
sUsageStatsManager, context,
firstEvent.getPackageName(), firstEvent.getPackageName(),
firstEvent.getTaskRootPackageName()); firstEvent.getTaskRootPackageName());
usageEvents.addAll(deviceEvents); usageEvents.addAll(deviceEvents);
@@ -975,7 +966,7 @@ public final class DataProcessor {
final long startTime = DatabaseUtils.getAppUsageStartTimestampOfUser( final long startTime = DatabaseUtils.getAppUsageStartTimestampOfUser(
context, userID, earliestTimestamp); context, userID, earliestTimestamp);
return loadAppUsageEventsForUserFromService( return loadAppUsageEventsForUserFromService(
sUsageStatsManager, startTime, now, userID, callingPackage); DatabaseUtils.sUsageStatsManager, startTime, now, userID, callingPackage);
} }
@Nullable @Nullable

View File

@@ -15,6 +15,8 @@
*/ */
package com.android.settings.fuelgauge.batteryusage; package com.android.settings.fuelgauge.batteryusage;
import android.app.usage.IUsageStatsManager;
import android.app.usage.UsageStatsManager;
import android.content.ContentResolver; import android.content.ContentResolver;
import android.content.ContentValues; import android.content.ContentValues;
import android.content.Context; import android.content.Context;
@@ -28,6 +30,8 @@ import android.os.BatteryManager;
import android.os.BatteryUsageStats; import android.os.BatteryUsageStats;
import android.os.Handler; import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock; import android.os.SystemClock;
import android.os.UserManager; import android.os.UserManager;
import android.util.Log; import android.util.Log;
@@ -63,6 +67,7 @@ public final class DatabaseUtils {
static final int DATA_RETENTION_INTERVAL_DAY = 9; static final int DATA_RETENTION_INTERVAL_DAY = 9;
static final String KEY_LAST_LOAD_FULL_CHARGE_TIME = "last_load_full_charge_time"; static final String KEY_LAST_LOAD_FULL_CHARGE_TIME = "last_load_full_charge_time";
static final String KEY_LAST_UPLOAD_FULL_CHARGE_TIME = "last_upload_full_charge_time"; static final String KEY_LAST_UPLOAD_FULL_CHARGE_TIME = "last_upload_full_charge_time";
static final String KEY_LAST_USAGE_SOURCE = "last_usage_source";
/** An authority name of the battery content provider. */ /** An authority name of the battery content provider. */
public static final String AUTHORITY = "com.android.settings.battery.usage.provider"; public static final String AUTHORITY = "com.android.settings.battery.usage.provider";
@@ -74,8 +79,6 @@ public final class DatabaseUtils {
public static final String BATTERY_STATE_TABLE = "BatteryState"; public static final String BATTERY_STATE_TABLE = "BatteryState";
/** A path name for app usage latest timestamp query. */ /** A path name for app usage latest timestamp query. */
public static final String APP_USAGE_LATEST_TIMESTAMP_PATH = "appUsageLatestTimestamp"; public static final String APP_USAGE_LATEST_TIMESTAMP_PATH = "appUsageLatestTimestamp";
/** A class name for battery usage data provider. */
public static final String SETTINGS_PACKAGE_PATH = "com.android.settings";
/** Key for query parameter timestamp used in BATTERY_CONTENT_URI **/ /** Key for query parameter timestamp used in BATTERY_CONTENT_URI **/
public static final String QUERY_KEY_TIMESTAMP = "timestamp"; public static final String QUERY_KEY_TIMESTAMP = "timestamp";
/** Key for query parameter userid used in APP_USAGE_EVENT_URI **/ /** Key for query parameter userid used in APP_USAGE_EVENT_URI **/
@@ -114,6 +117,11 @@ public final class DatabaseUtils {
@VisibleForTesting @VisibleForTesting
static Supplier<Cursor> sFakeSupplier; static Supplier<Cursor> sFakeSupplier;
@VisibleForTesting
static IUsageStatsManager sUsageStatsManager =
IUsageStatsManager.Stub.asInterface(
ServiceManager.getService(Context.USAGE_STATS_SERVICE));
private DatabaseUtils() { private DatabaseUtils() {
} }
@@ -468,6 +476,37 @@ public final class DatabaseUtils {
SHARED_PREFS_FILE, Context.MODE_PRIVATE); SHARED_PREFS_FILE, Context.MODE_PRIVATE);
} }
static void removeUsageSource(Context context) {
final SharedPreferences sharedPreferences = getSharedPreferences(context);
if (sharedPreferences != null && sharedPreferences.contains(KEY_LAST_USAGE_SOURCE)) {
sharedPreferences.edit().remove(KEY_LAST_USAGE_SOURCE).apply();
}
}
/**
* Returns what App Usage Observers will consider the source of usage for an activity.
*
* @see UsageStatsManager#getUsageSource()
*/
static int getUsageSource(Context context) {
final SharedPreferences sharedPreferences = getSharedPreferences(context);
if (sharedPreferences != null && sharedPreferences.contains(KEY_LAST_USAGE_SOURCE)) {
return sharedPreferences
.getInt(KEY_LAST_USAGE_SOURCE, ConvertUtils.DEFAULT_USAGE_SOURCE);
}
int usageSource = ConvertUtils.DEFAULT_USAGE_SOURCE;
try {
usageSource = sUsageStatsManager.getUsageSource();
} catch (RemoteException e) {
Log.e(TAG, "Failed to getUsageSource", e);
}
if (sharedPreferences != null) {
sharedPreferences.edit().putInt(KEY_LAST_USAGE_SOURCE, usageSource).apply();
}
return usageSource;
}
static void recordDateTime(Context context, String preferenceKey) { static void recordDateTime(Context context, String preferenceKey) {
final SharedPreferences sharedPreferences = getSharedPreferences(context); final SharedPreferences sharedPreferences = getSharedPreferences(context);
if (sharedPreferences != null) { if (sharedPreferences != null) {
@@ -564,7 +603,7 @@ public final class DatabaseUtils {
private static Map<Long, Map<String, BatteryHistEntry>> loadHistoryMapFromContentProvider( private static Map<Long, Map<String, BatteryHistEntry>> loadHistoryMapFromContentProvider(
Context context, Uri batteryStateUri) { Context context, Uri batteryStateUri) {
context = DatabaseUtils.getParentContext(context); context = getParentContext(context);
if (context == null) { if (context == null) {
return null; return null;
} }

View File

@@ -22,8 +22,10 @@ import static org.robolectric.Shadows.shadowOf;
import android.app.AlarmManager; import android.app.AlarmManager;
import android.app.Application; import android.app.Application;
import android.app.usage.UsageStatsManager;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences;
import androidx.test.core.app.ApplicationProvider; import androidx.test.core.app.ApplicationProvider;
@@ -40,7 +42,6 @@ import org.robolectric.Shadows;
import org.robolectric.shadows.ShadowAlarmManager; import org.robolectric.shadows.ShadowAlarmManager;
import java.time.Clock; import java.time.Clock;
import java.time.Duration;
import java.util.List; import java.util.List;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@@ -65,10 +66,12 @@ public final class BootBroadcastReceiverTest {
BatteryTestUtils.insertDataToBatteryStateTable( BatteryTestUtils.insertDataToBatteryStateTable(
mContext, Clock.systemUTC().millis(), "com.android.systemui"); mContext, Clock.systemUTC().millis(), "com.android.systemui");
mDao = database.batteryStateDao(); mDao = database.batteryStateDao();
clearSharedPreferences();
} }
@After @After
public void tearDown() { public void tearDown() {
clearSharedPreferences();
mPeriodicJobManager.reset(); mPeriodicJobManager.reset();
} }
@@ -82,8 +85,21 @@ public final class BootBroadcastReceiverTest {
@Test @Test
public void onReceive_withBootCompletedIntent_refreshesJob() { public void onReceive_withBootCompletedIntent_refreshesJob() {
final SharedPreferences sharedPreferences = DatabaseUtils.getSharedPreferences(mContext);
sharedPreferences
.edit()
.putInt(DatabaseUtils.KEY_LAST_USAGE_SOURCE,
UsageStatsManager.USAGE_SOURCE_CURRENT_ACTIVITY)
.apply();
mReceiver.onReceive(mContext, new Intent(Intent.ACTION_BOOT_COMPLETED)); mReceiver.onReceive(mContext, new Intent(Intent.ACTION_BOOT_COMPLETED));
assertThat(mShadowAlarmManager.peekNextScheduledAlarm()).isNotNull(); assertThat(mShadowAlarmManager.peekNextScheduledAlarm()).isNotNull();
assertThat(
DatabaseUtils
.getSharedPreferences(mContext)
.contains(DatabaseUtils.KEY_LAST_USAGE_SOURCE))
.isFalse();
} }
@Test @Test
@@ -133,15 +149,7 @@ public final class BootBroadcastReceiverTest {
BootBroadcastReceiver.ACTION_PERIODIC_JOB_RECHECK); BootBroadcastReceiver.ACTION_PERIODIC_JOB_RECHECK);
} }
private void insertExpiredData(int shiftDay) { private void clearSharedPreferences() {
final long expiredTimeInMs = DatabaseUtils.getSharedPreferences(mContext).edit().clear().apply();
Clock.systemUTC().millis() - Duration.ofDays(shiftDay).toMillis();
BatteryTestUtils.insertDataToBatteryStateTable(
mContext, expiredTimeInMs - 1, "com.android.systemui");
BatteryTestUtils.insertDataToBatteryStateTable(
mContext, expiredTimeInMs, "com.android.systemui");
// Ensures the testing environment is correct.
assertThat(mDao.getAllAfter(0)).hasSize(3);
} }
} }

View File

@@ -25,7 +25,6 @@ import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.spy; import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import android.app.usage.IUsageStatsManager;
import android.app.usage.UsageEvents; import android.app.usage.UsageEvents;
import android.app.usage.UsageEvents.Event; import android.app.usage.UsageEvents.Event;
import android.content.ContentValues; import android.content.ContentValues;
@@ -35,7 +34,6 @@ import android.database.MatrixCursor;
import android.os.BatteryManager; import android.os.BatteryManager;
import android.os.BatteryUsageStats; import android.os.BatteryUsageStats;
import android.os.LocaleList; import android.os.LocaleList;
import android.os.RemoteException;
import android.os.UserHandle; import android.os.UserHandle;
import com.android.settings.fuelgauge.batteryusage.db.AppUsageEventEntity; import com.android.settings.fuelgauge.batteryusage.db.AppUsageEventEntity;
@@ -62,14 +60,13 @@ public final class ConvertUtilsTest {
@Mock @Mock
private BatteryUsageStats mBatteryUsageStats; private BatteryUsageStats mBatteryUsageStats;
@Mock @Mock
private IUsageStatsManager mUsageStatsManager;
@Mock
private BatteryEntry mMockBatteryEntry; private BatteryEntry mMockBatteryEntry;
@Before @Before
public void setUp() { public void setUp() {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application); mContext = spy(RuntimeEnvironment.application);
ConvertUtils.sUsageSource = ConvertUtils.EMPTY_USAGE_SOURCE;
when(mContext.getPackageManager()).thenReturn(mMockPackageManager); when(mContext.getPackageManager()).thenReturn(mMockPackageManager);
} }
@@ -302,7 +299,7 @@ public final class ConvertUtilsTest {
final long userId = 2; final long userId = 2;
final AppUsageEvent appUsageEvent = ConvertUtils.convertToAppUsageEvent( final AppUsageEvent appUsageEvent = ConvertUtils.convertToAppUsageEvent(
mContext, mUsageStatsManager, event, userId); mContext, event, userId);
assertThat(appUsageEvent.getTimestamp()).isEqualTo(101L); assertThat(appUsageEvent.getTimestamp()).isEqualTo(101L);
assertThat(appUsageEvent.getType()).isEqualTo(AppUsageEventType.ACTIVITY_RESUMED); assertThat(appUsageEvent.getType()).isEqualTo(AppUsageEventType.ACTIVITY_RESUMED);
assertThat(appUsageEvent.getPackageName()).isEqualTo("com.android.settings1"); assertThat(appUsageEvent.getPackageName()).isEqualTo("com.android.settings1");
@@ -322,8 +319,8 @@ public final class ConvertUtilsTest {
when(mMockPackageManager.getPackageUidAsUser(any(), anyInt())).thenReturn(1001); when(mMockPackageManager.getPackageUidAsUser(any(), anyInt())).thenReturn(1001);
final long userId = 1; final long userId = 1;
final AppUsageEvent appUsageEvent = ConvertUtils.convertToAppUsageEvent( final AppUsageEvent appUsageEvent =
mContext, mUsageStatsManager, event, userId); ConvertUtils.convertToAppUsageEvent(mContext, event, userId);
assertThat(appUsageEvent.getTimestamp()).isEqualTo(101L); assertThat(appUsageEvent.getTimestamp()).isEqualTo(101L);
assertThat(appUsageEvent.getType()).isEqualTo(AppUsageEventType.DEVICE_SHUTDOWN); assertThat(appUsageEvent.getType()).isEqualTo(AppUsageEventType.DEVICE_SHUTDOWN);
assertThat(appUsageEvent.getPackageName()).isEqualTo("com.android.settings1"); assertThat(appUsageEvent.getPackageName()).isEqualTo("com.android.settings1");
@@ -338,8 +335,8 @@ public final class ConvertUtilsTest {
final Event event = new Event(); final Event event = new Event();
event.mPackage = null; event.mPackage = null;
final AppUsageEvent appUsageEvent = ConvertUtils.convertToAppUsageEvent( final AppUsageEvent appUsageEvent =
mContext, mUsageStatsManager, event, /*userId=*/ 0); ConvertUtils.convertToAppUsageEvent(mContext, event, /*userId=*/ 0);
assertThat(appUsageEvent).isNull(); assertThat(appUsageEvent).isNull();
} }
@@ -354,8 +351,8 @@ public final class ConvertUtilsTest {
.thenThrow(new PackageManager.NameNotFoundException()); .thenThrow(new PackageManager.NameNotFoundException());
final long userId = 1; final long userId = 1;
final AppUsageEvent appUsageEvent = ConvertUtils.convertToAppUsageEvent( final AppUsageEvent appUsageEvent =
mContext, mUsageStatsManager, event, userId); ConvertUtils.convertToAppUsageEvent(mContext, event, userId);
assertThat(appUsageEvent).isNull(); assertThat(appUsageEvent).isNull();
} }
@@ -450,51 +447,47 @@ public final class ConvertUtilsTest {
} }
@Test @Test
public void getEffectivePackageName_currentActivity_returnPackageName() throws RemoteException { public void getEffectivePackageName_currentActivity_returnPackageName() {
when(mUsageStatsManager.getUsageSource()).thenReturn(USAGE_SOURCE_CURRENT_ACTIVITY); ConvertUtils.sUsageSource = USAGE_SOURCE_CURRENT_ACTIVITY;
final String packageName = "com.android.settings1"; final String packageName = "com.android.settings1";
final String taskRootPackageName = "com.android.settings2"; final String taskRootPackageName = "com.android.settings2";
assertThat(ConvertUtils.getEffectivePackageName( assertThat(ConvertUtils.getEffectivePackageName(
mUsageStatsManager, packageName, taskRootPackageName)) mContext, packageName, taskRootPackageName))
.isEqualTo(packageName); .isEqualTo(packageName);
} }
@Test @Test
public void getEffectivePackageName_usageSourceThrowException_returnPackageName() public void getEffectivePackageName_emptyUsageSource_returnPackageName() {
throws RemoteException {
when(mUsageStatsManager.getUsageSource()).thenThrow(new RemoteException());
final String packageName = "com.android.settings1"; final String packageName = "com.android.settings1";
final String taskRootPackageName = "com.android.settings2"; final String taskRootPackageName = "com.android.settings2";
assertThat(ConvertUtils.getEffectivePackageName( assertThat(ConvertUtils.getEffectivePackageName(
mUsageStatsManager, packageName, taskRootPackageName)) mContext, packageName, taskRootPackageName))
.isEqualTo(packageName); .isEqualTo(packageName);
} }
@Test @Test
public void getEffectivePackageName_rootActivity_returnTaskRootPackageName() public void getEffectivePackageName_rootActivity_returnTaskRootPackageName() {
throws RemoteException { ConvertUtils.sUsageSource = USAGE_SOURCE_TASK_ROOT_ACTIVITY;
when(mUsageStatsManager.getUsageSource()).thenReturn(USAGE_SOURCE_TASK_ROOT_ACTIVITY);
final String packageName = "com.android.settings1"; final String packageName = "com.android.settings1";
final String taskRootPackageName = "com.android.settings2"; final String taskRootPackageName = "com.android.settings2";
assertThat(ConvertUtils.getEffectivePackageName( assertThat(ConvertUtils.getEffectivePackageName(
mUsageStatsManager, packageName, taskRootPackageName)) mContext, packageName, taskRootPackageName))
.isEqualTo(taskRootPackageName); .isEqualTo(taskRootPackageName);
} }
@Test @Test
public void getEffectivePackageName_nullOrEmptyTaskRoot_returnPackageName() public void getEffectivePackageName_nullOrEmptyTaskRoot_returnPackageName() {
throws RemoteException { ConvertUtils.sUsageSource = USAGE_SOURCE_TASK_ROOT_ACTIVITY;
when(mUsageStatsManager.getUsageSource()).thenReturn(USAGE_SOURCE_TASK_ROOT_ACTIVITY);
final String packageName = "com.android.settings1"; final String packageName = "com.android.settings1";
assertThat(ConvertUtils.getEffectivePackageName( assertThat(ConvertUtils.getEffectivePackageName(
mUsageStatsManager, packageName, /*taskRootPackageName=*/ null)) mContext, packageName, /*taskRootPackageName=*/ null))
.isEqualTo(packageName); .isEqualTo(packageName);
assertThat(ConvertUtils.getEffectivePackageName( assertThat(ConvertUtils.getEffectivePackageName(
mUsageStatsManager, packageName, /*taskRootPackageName=*/ "")) mContext, packageName, /*taskRootPackageName=*/ ""))
.isEqualTo(packageName); .isEqualTo(packageName);
} }
} }

View File

@@ -72,7 +72,7 @@ public final class DataProcessManagerTest {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application); mContext = spy(RuntimeEnvironment.application);
DataProcessor.sUsageStatsManager = mUsageStatsManager; DatabaseUtils.sUsageStatsManager = mUsageStatsManager;
doReturn(mContext).when(mContext).getApplicationContext(); doReturn(mContext).when(mContext).getApplicationContext();
doReturn(mUserManager) doReturn(mUserManager)
.when(mContext) .when(mContext)

View File

@@ -93,7 +93,7 @@ public final class DataProcessorTest {
mPowerUsageFeatureProvider = mFeatureFactory.powerUsageFeatureProvider; mPowerUsageFeatureProvider = mFeatureFactory.powerUsageFeatureProvider;
DataProcessor.sTestSystemAppsPackageNames = Set.of(); DataProcessor.sTestSystemAppsPackageNames = Set.of();
DataProcessor.sUsageStatsManager = mUsageStatsManager; DatabaseUtils.sUsageStatsManager = mUsageStatsManager;
doReturn(mIntent).when(mContext).registerReceiver( doReturn(mIntent).when(mContext).registerReceiver(
isA(BroadcastReceiver.class), isA(IntentFilter.class)); isA(BroadcastReceiver.class), isA(IntentFilter.class));
doReturn(100).when(mIntent).getIntExtra(eq(BatteryManager.EXTRA_SCALE), anyInt()); doReturn(100).when(mIntent).getIntExtra(eq(BatteryManager.EXTRA_SCALE), anyInt());
@@ -249,7 +249,7 @@ public final class DataProcessorTest {
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(
14400000L, hourlyBatteryLevelsPerDay, appUsageEventList, new ArrayList<>()); mContext, hourlyBatteryLevelsPerDay, appUsageEventList, new ArrayList<>());
assertThat(periodMap).hasSize(3); assertThat(periodMap).hasSize(3);
// Day 1 // Day 1
@@ -287,7 +287,8 @@ 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(
0L, hourlyBatteryLevelsPerDay, new ArrayList<>(), new ArrayList<>())).isNull(); mContext, hourlyBatteryLevelsPerDay, new ArrayList<>(), new ArrayList<>()))
.isNull();
} }
@Test @Test
@@ -1644,7 +1645,7 @@ public final class DataProcessorTest {
final Map<Long, Map<String, List<AppUsagePeriod>>> appUsagePeriodMap = final Map<Long, Map<String, List<AppUsagePeriod>>> appUsagePeriodMap =
DataProcessor.buildAppUsagePeriodList( DataProcessor.buildAppUsagePeriodList(
appUsageEvents, new ArrayList<>(), 0, 5); mContext, appUsageEvents, new ArrayList<>(), 0, 5);
assertThat(appUsagePeriodMap).hasSize(2); assertThat(appUsagePeriodMap).hasSize(2);
final Map<String, List<AppUsagePeriod>> userMap1 = appUsagePeriodMap.get(1L); final Map<String, List<AppUsagePeriod>> userMap1 = appUsagePeriodMap.get(1L);
@@ -1668,7 +1669,7 @@ public final class DataProcessorTest {
@Test @Test
public void buildAppUsagePeriodList_emptyEventList_returnNull() { public void buildAppUsagePeriodList_emptyEventList_returnNull() {
assertThat(DataProcessor.buildAppUsagePeriodList( assertThat(DataProcessor.buildAppUsagePeriodList(
new ArrayList<>(), new ArrayList<>(), 0, 1)).isNull(); mContext, new ArrayList<>(), new ArrayList<>(), 0, 1)).isNull();
} }
@Test @Test
@@ -1680,7 +1681,7 @@ public final class DataProcessorTest {
AppUsageEventType.DEVICE_SHUTDOWN, /*timestamp=*/ 2)); AppUsageEventType.DEVICE_SHUTDOWN, /*timestamp=*/ 2));
assertThat(DataProcessor.buildAppUsagePeriodList( assertThat(DataProcessor.buildAppUsagePeriodList(
appUsageEvents, new ArrayList<>(), 0, 3)).isNull(); mContext, appUsageEvents, new ArrayList<>(), 0, 3)).isNull();
} }
@Test @Test

View File

@@ -16,6 +16,9 @@
package com.android.settings.fuelgauge.batteryusage; package com.android.settings.fuelgauge.batteryusage;
import static android.app.usage.UsageStatsManager.USAGE_SOURCE_CURRENT_ACTIVITY;
import static android.app.usage.UsageStatsManager.USAGE_SOURCE_TASK_ROOT_ACTIVITY;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
@@ -23,15 +26,19 @@ import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy; import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import android.app.usage.IUsageStatsManager;
import android.content.ContentResolver; import android.content.ContentResolver;
import android.content.ContentValues; import android.content.ContentValues;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.database.MatrixCursor; import android.database.MatrixCursor;
import android.os.BatteryManager; import android.os.BatteryManager;
import android.os.BatteryUsageStats; import android.os.BatteryUsageStats;
import android.os.RemoteException;
import android.os.UserHandle; import android.os.UserHandle;
import android.os.UserManager; import android.os.UserManager;
@@ -67,6 +74,7 @@ public final class DatabaseUtilsTest {
@Mock private BatteryEntry mMockBatteryEntry2; @Mock private BatteryEntry mMockBatteryEntry2;
@Mock private BatteryEntry mMockBatteryEntry3; @Mock private BatteryEntry mMockBatteryEntry3;
@Mock private Context mMockContext; @Mock private Context mMockContext;
@Mock private IUsageStatsManager mUsageStatsManager;
@Before @Before
public void setUp() { public void setUp() {
@@ -77,6 +85,7 @@ public final class DatabaseUtilsTest {
doReturn(mPackageManager).when(mMockContext).getPackageManager(); doReturn(mPackageManager).when(mMockContext).getPackageManager();
doReturn(mPackageManager).when(mContext).getPackageManager(); doReturn(mPackageManager).when(mContext).getPackageManager();
DatabaseUtils.getSharedPreferences(mContext).edit().clear().apply(); DatabaseUtils.getSharedPreferences(mContext).edit().clear().apply();
DatabaseUtils.sUsageStatsManager = mUsageStatsManager;
} }
@Test @Test
@@ -422,6 +431,71 @@ public final class DatabaseUtilsTest {
assertThat(batteryHistMap).isEmpty(); assertThat(batteryHistMap).isEmpty();
} }
@Test
public void removeUsageSource_hasNoData() {
DatabaseUtils.removeUsageSource(mContext);
assertThat(
DatabaseUtils
.getSharedPreferences(mContext)
.contains(DatabaseUtils.KEY_LAST_USAGE_SOURCE))
.isFalse();
}
@Test
public void removeUsageSource_hasData_deleteUsageSource() {
final SharedPreferences sharedPreferences = DatabaseUtils.getSharedPreferences(mContext);
sharedPreferences
.edit()
.putInt(DatabaseUtils.KEY_LAST_USAGE_SOURCE, USAGE_SOURCE_TASK_ROOT_ACTIVITY)
.apply();
DatabaseUtils.removeUsageSource(mContext);
assertThat(
DatabaseUtils
.getSharedPreferences(mContext)
.contains(DatabaseUtils.KEY_LAST_USAGE_SOURCE))
.isFalse();
}
@Test
public void getUsageSource_hasData() {
final SharedPreferences sharedPreferences = DatabaseUtils.getSharedPreferences(mContext);
sharedPreferences
.edit()
.putInt(DatabaseUtils.KEY_LAST_USAGE_SOURCE, USAGE_SOURCE_TASK_ROOT_ACTIVITY)
.apply();
assertThat(DatabaseUtils.getUsageSource(mContext))
.isEqualTo(USAGE_SOURCE_TASK_ROOT_ACTIVITY);
}
@Test
public void getUsageSource_notHasData_writeLoadedData() throws RemoteException {
when(mUsageStatsManager.getUsageSource()).thenReturn(USAGE_SOURCE_TASK_ROOT_ACTIVITY);
assertThat(DatabaseUtils.getUsageSource(mContext))
.isEqualTo(USAGE_SOURCE_TASK_ROOT_ACTIVITY);
assertThat(
DatabaseUtils
.getSharedPreferences(mContext)
.getInt(DatabaseUtils.KEY_LAST_USAGE_SOURCE, USAGE_SOURCE_CURRENT_ACTIVITY))
.isEqualTo(USAGE_SOURCE_TASK_ROOT_ACTIVITY);
}
@Test
public void getUsageSource_throwException_writeDefaultData() throws RemoteException {
when(mUsageStatsManager.getUsageSource()).thenThrow(new RemoteException());
assertThat(DatabaseUtils.getUsageSource(mContext))
.isEqualTo(USAGE_SOURCE_CURRENT_ACTIVITY);
assertThat(
DatabaseUtils
.getSharedPreferences(mContext)
.getInt(DatabaseUtils.KEY_LAST_USAGE_SOURCE, USAGE_SOURCE_CURRENT_ACTIVITY))
.isEqualTo(USAGE_SOURCE_CURRENT_ACTIVITY);
}
@Test @Test
public void recordDateTime_writeDataIntoSharedPreferences() { public void recordDateTime_writeDataIntoSharedPreferences() {
final String preferenceKey = "test_preference_key"; final String preferenceKey = "test_preference_key";