diff --git a/Android.bp b/Android.bp index 06ce8ab22f5..b96d0dc2928 100644 --- a/Android.bp +++ b/Android.bp @@ -95,15 +95,11 @@ android_library { "SettingsLibActivityEmbedding", "aconfig_settings_flags_lib", "accessibility_settings_flags_lib", - "app-usage-event-protos-lite", - "battery-event-protos-lite", - "battery-usage-slot-protos-lite", "contextualcards", "development_settings_flag_lib", "factory_reset_flags_lib", "fuelgauge-log-protos-lite", - "fuelgauge-usage-state-protos-lite", - "power-anomaly-event-protos-lite", + "fuelgauge-protos-lite", "settings-contextual-card-protos-lite", "settings-log-bridge-protos-lite", "settings-logtags", diff --git a/protos/fuelgauge_log.proto b/protos/fuelgauge_log.proto index b16958d8e2b..3be173e87ca 100644 --- a/protos/fuelgauge_log.proto +++ b/protos/fuelgauge_log.proto @@ -21,6 +21,7 @@ message BatteryOptimizeHistoricalLogEntry { BACKUP = 5; FORCE_RESET = 6; EXTERNAL_UPDATE = 7; + EXPIRATION_RESET = 8; } optional string package_name = 1; diff --git a/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java b/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java index 42e6d9c4b68..005c0730343 100644 --- a/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java +++ b/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java @@ -43,6 +43,7 @@ import com.android.settings.core.InstrumentedPreferenceFragment; import com.android.settings.core.SubSettingLauncher; import com.android.settings.dashboard.DashboardFragment; import com.android.settings.fuelgauge.BatteryOptimizeHistoricalLogEntry.Action; +import com.android.settings.fuelgauge.batteryusage.AppOptModeSharedPreferencesUtils; import com.android.settings.fuelgauge.batteryusage.BatteryDiffEntry; import com.android.settings.fuelgauge.batteryusage.BatteryEntry; import com.android.settings.overlay.FeatureFactory; @@ -274,9 +275,12 @@ public class AdvancedPowerUsageDetail extends DashboardFragment final int currentOptimizeMode = mBatteryOptimizeUtils.getAppOptimizationMode(); mLogStringBuilder.append(", onPause mode = ").append(currentOptimizeMode); logMetricCategory(currentOptimizeMode); - mExecutor.execute( () -> { + if (currentOptimizeMode != mOptimizationMode) { + AppOptModeSharedPreferencesUtils.deleteAppOptimizationModeEventByUid( + getContext(), mBatteryOptimizeUtils.getUid()); + } BatteryOptimizeLogUtils.writeLog( getContext().getApplicationContext(), Action.LEAVE, diff --git a/src/com/android/settings/fuelgauge/BatteryOptimizeUtils.java b/src/com/android/settings/fuelgauge/BatteryOptimizeUtils.java index 9c7f00701d5..3e376184ac2 100644 --- a/src/com/android/settings/fuelgauge/BatteryOptimizeUtils.java +++ b/src/com/android/settings/fuelgauge/BatteryOptimizeUtils.java @@ -182,6 +182,14 @@ public class BatteryOptimizeUtils { && getAppOptimizationMode() != BatteryOptimizeUtils.MODE_RESTRICTED; } + String getPackageName() { + return mPackageName == null ? UNKNOWN_PACKAGE : mPackageName; + } + + int getUid() { + return mUid; + } + /** Gets the list of installed applications. */ public static ArraySet getInstalledApplications( Context context, IPackageManager ipm) { @@ -257,10 +265,6 @@ public class BatteryOptimizeUtils { } } - String getPackageName() { - return mPackageName == null ? UNKNOWN_PACKAGE : mPackageName; - } - static int getMode(AppOpsManager appOpsManager, int uid, String packageName) { return appOpsManager.checkOpNoThrow( AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, uid, packageName); diff --git a/src/com/android/settings/fuelgauge/PowerBackgroundUsageDetail.java b/src/com/android/settings/fuelgauge/PowerBackgroundUsageDetail.java index b662d3ef908..2d2c838bc36 100644 --- a/src/com/android/settings/fuelgauge/PowerBackgroundUsageDetail.java +++ b/src/com/android/settings/fuelgauge/PowerBackgroundUsageDetail.java @@ -35,6 +35,7 @@ import androidx.annotation.VisibleForTesting; import com.android.settings.R; import com.android.settings.core.SubSettingLauncher; import com.android.settings.dashboard.DashboardFragment; +import com.android.settings.fuelgauge.batteryusage.AppOptModeSharedPreferencesUtils; import com.android.settings.overlay.FeatureFactory; import com.android.settings.widget.EntityHeaderController; import com.android.settingslib.HelpUtils; @@ -121,6 +122,10 @@ public class PowerBackgroundUsageDetail extends DashboardFragment mExecutor.execute( () -> { + if (currentOptimizeMode != mOptimizationMode) { + AppOptModeSharedPreferencesUtils.deleteAppOptimizationModeEventByUid( + getContext(), mBatteryOptimizeUtils.getUid()); + } BatteryOptimizeLogUtils.writeLog( getContext().getApplicationContext(), Action.LEAVE, diff --git a/src/com/android/settings/fuelgauge/batteryusage/AppOptModeSharedPreferencesUtils.kt b/src/com/android/settings/fuelgauge/batteryusage/AppOptModeSharedPreferencesUtils.kt new file mode 100644 index 00000000000..60db0310040 --- /dev/null +++ b/src/com/android/settings/fuelgauge/batteryusage/AppOptModeSharedPreferencesUtils.kt @@ -0,0 +1,223 @@ +/* + * Copyright (C) 2024 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 android.content.Context +import android.content.SharedPreferences +import android.util.ArrayMap +import android.util.Base64 +import android.util.Log +import androidx.annotation.VisibleForTesting +import com.android.settings.fuelgauge.BatteryOptimizeHistoricalLogEntry.Action +import com.android.settings.fuelgauge.BatteryOptimizeUtils +import com.android.settings.fuelgauge.BatteryUtils + +/** A util to store and update app optimization mode expiration event data. */ +object AppOptModeSharedPreferencesUtils { + private const val TAG: String = "AppOptModeSharedPreferencesUtils" + private const val SHARED_PREFS_FILE: String = "app_optimization_mode_shared_prefs" + + @VisibleForTesting const val UNLIMITED_EXPIRE_TIME: Long = -1L + + private val appOptimizationModeLock = Any() + private val defaultInstance = AppOptimizationModeEvent.getDefaultInstance() + + /** Returns all app optimization mode events for log. */ + @JvmStatic + fun getAllEvents(context: Context): List = + synchronized(appOptimizationModeLock) { getAppOptModeEventsMap(context).values.toList() } + + /** Updates the app optimization mode event data. */ + @JvmStatic + fun updateAppOptModeExpiration( + context: Context, + uids: List, + packageNames: List, + optimizationModes: List, + expirationTimes: LongArray, + ) = + // The internal fun with an additional lambda parameter is used to + // 1) get true BatteryOptimizeUtils in production environment + // 2) get fake BatteryOptimizeUtils for testing environment + updateAppOptModeExpirationInternal( + context, + uids, + packageNames, + optimizationModes, + expirationTimes + ) { uid: Int, packageName: String -> + BatteryOptimizeUtils(context, uid, packageName) + } + + /** Resets the app optimization mode event data since the query timestamp. */ + @JvmStatic + fun resetExpiredAppOptModeBeforeTimestamp(context: Context, queryTimestamp: Long) = + synchronized(appOptimizationModeLock) { + val eventsMap = getAppOptModeEventsMap(context) + val expirationUids = ArrayList(eventsMap.size) + for ((uid, event) in eventsMap) { + if (event.expirationTime > queryTimestamp) { + continue + } + updateBatteryOptimizationMode( + context, + event.uid, + event.packageName, + event.resetOptimizationMode, + Action.EXPIRATION_RESET, + ) + expirationUids.add(uid) + } + // Remove the expired AppOptimizationModeEvent data from storage + clearSharedPreferences(context, expirationUids) + } + + /** Deletes all app optimization mode event data with a specific uid. */ + @JvmStatic + fun deleteAppOptimizationModeEventByUid(context: Context, uid: Int) = + synchronized(appOptimizationModeLock) { clearSharedPreferences(context, listOf(uid)) } + + @VisibleForTesting + fun updateAppOptModeExpirationInternal( + context: Context, + uids: List, + packageNames: List, + optimizationModes: List, + expirationTimes: LongArray, + getBatteryOptimizeUtils: (Int, String) -> BatteryOptimizeUtils + ) = + synchronized(appOptimizationModeLock) { + val eventsMap = getAppOptModeEventsMap(context) + val expirationEvents: MutableMap = ArrayMap() + for (i in uids.indices) { + val uid = uids[i] + val packageName = packageNames[i] + val optimizationMode = optimizationModes[i] + val originalOptMode: Int = + updateBatteryOptimizationMode( + context, + uid, + packageName, + optimizationMode, + Action.EXTERNAL_UPDATE, + getBatteryOptimizeUtils(uid, packageName) + ) + if (originalOptMode == BatteryOptimizeUtils.MODE_UNKNOWN) { + continue + } + // Make sure the reset mode is consistent with the expiration event in storage. + val resetOptMode = eventsMap[uid]?.resetOptimizationMode ?: originalOptMode + val expireTimeMs: Long = expirationTimes[i] + if (expireTimeMs != UNLIMITED_EXPIRE_TIME) { + Log.d( + TAG, + "setOptimizationMode($packageName) from $originalOptMode " + + "to $optimizationMode with expiration time $expireTimeMs", + ) + expirationEvents[uid] = + AppOptimizationModeEvent.newBuilder() + .setUid(uid) + .setPackageName(packageName) + .setResetOptimizationMode(resetOptMode) + .setExpirationTime(expireTimeMs) + .build() + } + } + + // Append and update the AppOptimizationModeEvent. + if (expirationEvents.isNotEmpty()) { + updateSharedPreferences(context, expirationEvents) + } + } + + @VisibleForTesting + fun updateBatteryOptimizationMode( + context: Context, + uid: Int, + packageName: String, + optimizationMode: Int, + action: Action, + batteryOptimizeUtils: BatteryOptimizeUtils = BatteryOptimizeUtils(context, uid, packageName) + ): Int { + if (!batteryOptimizeUtils.isOptimizeModeMutable) { + Log.w(TAG, "Fail to update immutable optimization mode for: $packageName") + return BatteryOptimizeUtils.MODE_UNKNOWN + } + val currentOptMode = batteryOptimizeUtils.appOptimizationMode + batteryOptimizeUtils.setAppUsageState(optimizationMode, action) + Log.d( + TAG, + "setAppUsageState($packageName) to $optimizationMode with action = ${action.name}", + ) + return currentOptMode + } + + private fun getSharedPreferences(context: Context): SharedPreferences { + return context.applicationContext.getSharedPreferences( + SHARED_PREFS_FILE, + Context.MODE_PRIVATE, + ) + } + + private fun getAppOptModeEventsMap(context: Context): ArrayMap { + val sharedPreferences = getSharedPreferences(context) + val allKeys = sharedPreferences.all?.keys ?: emptySet() + if (allKeys.isEmpty()) { + return ArrayMap() + } + val eventsMap = ArrayMap(allKeys.size) + for (key in allKeys) { + sharedPreferences.getString(key, null)?.let { + eventsMap[key.toInt()] = deserializeAppOptimizationModeEvent(it) + } + } + return eventsMap + } + + private fun updateSharedPreferences( + context: Context, + eventsMap: Map + ) { + val sharedPreferences = getSharedPreferences(context) + sharedPreferences.edit().run { + for ((uid, event) in eventsMap) { + putString(uid.toString(), serializeAppOptimizationModeEvent(event)) + } + apply() + } + } + + private fun clearSharedPreferences(context: Context, uids: List) { + val sharedPreferences = getSharedPreferences(context) + sharedPreferences.edit().run { + for (uid in uids) { + remove(uid.toString()) + } + apply() + } + } + + private fun serializeAppOptimizationModeEvent(event: AppOptimizationModeEvent): String { + return Base64.encodeToString(event.toByteArray(), Base64.DEFAULT) + } + + private fun deserializeAppOptimizationModeEvent( + encodedProtoString: String + ): AppOptimizationModeEvent { + return BatteryUtils.parseProtoFromString(encodedProtoString, defaultInstance) + } +} diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoader.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoader.java index 26bb6dd0a01..08369127b6d 100644 --- a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoader.java +++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoader.java @@ -167,6 +167,8 @@ public final class BatteryUsageDataLoader { try { final long start = System.currentTimeMillis(); loadBatteryStatsData(context, isFullChargeStart); + AppOptModeSharedPreferencesUtils.resetExpiredAppOptModeBeforeTimestamp( + context, System.currentTimeMillis()); if (!isFullChargeStart) { // No app usage data or battery diff data at this time. final UserIdsSeries userIdsSeries = diff --git a/src/com/android/settings/fuelgauge/protos/Android.bp b/src/com/android/settings/fuelgauge/protos/Android.bp index 462962b63c5..40fb987e62c 100644 --- a/src/com/android/settings/fuelgauge/protos/Android.bp +++ b/src/com/android/settings/fuelgauge/protos/Android.bp @@ -9,41 +9,9 @@ package { } java_library { - name: "app-usage-event-protos-lite", + name: "fuelgauge-protos-lite", proto: { type: "lite", }, - srcs: ["app_usage_event.proto"], -} - -java_library { - name: "battery-event-protos-lite", - proto: { - type: "lite", - }, - srcs: ["battery_event.proto"], -} - -java_library { - name: "battery-usage-slot-protos-lite", - proto: { - type: "lite", - }, - srcs: ["battery_usage_slot.proto"], -} - -java_library { - name: "fuelgauge-usage-state-protos-lite", - proto: { - type: "lite", - }, - srcs: ["fuelgauge_usage_state.proto"], -} - -java_library { - name: "power-anomaly-event-protos-lite", - proto: { - type: "lite", - }, - srcs: ["power_anomaly_event.proto"], + srcs: ["*.proto"], } diff --git a/src/com/android/settings/fuelgauge/protos/app_optimization_mode_event.proto b/src/com/android/settings/fuelgauge/protos/app_optimization_mode_event.proto new file mode 100644 index 00000000000..81d51bc0d6b --- /dev/null +++ b/src/com/android/settings/fuelgauge/protos/app_optimization_mode_event.proto @@ -0,0 +1,18 @@ +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "com.android.settings.fuelgauge.batteryusage"; +option java_outer_classname = "AppOptimizationModeEventProto"; + +message AppOptimizationModeEvents { + // Map of uid to AppOptimizationModeEvent + map events = 1; +} + +message AppOptimizationModeEvent { + optional int32 uid = 1; + optional string package_name = 2; + // Value of BatteryUsageSlot.BatteryOptimizationMode, range = [0,3] + optional int32 reset_optimization_mode = 3; + optional int64 expiration_time = 4; +} diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/AppOptModeSharedPreferencesUtilsTest.kt b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/AppOptModeSharedPreferencesUtilsTest.kt new file mode 100644 index 00000000000..02d3739a9c1 --- /dev/null +++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/AppOptModeSharedPreferencesUtilsTest.kt @@ -0,0 +1,212 @@ +/* + * Copyright (C) 2024 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 android.content.Context +import androidx.test.core.app.ApplicationProvider +import com.android.settings.fuelgauge.BatteryOptimizeHistoricalLogEntry.Action +import com.android.settings.fuelgauge.BatteryOptimizeUtils +import com.android.settings.fuelgauge.BatteryOptimizeUtils.MODE_OPTIMIZED +import com.android.settings.fuelgauge.BatteryOptimizeUtils.MODE_RESTRICTED +import com.android.settings.fuelgauge.BatteryOptimizeUtils.MODE_UNKNOWN +import com.android.settings.fuelgauge.BatteryOptimizeUtils.MODE_UNRESTRICTED +import com.android.settings.fuelgauge.batteryusage.AppOptModeSharedPreferencesUtils.UNLIMITED_EXPIRE_TIME +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentMatchers.any +import org.mockito.Mockito.anyInt +import org.mockito.Mockito.never +import org.mockito.Mockito.spy +import org.mockito.Mockito.verify +import org.mockito.Mockito.`when` as whenever +import org.mockito.Spy +import org.mockito.junit.MockitoJUnit +import org.mockito.junit.MockitoRule +import org.robolectric.RobolectricTestRunner + +@RunWith(RobolectricTestRunner::class) +class AppOptModeSharedPreferencesUtilsTest { + @JvmField @Rule val mockitoRule: MockitoRule = MockitoJUnit.rule() + + @Spy private var context: Context = ApplicationProvider.getApplicationContext() + + @Spy + private var testBatteryOptimizeUtils = spy(BatteryOptimizeUtils(context, UID, PACKAGE_NAME)) + + @Before + fun setup() { + AppOptModeSharedPreferencesUtils.deleteAppOptimizationModeEventByUid(context, UID) + } + + @Test + fun getAllEvents_emptyData_verifyEmptyList() { + assertThat(AppOptModeSharedPreferencesUtils.getAllEvents(context)).isEmpty() + } + + @Test + fun updateAppOptModeExpirationInternal_withExpirationTime_verifyData() { + insertAppOptModeEventForTest(/* expirationTime= */ 1000L) + + val events = AppOptModeSharedPreferencesUtils.getAllEvents(context) + + assertThat(events.size).isEqualTo(1) + assertAppOptimizationModeEventInfo(events.get(0), UID, PACKAGE_NAME, MODE_OPTIMIZED, 1000L) + } + + @Test + fun updateAppOptModeExpirationInternal_withoutExpirationTime_verifyEmptyList() { + insertAppOptModeEventForTest(/* expirationTime= */ UNLIMITED_EXPIRE_TIME) + + assertThat(AppOptModeSharedPreferencesUtils.getAllEvents(context)).isEmpty() + } + + @Test + fun deleteAppOptimizationModeEventByUid_uidNotContained_verifyData() { + insertAppOptModeEventForTest(/* expirationTime= */ 1000L) + assertThat(AppOptModeSharedPreferencesUtils.getAllEvents(context).size).isEqualTo(1) + + AppOptModeSharedPreferencesUtils.deleteAppOptimizationModeEventByUid(context, UNSET_UID) + val events = AppOptModeSharedPreferencesUtils.getAllEvents(context) + + assertThat(events.size).isEqualTo(1) + assertAppOptimizationModeEventInfo(events.get(0), UID, PACKAGE_NAME, MODE_OPTIMIZED, 1000L) + } + + @Test + fun deleteAppOptimizationModeEventByUid_uidExisting_verifyData() { + insertAppOptModeEventForTest(/* expirationTime= */ 1000L) + + AppOptModeSharedPreferencesUtils.deleteAppOptimizationModeEventByUid(context, UID) + + assertThat(AppOptModeSharedPreferencesUtils.getAllEvents(context)).isEmpty() + } + + @Test + fun resetExpiredAppOptModeBeforeTimestamp_noExpiredData_verifyData() { + insertAppOptModeEventForTest(/* expirationTime= */ 1000L) + + AppOptModeSharedPreferencesUtils.resetExpiredAppOptModeBeforeTimestamp(context, 999L) + val events = AppOptModeSharedPreferencesUtils.getAllEvents(context) + + assertThat(events.size).isEqualTo(1) + assertAppOptimizationModeEventInfo(events.get(0), UID, PACKAGE_NAME, MODE_OPTIMIZED, 1000L) + } + + @Test + fun resetExpiredAppOptModeBeforeTimestamp_hasExpiredData_verifyEmptyList() { + insertAppOptModeEventForTest(/* expirationTime= */ 1000L) + + AppOptModeSharedPreferencesUtils.resetExpiredAppOptModeBeforeTimestamp(context, 1001L) + + assertThat(AppOptModeSharedPreferencesUtils.getAllEvents(context)).isEmpty() + } + + @Test + fun updateBatteryOptimizationMode_updateToOptimizedMode_verifyAction() { + whenever(testBatteryOptimizeUtils?.isOptimizeModeMutable).thenReturn(true) + whenever(testBatteryOptimizeUtils?.getAppOptimizationMode(true)) + .thenReturn(MODE_UNRESTRICTED) + + val currentOptMode = + AppOptModeSharedPreferencesUtils.updateBatteryOptimizationMode( + context, + UID, + PACKAGE_NAME, + MODE_OPTIMIZED, + Action.EXTERNAL_UPDATE, + testBatteryOptimizeUtils + ) + + verify(testBatteryOptimizeUtils)?.setAppUsageState(MODE_OPTIMIZED, Action.EXTERNAL_UPDATE) + assertThat(currentOptMode).isEqualTo(MODE_UNRESTRICTED) + } + + @Test + fun updateBatteryOptimizationMode_optimizationModeNotChanged_verifyAction() { + whenever(testBatteryOptimizeUtils?.isOptimizeModeMutable).thenReturn(false) + whenever(testBatteryOptimizeUtils?.getAppOptimizationMode(true)) + .thenReturn(MODE_UNRESTRICTED) + + val currentOptMode = + AppOptModeSharedPreferencesUtils.updateBatteryOptimizationMode( + context, + UID, + PACKAGE_NAME, + MODE_OPTIMIZED, + Action.EXTERNAL_UPDATE, + testBatteryOptimizeUtils + ) + + verify(testBatteryOptimizeUtils, never())?.setAppUsageState(anyInt(), any()) + assertThat(currentOptMode).isEqualTo(MODE_UNKNOWN) + } + + @Test + fun updateBatteryOptimizationMode_updateToSameOptimizationMode_verifyAction() { + whenever(testBatteryOptimizeUtils?.isOptimizeModeMutable).thenReturn(true) + whenever(testBatteryOptimizeUtils?.getAppOptimizationMode(true)).thenReturn(MODE_RESTRICTED) + + val currentOptMode = + AppOptModeSharedPreferencesUtils.updateBatteryOptimizationMode( + context, + UID, + PACKAGE_NAME, + MODE_RESTRICTED, + Action.EXTERNAL_UPDATE, + testBatteryOptimizeUtils + ) + + verify(testBatteryOptimizeUtils)?.setAppUsageState(MODE_RESTRICTED, Action.EXTERNAL_UPDATE) + assertThat(currentOptMode).isEqualTo(MODE_RESTRICTED) + } + + private fun insertAppOptModeEventForTest(expirationTime: Long) { + whenever(testBatteryOptimizeUtils?.isOptimizeModeMutable).thenReturn(true) + whenever(testBatteryOptimizeUtils?.getAppOptimizationMode(true)).thenReturn(MODE_OPTIMIZED) + AppOptModeSharedPreferencesUtils.updateAppOptModeExpirationInternal( + context, + mutableListOf(UID), + mutableListOf(PACKAGE_NAME), + mutableListOf(MODE_OPTIMIZED), + longArrayOf(expirationTime) + ) { _: Int, _: String -> + testBatteryOptimizeUtils + } + } + + companion object { + const val UID: Int = 12345 + const val UNSET_UID: Int = 15432 + const val PACKAGE_NAME: String = "com.android.app" + + private fun assertAppOptimizationModeEventInfo( + event: AppOptimizationModeEvent, + uid: Int, + packageName: String, + resetOptimizationMode: Int, + expirationTime: Long + ) { + assertThat(event.uid).isEqualTo(uid) + assertThat(event.packageName).isEqualTo(packageName) + assertThat(event.resetOptimizationMode).isEqualTo(resetOptimizationMode) + assertThat(event.expirationTime).isEqualTo(expirationTime) + } + } +}