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