/* * Copyright (C) 2017 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.testutils; import static org.mockito.Mockito.when; import android.app.settings.SettingsEnums; import android.content.Context; import android.content.Intent; import android.hardware.usb.UsbManager; import android.hardware.usb.UsbPort; import android.hardware.usb.UsbPortStatus; import android.os.BatteryManager; import android.os.UserManager; import android.provider.Settings; import androidx.room.Room; import com.android.settings.DisplaySettings; import com.android.settings.display.ScreenTimeoutSettings; import com.android.settings.fuelgauge.batteryusage.BatteryInformation; import com.android.settings.fuelgauge.batteryusage.ConvertUtils; import com.android.settings.fuelgauge.batteryusage.DeviceBatteryState; import com.android.settings.fuelgauge.batteryusage.PowerAnomalyEvent; import com.android.settings.fuelgauge.batteryusage.PowerAnomalyEventList; import com.android.settings.fuelgauge.batteryusage.PowerAnomalyKey; import com.android.settings.fuelgauge.batteryusage.PowerAnomalyType; import com.android.settings.fuelgauge.batteryusage.WarningBannerInfo; import com.android.settings.fuelgauge.batteryusage.WarningItemInfo; import com.android.settings.fuelgauge.batteryusage.db.AppUsageEventDao; import com.android.settings.fuelgauge.batteryusage.db.AppUsageEventEntity; import com.android.settings.fuelgauge.batteryusage.db.BatteryState; import com.android.settings.fuelgauge.batteryusage.db.BatteryStateDao; import com.android.settings.fuelgauge.batteryusage.db.BatteryStateDatabase; import com.google.common.collect.ImmutableList; import org.robolectric.Shadows; import java.util.ArrayList; import java.util.List; public class BatteryTestUtils { public static Intent getChargingIntent() { return getCustomBatteryIntent( BatteryManager.BATTERY_PLUGGED_AC, 50 /* level */, 100 /* scale */, BatteryManager.BATTERY_STATUS_CHARGING); } public static Intent getDischargingIntent() { return getCustomBatteryIntent( 0 /* plugged */, 10 /* level */, 100 /* scale */, BatteryManager.BATTERY_STATUS_DISCHARGING); } /** Sets the work profile mode. */ public static void setWorkProfile(Context context) { final UserManager userManager = context.getSystemService(UserManager.class); Shadows.shadowOf(userManager).setManagedProfile(true); Shadows.shadowOf(userManager).setIsSystemUser(false); } /** Creates and sets up the in-memory {@link BatteryStateDatabase}. */ public static BatteryStateDatabase setUpBatteryStateDatabase(Context context) { final BatteryStateDatabase inMemoryDatabase = Room.inMemoryDatabaseBuilder(context, BatteryStateDatabase.class) .allowMainThreadQueries() .build(); BatteryStateDatabase.setBatteryStateDatabase(inMemoryDatabase); return inMemoryDatabase; } /** Inserts a fake data into the database for testing. */ public static void insertDataToBatteryStateTable( Context context, long timestamp, String packageName) { insertDataToBatteryStateTable( context, timestamp, packageName, /* multiple= */ false, /* isFullChargeStart= */ false); } /** Inserts a fake data into the database for testing. */ public static void insertDataToBatteryStateTable( Context context, long timestamp, String packageName, boolean isFullChargeStart) { insertDataToBatteryStateTable( context, timestamp, packageName, /* multiple= */ false, isFullChargeStart); } /** Inserts a fake data into the database for testing. */ public static void insertDataToBatteryStateTable( Context context, long timestamp, String packageName, boolean multiple, boolean isFullChargeStart) { DeviceBatteryState deviceBatteryState = DeviceBatteryState.newBuilder() .setBatteryLevel(31) .setBatteryStatus(0) .setBatteryHealth(0) .build(); BatteryInformation batteryInformation = BatteryInformation.newBuilder() .setDeviceBatteryState(deviceBatteryState) .setIsHidden(true) .setBootTimestamp(timestamp - 1) .setZoneId("Europe/Paris") .setAppLabel("Settings") .setTotalPower(100f) .setConsumePower(0.3f) .setPercentOfTotal(10f) .setDrainType(1) .setForegroundUsageTimeInMs(60000) .setBackgroundUsageTimeInMs(10000) .setForegroundUsageConsumePower(0.1f) .setForegroundServiceUsageConsumePower(0.05f) .setBackgroundUsageConsumePower(0.1f) .setCachedUsageConsumePower(0.05f) .build(); final BatteryState state = new BatteryState( /* uid= */ 1001L, /* userId= */ 100L, packageName, timestamp, /* consumerType= */ 2, isFullChargeStart, ConvertUtils.convertBatteryInformationToString(batteryInformation), ""); BatteryStateDao dao = BatteryStateDatabase.getInstance(context).batteryStateDao(); if (multiple) { dao.insertAll(ImmutableList.of(state)); } else { dao.insert(state); } } /** Inserts a fake data into the database for testing. */ public static void insertDataToAppUsageEventTable( Context context, long userId, long timestamp, String packageName) { insertDataToAppUsageEventTable( context, userId, timestamp, packageName, /* multiple= */ false); } /** Inserts a fake data into the database for testing. */ public static void insertDataToAppUsageEventTable( Context context, long userId, long timestamp, String packageName, boolean multiple) { final AppUsageEventEntity entity = new AppUsageEventEntity( /* uid= */ 101L, userId, timestamp, /* appUsageEventType= */ 2, packageName, /* instanceId= */ 10001, /* taskRootPackageName= */ "com.android.settings"); AppUsageEventDao dao = BatteryStateDatabase.getInstance(context).appUsageEventDao(); if (multiple) { dao.insertAll(ImmutableList.of(entity)); } else { dao.insert(entity); } } /** Gets customized battery changed intent. */ public static Intent getCustomBatteryIntent(int plugged, int level, int scale, int status) { Intent intent = new Intent(); intent.putExtra(BatteryManager.EXTRA_PLUGGED, plugged); intent.putExtra(BatteryManager.EXTRA_LEVEL, level); intent.putExtra(BatteryManager.EXTRA_SCALE, scale); intent.putExtra(BatteryManager.EXTRA_STATUS, status); return intent; } /** Configures the incompatible charger environment. */ public static void setupIncompatibleEvent( UsbPort mockUsbPort, UsbManager mockUsbManager, UsbPortStatus mockUsbPortStatus) { final List usbPorts = new ArrayList<>(); usbPorts.add(mockUsbPort); when(mockUsbManager.getPorts()).thenReturn(usbPorts); when(mockUsbPort.getStatus()).thenReturn(mockUsbPortStatus); when(mockUsbPort.supportsComplianceWarnings()).thenReturn(true); when(mockUsbPortStatus.isConnected()).thenReturn(true); when(mockUsbPortStatus.getComplianceWarnings()) .thenReturn(new int[] {UsbPortStatus.COMPLIANCE_WARNING_DEBUG_ACCESSORY}); } /** Create an empty power anomaly event list proto. */ public static PowerAnomalyEventList createEmptyPowerAnomalyEventList() { return PowerAnomalyEventList.getDefaultInstance(); } /** Create an non-empty power anomaly event list proto. */ public static PowerAnomalyEventList createNonEmptyPowerAnomalyEventList() { return PowerAnomalyEventList.newBuilder() .addPowerAnomalyEvents(0, createAdaptiveBrightnessAnomalyEvent()) .addPowerAnomalyEvents(1, createScreenTimeoutAnomalyEvent()) .build(); } /** Create a power anomaly event proto of adaptive brightness. */ public static PowerAnomalyEvent createAdaptiveBrightnessAnomalyEvent() { return createAdaptiveBrightnessAnomalyEvent(false); } /** Create a power anomaly event proto of adaptive brightness. */ public static PowerAnomalyEvent createAdaptiveBrightnessAnomalyEvent(boolean changeSettings) { // TODO: migrate "auto_brightness_entry" to use R.string.preference_key_auto_brightness // if we can access the Context here. (b/338314718) WarningBannerInfo.Builder warningBannerInfoBuilder = WarningBannerInfo.newBuilder() .setMainButtonDestination(DisplaySettings.class.getName()) .setMainButtonSourceMetricsCategory(SettingsEnums.DISPLAY) .setMainButtonSourceHighlightKey("auto_brightness_entry"); if (changeSettings) { warningBannerInfoBuilder .setMainButtonConfigSettingsName(Settings.System.SCREEN_BRIGHTNESS_MODE) .setMainButtonConfigSettingsValue( Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); } return PowerAnomalyEvent.newBuilder() .setEventId("BrightnessAnomaly") .setType(PowerAnomalyType.TYPE_SETTINGS_BANNER) .setKey(PowerAnomalyKey.KEY_BRIGHTNESS) .setDismissRecordKey(PowerAnomalyKey.KEY_BRIGHTNESS.name()) .setScore(1.2f) .setWarningBannerInfo(warningBannerInfoBuilder.build()) .build(); } /** Create a power anomaly event proto of screen timeout. */ public static PowerAnomalyEvent createScreenTimeoutAnomalyEvent() { return PowerAnomalyEvent.newBuilder() .setEventId("ScreenTimeoutAnomaly") .setType(PowerAnomalyType.TYPE_SETTINGS_BANNER) .setKey(PowerAnomalyKey.KEY_SCREEN_TIMEOUT) .setDismissRecordKey(PowerAnomalyKey.KEY_SCREEN_TIMEOUT.name()) .setScore(1.1f) .setWarningBannerInfo( WarningBannerInfo.newBuilder() .setMainButtonDestination(ScreenTimeoutSettings.class.getName()) .setMainButtonSourceMetricsCategory(SettingsEnums.SCREEN_TIMEOUT) .setMainButtonSourceHighlightKey("60000") .build()) .build(); } /** Create a power anomaly event proto of app anomaly. */ public static PowerAnomalyEvent createAppAnomalyEvent() { return PowerAnomalyEvent.newBuilder() .setEventId("AppAnomaly") .setType(PowerAnomalyType.TYPE_APPS_ITEM) .setKey(PowerAnomalyKey.KEY_APP_TOTAL_HIGHER_THAN_USUAL) .setDismissRecordKey("KEY_APP_1") .setScore(2.0f) .setWarningItemInfo( WarningItemInfo.newBuilder() .setStartTimestamp(1694361600000L) // 2023-09-11 00:00:00 .setEndTimestamp(1694368800000L) // 2023-09-11 02:00:00 .build()) .build(); } }