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.fuelgauge; 18 19 import static com.android.settings.SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS; 20 import static com.google.common.truth.Truth.assertThat; 21 import static org.mockito.ArgumentMatchers.nullable; 22 import static org.mockito.Matchers.any; 23 import static org.mockito.Matchers.anyInt; 24 import static org.mockito.Matchers.anyLong; 25 import static org.mockito.Matchers.eq; 26 import static org.mockito.Mockito.doAnswer; 27 import static org.mockito.Mockito.doReturn; 28 import static org.mockito.Mockito.mock; 29 import static org.mockito.Mockito.spy; 30 import static org.mockito.Mockito.verify; 31 import static org.mockito.Mockito.when; 32 33 import android.app.Activity; 34 import android.app.AppOpsManager; 35 import android.app.LoaderManager; 36 import android.content.Context; 37 import android.content.Intent; 38 import android.content.pm.ApplicationInfo; 39 import android.content.pm.PackageManager; 40 import android.graphics.drawable.Drawable; 41 import android.os.BatteryStats; 42 import android.os.Bundle; 43 import android.os.UserHandle; 44 import android.support.v7.preference.Preference; 45 import android.support.v7.widget.RecyclerView; 46 47 import com.android.internal.os.BatterySipper; 48 import com.android.internal.os.BatteryStatsHelper; 49 import com.android.settings.R; 50 import com.android.settings.SettingsActivity; 51 import com.android.settings.applications.LayoutPreference; 52 import com.android.settings.fuelgauge.anomaly.Anomaly; 53 import com.android.settings.fuelgauge.anomaly.AnomalySummaryPreferenceController; 54 import com.android.settings.testutils.FakeFeatureFactory; 55 import com.android.settings.testutils.SettingsRobolectricTestRunner; 56 import com.android.settings.testutils.shadow.ShadowActivityManager; 57 import com.android.settings.testutils.shadow.ShadowEntityHeaderController; 58 import com.android.settings.widget.EntityHeaderController; 59 import com.android.settingslib.applications.AppUtils; 60 import com.android.settingslib.applications.ApplicationsState; 61 import com.android.settingslib.applications.instantapps.InstantAppDataProvider; 62 import com.android.settingslib.core.lifecycle.Lifecycle; 63 64 import org.junit.After; 65 import org.junit.Before; 66 import org.junit.Test; 67 import org.junit.runner.RunWith; 68 import org.mockito.Answers; 69 import org.mockito.ArgumentCaptor; 70 import org.mockito.Mock; 71 import org.mockito.MockitoAnnotations; 72 import org.mockito.stubbing.Answer; 73 import org.robolectric.RuntimeEnvironment; 74 import org.robolectric.annotation.Config; 75 import org.robolectric.util.ReflectionHelpers; 76 77 import java.util.ArrayList; 78 import java.util.List; 79 80 @RunWith(SettingsRobolectricTestRunner.class) 81 @Config(shadows = {ShadowEntityHeaderController.class, ShadowActivityManager.class}) 82 public class AdvancedPowerUsageDetailTest { 83 private static final String APP_LABEL = "app label"; 84 private static final String SUMMARY = "summary"; 85 private static final String[] PACKAGE_NAME = {"com.android.app"}; 86 private static final String USAGE_PERCENT = "16%"; 87 private static final int ICON_ID = 123; 88 private static final int UID = 1; 89 private static final int POWER_MAH = 150; 90 private static final long BACKGROUND_TIME_MS = 100; 91 private static final long FOREGROUND_ACTIVITY_TIME_MS = 123; 92 private static final long FOREGROUND_SERVICE_TIME_MS = 444; 93 private static final long FOREGROUND_TIME_MS = 94 FOREGROUND_ACTIVITY_TIME_MS + FOREGROUND_SERVICE_TIME_MS; 95 private static final long PROCSTATE_TOP_TIME_MS = FOREGROUND_ACTIVITY_TIME_MS; 96 private static final long BACKGROUND_TIME_US = BACKGROUND_TIME_MS * 1000; 97 private static final long FOREGROUND_ACTIVITY_TIME_US = FOREGROUND_ACTIVITY_TIME_MS * 1000; 98 private static final long FOREGROUND_SERVICE_TIME_US = FOREGROUND_SERVICE_TIME_MS * 1000; 99 private static final long FOREGROUND_TIME_US = FOREGROUND_TIME_MS * 1000; 100 private static final long PROCSTATE_TOP_TIME_US = PROCSTATE_TOP_TIME_MS * 1000; 101 private static final long PHONE_FOREGROUND_TIME_MS = 250 * 1000; 102 private static final long PHONE_BACKGROUND_TIME_MS = 0; 103 104 @Mock(answer = Answers.RETURNS_DEEP_STUBS) 105 private Activity mActivity; 106 @Mock 107 private EntityHeaderController mEntityHeaderController; 108 @Mock 109 private LayoutPreference mHeaderPreference; 110 @Mock 111 private ApplicationsState mState; 112 @Mock 113 private ApplicationsState.AppEntry mAppEntry; 114 @Mock 115 private Bundle mBundle; 116 @Mock 117 private BatteryEntry mBatteryEntry; 118 @Mock 119 private BatterySipper mBatterySipper; 120 @Mock 121 private BatteryStatsHelper mBatteryStatsHelper; 122 @Mock 123 private BatteryStats.Uid mUid; 124 @Mock 125 private PackageManager mPackageManager; 126 @Mock 127 private AppOpsManager mAppOpsManager; 128 @Mock 129 private LoaderManager mLoaderManager; 130 @Mock 131 private AnomalySummaryPreferenceController mAnomalySummaryPreferenceController; 132 @Mock 133 private BatteryStats.Timer mForegroundActivityTimer; 134 @Mock 135 private BatteryUtils mBatteryUtils; 136 private Context mContext; 137 private Preference mForegroundPreference; 138 private Preference mBackgroundPreference; 139 private AdvancedPowerUsageDetail mFragment; 140 private SettingsActivity mTestActivity; 141 private List<Anomaly> mAnomalies; 142 143 @Before setUp()144 public void setUp() { 145 MockitoAnnotations.initMocks(this); 146 147 mContext = spy(RuntimeEnvironment.application); 148 FakeFeatureFactory.setupForTest(); 149 150 mFragment = spy(new AdvancedPowerUsageDetail()); 151 doReturn(mContext).when(mFragment).getContext(); 152 doReturn(mActivity).when(mFragment).getActivity(); 153 doReturn(SUMMARY).when(mFragment).getString(anyInt()); 154 doReturn(APP_LABEL).when(mBundle).getString(nullable(String.class)); 155 when(mFragment.getArguments()).thenReturn(mBundle); 156 doReturn(mLoaderManager).when(mFragment).getLoaderManager(); 157 158 ShadowEntityHeaderController.setUseMock(mEntityHeaderController); 159 doReturn(mEntityHeaderController).when(mEntityHeaderController) 160 .setRecyclerView(nullable(RecyclerView.class), nullable(Lifecycle.class)); 161 doReturn(mEntityHeaderController).when(mEntityHeaderController) 162 .setButtonActions(anyInt(), anyInt()); 163 doReturn(mEntityHeaderController).when(mEntityHeaderController) 164 .setIcon(nullable(Drawable.class)); 165 doReturn(mEntityHeaderController).when(mEntityHeaderController).setIcon(nullable( 166 ApplicationsState.AppEntry.class)); 167 doReturn(mEntityHeaderController).when(mEntityHeaderController) 168 .setLabel(nullable(String.class)); 169 doReturn(mEntityHeaderController).when(mEntityHeaderController) 170 .setLabel(nullable(String.class)); 171 doReturn(mEntityHeaderController).when(mEntityHeaderController) 172 .setLabel(nullable(ApplicationsState.AppEntry.class)); 173 doReturn(mEntityHeaderController).when(mEntityHeaderController) 174 .setSummary(nullable(String.class)); 175 176 doReturn(UID).when(mBatterySipper).getUid(); 177 when(mBatteryEntry.getLabel()).thenReturn(APP_LABEL); 178 doReturn(BACKGROUND_TIME_US).when(mUid).getProcessStateTime( 179 eq(BatteryStats.Uid.PROCESS_STATE_BACKGROUND), anyLong(), anyInt()); 180 doReturn(PROCSTATE_TOP_TIME_US).when(mUid).getProcessStateTime( 181 eq(BatteryStats.Uid.PROCESS_STATE_TOP), anyLong(), anyInt()); 182 doReturn(mForegroundActivityTimer).when(mUid).getForegroundActivityTimer(); 183 doReturn(FOREGROUND_ACTIVITY_TIME_US).when(mForegroundActivityTimer) 184 .getTotalTimeLocked(anyLong(), anyInt()); 185 ReflectionHelpers.setField(mBatteryEntry, "sipper", mBatterySipper); 186 mBatteryEntry.iconId = ICON_ID; 187 mBatterySipper.uidObj = mUid; 188 mBatterySipper.drainType = BatterySipper.DrainType.APP; 189 190 mFragment.mHeaderPreference = mHeaderPreference; 191 mFragment.mState = mState; 192 mFragment.mBatteryUtils = new BatteryUtils(RuntimeEnvironment.application); 193 mAppEntry.info = mock(ApplicationInfo.class); 194 195 mTestActivity = spy(new SettingsActivity()); 196 doReturn(mPackageManager).when(mTestActivity).getPackageManager(); 197 doReturn(mPackageManager).when(mActivity).getPackageManager(); 198 doReturn(mAppOpsManager).when(mTestActivity).getSystemService(Context.APP_OPS_SERVICE); 199 200 mBatteryUtils = spy(new BatteryUtils(mContext)); 201 doReturn(FOREGROUND_SERVICE_TIME_US).when(mBatteryUtils).getForegroundServiceTotalTimeUs( 202 any(BatteryStats.Uid.class), anyLong()); 203 204 final ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class); 205 206 Answer<Void> callable = invocation -> { 207 mBundle = captor.getValue().getBundleExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS); 208 return null; 209 }; 210 doAnswer(callable).when(mActivity).startActivityAsUser(captor.capture(), 211 nullable(UserHandle.class)); 212 doAnswer(callable).when(mActivity).startActivity(captor.capture()); 213 214 mForegroundPreference = new Preference(mContext); 215 mBackgroundPreference = new Preference(mContext); 216 mFragment.mForegroundPreference = mForegroundPreference; 217 mFragment.mBackgroundPreference = mBackgroundPreference; 218 mFragment.mAnomalySummaryPreferenceController = mAnomalySummaryPreferenceController; 219 220 mAnomalies = new ArrayList<>(); 221 mAnomalies.add(new Anomaly.Builder().setUid(UID).setType( 222 Anomaly.AnomalyType.WAKE_LOCK).build()); 223 } 224 225 @After reset()226 public void reset() { 227 ShadowEntityHeaderController.reset(); 228 } 229 230 @Test testInitHeader_NoAppEntry_BuildByBundle()231 public void testInitHeader_NoAppEntry_BuildByBundle() { 232 mFragment.mAppEntry = null; 233 mFragment.initHeader(); 234 235 verify(mEntityHeaderController).setIcon(nullable(Drawable.class)); 236 verify(mEntityHeaderController).setLabel(APP_LABEL); 237 } 238 239 @Test testInitHeader_HasAppEntry_BuildByAppEntry()240 public void testInitHeader_HasAppEntry_BuildByAppEntry() { 241 ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider", 242 new InstantAppDataProvider() { 243 @Override 244 public boolean isInstantApp(ApplicationInfo info) { 245 return false; 246 } 247 }); 248 mFragment.mAppEntry = mAppEntry; 249 mFragment.initHeader(); 250 251 verify(mEntityHeaderController).setIcon(mAppEntry); 252 verify(mEntityHeaderController).setLabel(mAppEntry); 253 verify(mEntityHeaderController).setIsInstantApp(false); 254 } 255 256 @Test testInitHeader_HasAppEntry_InstantApp()257 public void testInitHeader_HasAppEntry_InstantApp() { 258 ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider", 259 new InstantAppDataProvider() { 260 @Override 261 public boolean isInstantApp(ApplicationInfo info) { 262 return true; 263 } 264 }); 265 mFragment.mAppEntry = mAppEntry; 266 mFragment.initHeader(); 267 268 verify(mEntityHeaderController).setIcon(mAppEntry); 269 verify(mEntityHeaderController).setLabel(mAppEntry); 270 verify(mEntityHeaderController).setIsInstantApp(true); 271 verify(mEntityHeaderController).setSummary((CharSequence) null); 272 } 273 274 @Test testStartBatteryDetailPage_hasBasicData()275 public void testStartBatteryDetailPage_hasBasicData() { 276 AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mBatteryUtils, mFragment, 277 mBatteryStatsHelper, 0, mBatteryEntry, USAGE_PERCENT, mAnomalies); 278 279 assertThat(mBundle.getInt(AdvancedPowerUsageDetail.EXTRA_UID)).isEqualTo(UID); 280 assertThat(mBundle.getLong(AdvancedPowerUsageDetail.EXTRA_BACKGROUND_TIME)) 281 .isEqualTo(BACKGROUND_TIME_MS); 282 assertThat(mBundle.getLong(AdvancedPowerUsageDetail.EXTRA_FOREGROUND_TIME)) 283 .isEqualTo(FOREGROUND_TIME_MS); 284 assertThat(mBundle.getString(AdvancedPowerUsageDetail.EXTRA_POWER_USAGE_PERCENT)) 285 .isEqualTo(USAGE_PERCENT); 286 assertThat(mBundle.getParcelableArrayList( 287 AdvancedPowerUsageDetail.EXTRA_ANOMALY_LIST)).isEqualTo(mAnomalies); 288 } 289 290 @Test testStartBatteryDetailPage_typeNotApp_hasBasicData()291 public void testStartBatteryDetailPage_typeNotApp_hasBasicData() { 292 mBatterySipper.drainType = BatterySipper.DrainType.PHONE; 293 mBatterySipper.usageTimeMs = PHONE_FOREGROUND_TIME_MS; 294 295 AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mBatteryUtils, mFragment, 296 mBatteryStatsHelper, 0, mBatteryEntry, USAGE_PERCENT, null); 297 298 assertThat(mBundle.getInt(AdvancedPowerUsageDetail.EXTRA_UID)).isEqualTo(UID); 299 assertThat(mBundle.getLong(AdvancedPowerUsageDetail.EXTRA_FOREGROUND_TIME)) 300 .isEqualTo(PHONE_FOREGROUND_TIME_MS); 301 assertThat(mBundle.getLong(AdvancedPowerUsageDetail.EXTRA_BACKGROUND_TIME)) 302 .isEqualTo(PHONE_BACKGROUND_TIME_MS); 303 assertThat(mBundle.getString(AdvancedPowerUsageDetail.EXTRA_POWER_USAGE_PERCENT)) 304 .isEqualTo(USAGE_PERCENT); 305 assertThat(mBundle.getParcelableArrayList( 306 AdvancedPowerUsageDetail.EXTRA_ANOMALY_LIST)).isNull(); 307 } 308 309 @Test testStartBatteryDetailPage_NormalApp()310 public void testStartBatteryDetailPage_NormalApp() { 311 mBatterySipper.mPackages = PACKAGE_NAME; 312 mBatteryEntry.defaultPackageName = PACKAGE_NAME[0]; 313 AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mBatteryUtils, mFragment, 314 mBatteryStatsHelper, 0, mBatteryEntry, USAGE_PERCENT, mAnomalies); 315 316 assertThat(mBundle.getString(AdvancedPowerUsageDetail.EXTRA_PACKAGE_NAME)).isEqualTo( 317 PACKAGE_NAME[0]); 318 assertThat(mBundle.getParcelableArrayList( 319 AdvancedPowerUsageDetail.EXTRA_ANOMALY_LIST)).isEqualTo(mAnomalies); 320 } 321 322 @Test testStartBatteryDetailPage_SystemApp()323 public void testStartBatteryDetailPage_SystemApp() { 324 mBatterySipper.mPackages = null; 325 AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mBatteryUtils, mFragment, 326 mBatteryStatsHelper, 0, mBatteryEntry, USAGE_PERCENT, null); 327 328 assertThat(mBundle.getString(AdvancedPowerUsageDetail.EXTRA_LABEL)).isEqualTo(APP_LABEL); 329 assertThat(mBundle.getInt(AdvancedPowerUsageDetail.EXTRA_ICON_ID)).isEqualTo(ICON_ID); 330 assertThat(mBundle.getString(AdvancedPowerUsageDetail.EXTRA_PACKAGE_NAME)).isNull(); 331 assertThat(mBundle.getParcelableArrayList( 332 AdvancedPowerUsageDetail.EXTRA_ANOMALY_LIST)).isNull(); 333 } 334 335 @Test testStartBatteryDetailPage_WorkApp()336 public void testStartBatteryDetailPage_WorkApp() { 337 final int appUid = 1010019; 338 mBatterySipper.mPackages = PACKAGE_NAME; 339 doReturn(appUid).when(mBatterySipper).getUid(); 340 AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mBatteryUtils, mFragment, 341 mBatteryStatsHelper, 0, mBatteryEntry, USAGE_PERCENT, null); 342 343 344 verify(mActivity).startActivityAsUser(any(Intent.class), eq(new UserHandle(10))); 345 } 346 347 @Test testStartBatteryDetailPage_typeUser_startByCurrentUser()348 public void testStartBatteryDetailPage_typeUser_startByCurrentUser() { 349 mBatterySipper.drainType = BatterySipper.DrainType.USER; 350 mBatterySipper.userId = 10; 351 352 final int currentUser = 20; 353 ShadowActivityManager.setCurrentUser(currentUser); 354 AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mBatteryUtils, mFragment, 355 mBatteryStatsHelper, 0, mBatteryEntry, USAGE_PERCENT, null); 356 357 verify(mActivity).startActivityAsUser(any(Intent.class), eq(new UserHandle(currentUser))); 358 } 359 360 @Test testStartBatteryDetailPage_noBatteryUsage_hasBasicData()361 public void testStartBatteryDetailPage_noBatteryUsage_hasBasicData() { 362 final ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class); 363 364 AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mFragment, PACKAGE_NAME[0]); 365 366 verify(mActivity).startActivity(captor.capture()); 367 368 assertThat(captor.getValue().getBundleExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS) 369 .getString(AdvancedPowerUsageDetail.EXTRA_PACKAGE_NAME)) 370 .isEqualTo(PACKAGE_NAME[0]); 371 372 assertThat(captor.getValue().getBundleExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS) 373 .getString(AdvancedPowerUsageDetail.EXTRA_POWER_USAGE_PERCENT)) 374 .isEqualTo("0%"); 375 } 376 377 @Test testStartBatteryDetailPage_batteryEntryNotExisted_extractUidFromPackageName()378 public void testStartBatteryDetailPage_batteryEntryNotExisted_extractUidFromPackageName() throws 379 PackageManager.NameNotFoundException { 380 doReturn(UID).when(mPackageManager).getPackageUid(PACKAGE_NAME[0], 0 /* no flag */); 381 382 AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mFragment, PACKAGE_NAME[0]); 383 384 assertThat(mBundle.getInt(AdvancedPowerUsageDetail.EXTRA_UID)).isEqualTo(UID); 385 } 386 387 @Test testStartBatteryDetailPage_defaultPackageNull_chooseFromBatterySipper()388 public void testStartBatteryDetailPage_defaultPackageNull_chooseFromBatterySipper() { 389 mBatteryEntry.defaultPackageName = null; 390 mBatteryEntry.sipper.mPackages = PACKAGE_NAME; 391 392 AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mBatteryUtils, mFragment, 393 mBatteryStatsHelper, 0, mBatteryEntry, USAGE_PERCENT, null); 394 395 assertThat(mBundle.getString(AdvancedPowerUsageDetail.EXTRA_PACKAGE_NAME)) 396 .isEqualTo(PACKAGE_NAME[0]); 397 } 398 399 @Test testInitPreference_hasCorrectSummary()400 public void testInitPreference_hasCorrectSummary() { 401 Bundle bundle = new Bundle(4); 402 bundle.putLong(AdvancedPowerUsageDetail.EXTRA_BACKGROUND_TIME, BACKGROUND_TIME_MS); 403 bundle.putLong(AdvancedPowerUsageDetail.EXTRA_FOREGROUND_TIME, FOREGROUND_TIME_MS); 404 bundle.putString(AdvancedPowerUsageDetail.EXTRA_POWER_USAGE_PERCENT, USAGE_PERCENT); 405 bundle.putInt(AdvancedPowerUsageDetail.EXTRA_POWER_USAGE_AMOUNT, POWER_MAH); 406 when(mFragment.getArguments()).thenReturn(bundle); 407 408 doReturn(mContext.getText(R.string.battery_used_for)).when(mFragment).getText( 409 R.string.battery_used_for); 410 doReturn(mContext.getText(R.string.battery_active_for)).when(mFragment).getText( 411 R.string.battery_active_for); 412 413 mFragment.initPreference(); 414 415 assertThat(mForegroundPreference.getSummary().toString()).isEqualTo("Used for 0 min"); 416 assertThat(mBackgroundPreference.getSummary().toString()).isEqualTo("Active for 0 min"); 417 } 418 419 @Test testInitAnomalyInfo_anomalyNull_startAnomalyLoader()420 public void testInitAnomalyInfo_anomalyNull_startAnomalyLoader() { 421 doReturn(null).when(mBundle) 422 .getParcelableArrayList(AdvancedPowerUsageDetail.EXTRA_ANOMALY_LIST); 423 424 mFragment.initAnomalyInfo(); 425 426 verify(mLoaderManager).initLoader(eq(0), eq(Bundle.EMPTY), any()); 427 } 428 429 @Test testInitAnomalyInfo_anomalyExisted_updateAnomaly()430 public void testInitAnomalyInfo_anomalyExisted_updateAnomaly() { 431 doReturn(mAnomalies).when(mBundle) 432 .getParcelableArrayList(AdvancedPowerUsageDetail.EXTRA_ANOMALY_LIST); 433 434 mFragment.initAnomalyInfo(); 435 436 verify(mAnomalySummaryPreferenceController).updateAnomalySummaryPreference(mAnomalies); 437 } 438 } 439