1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settings.testutils; 18 19 import static org.mockito.Mockito.when; 20 21 import android.app.settings.SettingsEnums; 22 import android.content.Context; 23 import android.content.Intent; 24 import android.hardware.usb.UsbManager; 25 import android.hardware.usb.UsbPort; 26 import android.hardware.usb.UsbPortStatus; 27 import android.os.BatteryManager; 28 import android.os.UserManager; 29 import android.provider.Settings; 30 31 import androidx.room.Room; 32 33 import com.android.settings.DisplaySettings; 34 import com.android.settings.display.ScreenTimeoutSettings; 35 import com.android.settings.fuelgauge.batteryusage.BatteryInformation; 36 import com.android.settings.fuelgauge.batteryusage.ConvertUtils; 37 import com.android.settings.fuelgauge.batteryusage.DeviceBatteryState; 38 import com.android.settings.fuelgauge.batteryusage.PowerAnomalyEvent; 39 import com.android.settings.fuelgauge.batteryusage.PowerAnomalyEventList; 40 import com.android.settings.fuelgauge.batteryusage.PowerAnomalyKey; 41 import com.android.settings.fuelgauge.batteryusage.PowerAnomalyType; 42 import com.android.settings.fuelgauge.batteryusage.WarningBannerInfo; 43 import com.android.settings.fuelgauge.batteryusage.WarningItemInfo; 44 import com.android.settings.fuelgauge.batteryusage.db.AppUsageEventDao; 45 import com.android.settings.fuelgauge.batteryusage.db.AppUsageEventEntity; 46 import com.android.settings.fuelgauge.batteryusage.db.BatteryState; 47 import com.android.settings.fuelgauge.batteryusage.db.BatteryStateDao; 48 import com.android.settings.fuelgauge.batteryusage.db.BatteryStateDatabase; 49 50 import com.google.common.collect.ImmutableList; 51 52 import org.robolectric.Shadows; 53 54 import java.util.ArrayList; 55 import java.util.List; 56 57 public class BatteryTestUtils { 58 getChargingIntent()59 public static Intent getChargingIntent() { 60 return getCustomBatteryIntent( 61 BatteryManager.BATTERY_PLUGGED_AC, 62 50 /* level */, 63 100 /* scale */, 64 BatteryManager.BATTERY_STATUS_CHARGING); 65 } 66 getDischargingIntent()67 public static Intent getDischargingIntent() { 68 return getCustomBatteryIntent( 69 0 /* plugged */, 70 10 /* level */, 71 100 /* scale */, 72 BatteryManager.BATTERY_STATUS_DISCHARGING); 73 } 74 75 /** Sets the work profile mode. */ setWorkProfile(Context context)76 public static void setWorkProfile(Context context) { 77 final UserManager userManager = context.getSystemService(UserManager.class); 78 Shadows.shadowOf(userManager).setManagedProfile(true); 79 Shadows.shadowOf(userManager).setIsSystemUser(false); 80 } 81 82 /** Creates and sets up the in-memory {@link BatteryStateDatabase}. */ setUpBatteryStateDatabase(Context context)83 public static BatteryStateDatabase setUpBatteryStateDatabase(Context context) { 84 final BatteryStateDatabase inMemoryDatabase = 85 Room.inMemoryDatabaseBuilder(context, BatteryStateDatabase.class) 86 .allowMainThreadQueries() 87 .build(); 88 BatteryStateDatabase.setBatteryStateDatabase(inMemoryDatabase); 89 return inMemoryDatabase; 90 } 91 92 /** Inserts a fake data into the database for testing. */ insertDataToBatteryStateTable( Context context, long timestamp, String packageName)93 public static void insertDataToBatteryStateTable( 94 Context context, long timestamp, String packageName) { 95 insertDataToBatteryStateTable( 96 context, 97 timestamp, 98 packageName, 99 /* multiple= */ false, 100 /* isFullChargeStart= */ false); 101 } 102 103 /** Inserts a fake data into the database for testing. */ insertDataToBatteryStateTable( Context context, long timestamp, String packageName, boolean isFullChargeStart)104 public static void insertDataToBatteryStateTable( 105 Context context, long timestamp, String packageName, boolean isFullChargeStart) { 106 insertDataToBatteryStateTable( 107 context, timestamp, packageName, /* multiple= */ false, isFullChargeStart); 108 } 109 110 /** Inserts a fake data into the database for testing. */ insertDataToBatteryStateTable( Context context, long timestamp, String packageName, boolean multiple, boolean isFullChargeStart)111 public static void insertDataToBatteryStateTable( 112 Context context, 113 long timestamp, 114 String packageName, 115 boolean multiple, 116 boolean isFullChargeStart) { 117 DeviceBatteryState deviceBatteryState = 118 DeviceBatteryState.newBuilder() 119 .setBatteryLevel(31) 120 .setBatteryStatus(0) 121 .setBatteryHealth(0) 122 .build(); 123 BatteryInformation batteryInformation = 124 BatteryInformation.newBuilder() 125 .setDeviceBatteryState(deviceBatteryState) 126 .setIsHidden(true) 127 .setBootTimestamp(timestamp - 1) 128 .setZoneId("Europe/Paris") 129 .setAppLabel("Settings") 130 .setTotalPower(100f) 131 .setConsumePower(0.3f) 132 .setPercentOfTotal(10f) 133 .setDrainType(1) 134 .setForegroundUsageTimeInMs(60000) 135 .setBackgroundUsageTimeInMs(10000) 136 .setForegroundUsageConsumePower(0.1f) 137 .setForegroundServiceUsageConsumePower(0.05f) 138 .setBackgroundUsageConsumePower(0.1f) 139 .setCachedUsageConsumePower(0.05f) 140 .build(); 141 142 final BatteryState state = 143 new BatteryState( 144 /* uid= */ 1001L, 145 /* userId= */ 100L, 146 packageName, 147 timestamp, 148 /* consumerType= */ 2, 149 isFullChargeStart, 150 ConvertUtils.convertBatteryInformationToString(batteryInformation), 151 ""); 152 BatteryStateDao dao = BatteryStateDatabase.getInstance(context).batteryStateDao(); 153 if (multiple) { 154 dao.insertAll(ImmutableList.of(state)); 155 } else { 156 dao.insert(state); 157 } 158 } 159 160 /** Inserts a fake data into the database for testing. */ insertDataToAppUsageEventTable( Context context, long userId, long timestamp, String packageName)161 public static void insertDataToAppUsageEventTable( 162 Context context, long userId, long timestamp, String packageName) { 163 insertDataToAppUsageEventTable( 164 context, userId, timestamp, packageName, /* multiple= */ false); 165 } 166 167 /** Inserts a fake data into the database for testing. */ insertDataToAppUsageEventTable( Context context, long userId, long timestamp, String packageName, boolean multiple)168 public static void insertDataToAppUsageEventTable( 169 Context context, long userId, long timestamp, String packageName, boolean multiple) { 170 final AppUsageEventEntity entity = 171 new AppUsageEventEntity( 172 /* uid= */ 101L, 173 userId, 174 timestamp, 175 /* appUsageEventType= */ 2, 176 packageName, 177 /* instanceId= */ 10001, 178 /* taskRootPackageName= */ "com.android.settings"); 179 AppUsageEventDao dao = BatteryStateDatabase.getInstance(context).appUsageEventDao(); 180 if (multiple) { 181 dao.insertAll(ImmutableList.of(entity)); 182 } else { 183 dao.insert(entity); 184 } 185 } 186 187 /** Gets customized battery changed intent. */ getCustomBatteryIntent(int plugged, int level, int scale, int status)188 public static Intent getCustomBatteryIntent(int plugged, int level, int scale, int status) { 189 Intent intent = new Intent(); 190 intent.putExtra(BatteryManager.EXTRA_PLUGGED, plugged); 191 intent.putExtra(BatteryManager.EXTRA_LEVEL, level); 192 intent.putExtra(BatteryManager.EXTRA_SCALE, scale); 193 intent.putExtra(BatteryManager.EXTRA_STATUS, status); 194 195 return intent; 196 } 197 198 /** Configures the incompatible charger environment. */ setupIncompatibleEvent( UsbPort mockUsbPort, UsbManager mockUsbManager, UsbPortStatus mockUsbPortStatus)199 public static void setupIncompatibleEvent( 200 UsbPort mockUsbPort, UsbManager mockUsbManager, UsbPortStatus mockUsbPortStatus) { 201 final List<UsbPort> usbPorts = new ArrayList<>(); 202 usbPorts.add(mockUsbPort); 203 when(mockUsbManager.getPorts()).thenReturn(usbPorts); 204 when(mockUsbPort.getStatus()).thenReturn(mockUsbPortStatus); 205 when(mockUsbPort.supportsComplianceWarnings()).thenReturn(true); 206 when(mockUsbPortStatus.isConnected()).thenReturn(true); 207 when(mockUsbPortStatus.getComplianceWarnings()) 208 .thenReturn(new int[] {UsbPortStatus.COMPLIANCE_WARNING_DEBUG_ACCESSORY}); 209 } 210 211 /** Create an empty power anomaly event list proto. */ createEmptyPowerAnomalyEventList()212 public static PowerAnomalyEventList createEmptyPowerAnomalyEventList() { 213 return PowerAnomalyEventList.getDefaultInstance(); 214 } 215 216 /** Create an non-empty power anomaly event list proto. */ createNonEmptyPowerAnomalyEventList()217 public static PowerAnomalyEventList createNonEmptyPowerAnomalyEventList() { 218 return PowerAnomalyEventList.newBuilder() 219 .addPowerAnomalyEvents(0, createAdaptiveBrightnessAnomalyEvent()) 220 .addPowerAnomalyEvents(1, createScreenTimeoutAnomalyEvent()) 221 .build(); 222 } 223 224 /** Create a power anomaly event proto of adaptive brightness. */ createAdaptiveBrightnessAnomalyEvent()225 public static PowerAnomalyEvent createAdaptiveBrightnessAnomalyEvent() { 226 return createAdaptiveBrightnessAnomalyEvent(false); 227 } 228 229 /** Create a power anomaly event proto of adaptive brightness. */ createAdaptiveBrightnessAnomalyEvent(boolean changeSettings)230 public static PowerAnomalyEvent createAdaptiveBrightnessAnomalyEvent(boolean changeSettings) { 231 // TODO: migrate "auto_brightness_entry" to use R.string.preference_key_auto_brightness 232 // if we can access the Context here. (b/338314718) 233 WarningBannerInfo.Builder warningBannerInfoBuilder = 234 WarningBannerInfo.newBuilder() 235 .setMainButtonDestination(DisplaySettings.class.getName()) 236 .setMainButtonSourceMetricsCategory(SettingsEnums.DISPLAY) 237 .setMainButtonSourceHighlightKey("auto_brightness_entry"); 238 if (changeSettings) { 239 warningBannerInfoBuilder 240 .setMainButtonConfigSettingsName(Settings.System.SCREEN_BRIGHTNESS_MODE) 241 .setMainButtonConfigSettingsValue( 242 Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); 243 } 244 return PowerAnomalyEvent.newBuilder() 245 .setEventId("BrightnessAnomaly") 246 .setType(PowerAnomalyType.TYPE_SETTINGS_BANNER) 247 .setKey(PowerAnomalyKey.KEY_BRIGHTNESS) 248 .setDismissRecordKey(PowerAnomalyKey.KEY_BRIGHTNESS.name()) 249 .setScore(1.2f) 250 .setWarningBannerInfo(warningBannerInfoBuilder.build()) 251 .build(); 252 } 253 254 /** Create a power anomaly event proto of screen timeout. */ createScreenTimeoutAnomalyEvent()255 public static PowerAnomalyEvent createScreenTimeoutAnomalyEvent() { 256 return PowerAnomalyEvent.newBuilder() 257 .setEventId("ScreenTimeoutAnomaly") 258 .setType(PowerAnomalyType.TYPE_SETTINGS_BANNER) 259 .setKey(PowerAnomalyKey.KEY_SCREEN_TIMEOUT) 260 .setDismissRecordKey(PowerAnomalyKey.KEY_SCREEN_TIMEOUT.name()) 261 .setScore(1.1f) 262 .setWarningBannerInfo( 263 WarningBannerInfo.newBuilder() 264 .setMainButtonDestination(ScreenTimeoutSettings.class.getName()) 265 .setMainButtonSourceMetricsCategory(SettingsEnums.SCREEN_TIMEOUT) 266 .setMainButtonSourceHighlightKey("60000") 267 .build()) 268 .build(); 269 } 270 271 /** Create a power anomaly event proto of app anomaly. */ createAppAnomalyEvent()272 public static PowerAnomalyEvent createAppAnomalyEvent() { 273 return PowerAnomalyEvent.newBuilder() 274 .setEventId("AppAnomaly") 275 .setType(PowerAnomalyType.TYPE_APPS_ITEM) 276 .setKey(PowerAnomalyKey.KEY_APP_TOTAL_HIGHER_THAN_USUAL) 277 .setDismissRecordKey("KEY_APP_1") 278 .setScore(2.0f) 279 .setWarningItemInfo( 280 WarningItemInfo.newBuilder() 281 .setStartTimestamp(1694361600000L) // 2023-09-11 00:00:00 282 .setEndTimestamp(1694368800000L) // 2023-09-11 02:00:00 283 .build()) 284 .build(); 285 } 286 } 287