1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 * 15 * 16 */ 17 18 package com.android.settings.fuelgauge; 19 20 import static com.google.common.truth.Truth.assertThat; 21 22 import static org.mockito.ArgumentMatchers.any; 23 import static org.mockito.Mockito.doReturn; 24 import static org.mockito.Mockito.spy; 25 import static org.mockito.Mockito.verify; 26 import static org.mockito.Mockito.verifyZeroInteractions; 27 import static org.mockito.Mockito.when; 28 29 import android.app.Activity; 30 import android.content.Context; 31 import android.content.Intent; 32 import android.icu.text.NumberFormat; 33 import android.os.BatteryManager; 34 import android.os.PowerManager; 35 import android.text.TextUtils; 36 37 import androidx.lifecycle.LifecycleOwner; 38 import androidx.preference.PreferenceFragmentCompat; 39 import androidx.preference.PreferenceScreen; 40 41 import com.android.settings.R; 42 import com.android.settings.core.BasePreferenceController; 43 import com.android.settings.fuelgauge.batterytip.tips.BatteryTip; 44 import com.android.settings.fuelgauge.batterytip.tips.LowBatteryTip; 45 import com.android.settings.fuelgauge.batterytip.tips.SmartBatteryTip; 46 import com.android.settings.testutils.shadow.ShadowEntityHeaderController; 47 import com.android.settings.testutils.shadow.ShadowUtils; 48 import com.android.settings.widget.EntityHeaderController; 49 import com.android.settingslib.core.lifecycle.Lifecycle; 50 import com.android.settingslib.widget.UsageProgressBarPreference; 51 52 import org.junit.After; 53 import org.junit.Before; 54 import org.junit.Test; 55 import org.junit.runner.RunWith; 56 import org.mockito.Mock; 57 import org.mockito.MockitoAnnotations; 58 import org.robolectric.RobolectricTestRunner; 59 import org.robolectric.RuntimeEnvironment; 60 import org.robolectric.Shadows; 61 import org.robolectric.annotation.Config; 62 import org.robolectric.shadows.ShadowPowerManager; 63 64 @RunWith(RobolectricTestRunner.class) 65 @Config(shadows = {ShadowEntityHeaderController.class, ShadowUtils.class}) 66 public class BatteryHeaderPreferenceControllerTest { 67 68 private static final String PREF_KEY = "battery_header"; 69 private static final int BATTERY_LEVEL = 60; 70 private static final int BATTERY_MAX_LEVEL = 100; 71 private static final String TIME_LEFT = "2h30min"; 72 private static final String BATTERY_STATUS = "Charging"; 73 74 @Mock 75 private Activity mActivity; 76 @Mock 77 private PreferenceFragmentCompat mPreferenceFragment; 78 @Mock 79 private PreferenceScreen mPreferenceScreen; 80 @Mock 81 private BatteryInfo mBatteryInfo; 82 @Mock 83 private EntityHeaderController mEntityHeaderController; 84 @Mock 85 private UsageProgressBarPreference mBatteryUsageProgressBarPref; 86 @Mock 87 private BatteryStatusFeatureProvider mBatteryStatusFeatureProvider; 88 private BatteryHeaderPreferenceController mController; 89 private Context mContext; 90 private ShadowPowerManager mShadowPowerManager; 91 private Intent mBatteryIntent; 92 private LifecycleOwner mLifecycleOwner; 93 private Lifecycle mLifecycle; 94 95 @Before setUp()96 public void setUp() { 97 MockitoAnnotations.initMocks(this); 98 99 mLifecycleOwner = () -> mLifecycle; 100 mLifecycle = new Lifecycle(mLifecycleOwner); 101 mContext = spy(RuntimeEnvironment.application); 102 ShadowEntityHeaderController.setUseMock(mEntityHeaderController); 103 104 mBatteryIntent = new Intent(); 105 mBatteryIntent.putExtra(BatteryManager.EXTRA_LEVEL, BATTERY_LEVEL); 106 mBatteryIntent.putExtra(BatteryManager.EXTRA_SCALE, 100); 107 mBatteryIntent.putExtra(BatteryManager.EXTRA_PLUGGED, 1); 108 doReturn(mBatteryIntent).when(mContext).registerReceiver(any(), any()); 109 110 doReturn(mBatteryUsageProgressBarPref).when(mPreferenceScreen) 111 .findPreference(BatteryHeaderPreferenceController.KEY_BATTERY_HEADER); 112 113 mBatteryInfo.batteryLevel = BATTERY_LEVEL; 114 115 mShadowPowerManager = Shadows.shadowOf(mContext.getSystemService(PowerManager.class)); 116 117 mController = spy(new BatteryHeaderPreferenceController(mContext, PREF_KEY)); 118 mLifecycle.addObserver(mController); 119 mController.setActivity(mActivity); 120 mController.setFragment(mPreferenceFragment); 121 mController.setLifecycle(mLifecycle); 122 mController.mBatteryUsageProgressBarPref = mBatteryUsageProgressBarPref; 123 mController.mBatteryStatusFeatureProvider = mBatteryStatusFeatureProvider; 124 } 125 126 @After tearDown()127 public void tearDown() { 128 ShadowEntityHeaderController.reset(); 129 ShadowUtils.reset(); 130 } 131 132 @Test displayPreference_displayBatteryLevel()133 public void displayPreference_displayBatteryLevel() { 134 mController.displayPreference(mPreferenceScreen); 135 136 verify(mBatteryUsageProgressBarPref).setUsageSummary(formatBatteryPercentageText()); 137 verify(mBatteryUsageProgressBarPref).setPercent(BATTERY_LEVEL, BATTERY_MAX_LEVEL); 138 } 139 140 @Test updatePreference_hasRemainingTime_showRemainingLabel()141 public void updatePreference_hasRemainingTime_showRemainingLabel() { 142 mBatteryInfo.remainingLabel = TIME_LEFT; 143 144 mController.updateHeaderPreference(mBatteryInfo); 145 146 verify(mBatteryUsageProgressBarPref).setBottomSummary(mBatteryInfo.remainingLabel); 147 } 148 149 @Test updatePreference_updateBatteryInfo()150 public void updatePreference_updateBatteryInfo() { 151 setChargingState(/* isDischarging */ true, /* updatedByStatusFeature */ false); 152 153 mController.updateHeaderPreference(mBatteryInfo); 154 155 verify(mBatteryUsageProgressBarPref).setUsageSummary(formatBatteryPercentageText()); 156 verify(mBatteryUsageProgressBarPref).setBottomSummary(mBatteryInfo.remainingLabel); 157 verify(mBatteryUsageProgressBarPref).setPercent(BATTERY_LEVEL, BATTERY_MAX_LEVEL); 158 } 159 160 @Test updatePreference_noRemainingTime_showStatusLabel()161 public void updatePreference_noRemainingTime_showStatusLabel() { 162 mBatteryInfo.remainingLabel = null; 163 mBatteryInfo.statusLabel = BATTERY_STATUS; 164 165 mController.updateHeaderPreference(mBatteryInfo); 166 167 verify(mBatteryUsageProgressBarPref).setBottomSummary(BATTERY_STATUS); 168 } 169 170 @Test updatePreference_statusAnomalous_showStatusLabel()171 public void updatePreference_statusAnomalous_showStatusLabel() { 172 mBatteryInfo.remainingLabel = TIME_LEFT; 173 mBatteryInfo.statusLabel = BATTERY_STATUS; 174 mBatteryInfo.batteryStatus = BatteryManager.BATTERY_STATUS_NOT_CHARGING; 175 176 mController.updateHeaderPreference(mBatteryInfo); 177 178 verify(mBatteryUsageProgressBarPref).setBottomSummary(BATTERY_STATUS); 179 } 180 181 @Test updatePreference_charging_showFullText()182 public void updatePreference_charging_showFullText() { 183 setChargingState(/* isDischarging */ false, /* updatedByStatusFeature */ false); 184 185 mController.updateHeaderPreference(mBatteryInfo); 186 187 final String expectedResult = BATTERY_STATUS + " • " + TIME_LEFT; 188 verify(mBatteryUsageProgressBarPref).setBottomSummary(expectedResult); 189 } 190 191 @Test updatePreference_powerSaverOn_showPowerSaverOn()192 public void updatePreference_powerSaverOn_showPowerSaverOn() { 193 setChargingState(/* isDischarging */ true, /* updatedByStatusFeature */ false); 194 mShadowPowerManager.setIsPowerSaveMode(true); 195 196 mController.updateHeaderPreference(mBatteryInfo); 197 198 final String expectedResult = "Battery Saver on • " + TIME_LEFT; 199 verify(mBatteryUsageProgressBarPref).setBottomSummary(expectedResult); 200 } 201 202 @Test updatePreference_triggerBatteryStatusUpdateTrue_updatePercentageAndUsageOnly()203 public void updatePreference_triggerBatteryStatusUpdateTrue_updatePercentageAndUsageOnly() { 204 setChargingState(/* isDischarging */ true, /* updatedByStatusFeature */ true); 205 206 mController.updateHeaderPreference(mBatteryInfo); 207 208 verify(mBatteryUsageProgressBarPref).setUsageSummary(formatBatteryPercentageText()); 209 verify(mBatteryUsageProgressBarPref).setPercent(BATTERY_LEVEL, BATTERY_MAX_LEVEL); 210 } 211 212 @Test updatePreference_triggerBatteryStatusUpdateFalse_updateBatteryInfo()213 public void updatePreference_triggerBatteryStatusUpdateFalse_updateBatteryInfo() { 214 setChargingState(/* isDischarging */ true, /* updatedByStatusFeature */ false); 215 216 mController.updateHeaderPreference(mBatteryInfo); 217 218 verify(mBatteryUsageProgressBarPref).setUsageSummary(formatBatteryPercentageText()); 219 verify(mBatteryUsageProgressBarPref).setBottomSummary(mBatteryInfo.remainingLabel); 220 verify(mBatteryUsageProgressBarPref).setPercent(BATTERY_LEVEL, BATTERY_MAX_LEVEL); 221 } 222 223 @Test updateBatteryStatus_nullLabel_updateSummaryOnly()224 public void updateBatteryStatus_nullLabel_updateSummaryOnly() { 225 setChargingState(/* isDischarging */ true, /* updatedByStatusFeature */ false); 226 227 mController.updateBatteryStatus(null, mBatteryInfo); 228 229 verify(mBatteryUsageProgressBarPref).setBottomSummary(mBatteryInfo.remainingLabel); 230 } 231 232 @Test updateBatteryStatus_withLabel_showLabelText()233 public void updateBatteryStatus_withLabel_showLabelText() { 234 setChargingState(/* isDischarging */ true, /* updatedByStatusFeature */ false); 235 236 final String label = "Update by battery status • " + TIME_LEFT; 237 mController.updateBatteryStatus(label, mBatteryInfo); 238 239 verify(mBatteryUsageProgressBarPref).setBottomSummary(label); 240 } 241 242 @Test updateHeaderByBatteryTips_lowBatteryTip_showLowBattery()243 public void updateHeaderByBatteryTips_lowBatteryTip_showLowBattery() { 244 setChargingState(/* isDischarging */ true, /* updatedByStatusFeature */ false); 245 BatteryTip lowBatteryTip = new LowBatteryTip( 246 BatteryTip.StateType.NEW, /* powerSaveModeOn */false); 247 248 mController.updateHeaderByBatteryTips(lowBatteryTip, mBatteryInfo); 249 250 final String expectedResult = "Low battery • " + TIME_LEFT; 251 verify(mBatteryUsageProgressBarPref).setBottomSummary(expectedResult); 252 } 253 254 @Test updateHeaderByBatteryTips_notLowBatteryTip_showRemainingLabel()255 public void updateHeaderByBatteryTips_notLowBatteryTip_showRemainingLabel() { 256 setChargingState(/* isDischarging */ true, /* updatedByStatusFeature */ false); 257 BatteryTip lowBatteryTip = new SmartBatteryTip(BatteryTip.StateType.NEW); 258 259 mController.updateHeaderByBatteryTips(lowBatteryTip, mBatteryInfo); 260 261 verify(mBatteryUsageProgressBarPref).setBottomSummary(mBatteryInfo.remainingLabel); 262 } 263 264 @Test updateHeaderByBatteryTips_noTip_noAction()265 public void updateHeaderByBatteryTips_noTip_noAction() { 266 setChargingState(/* isDischarging */ true, /* updatedByStatusFeature */ false); 267 268 mController.updateHeaderByBatteryTips(null, mBatteryInfo); 269 270 verifyZeroInteractions(mBatteryUsageProgressBarPref); 271 } 272 273 @Test updateHeaderByBatteryTips_noBatteryInfo_noAction()274 public void updateHeaderByBatteryTips_noBatteryInfo_noAction() { 275 BatteryTip lowBatteryTip = new LowBatteryTip( 276 BatteryTip.StateType.NEW, /* powerSaveModeOn */false); 277 278 mController.updateHeaderByBatteryTips(lowBatteryTip, null); 279 280 verifyZeroInteractions(mBatteryUsageProgressBarPref); 281 } 282 283 @Test updatePreference_isOverheat_showEmptyText()284 public void updatePreference_isOverheat_showEmptyText() { 285 mBatteryInfo.isOverheated = true; 286 287 mController.updateHeaderPreference(mBatteryInfo); 288 289 verify(mBatteryUsageProgressBarPref).setBottomSummary(null); 290 } 291 292 @Test quickUpdateHeaderPreference_onlyUpdateBatteryLevelAndChargingState()293 public void quickUpdateHeaderPreference_onlyUpdateBatteryLevelAndChargingState() { 294 mController.quickUpdateHeaderPreference(); 295 296 verify(mBatteryUsageProgressBarPref).setUsageSummary(formatBatteryPercentageText()); 297 verify(mBatteryUsageProgressBarPref).setPercent(BATTERY_LEVEL, BATTERY_MAX_LEVEL); 298 } 299 300 @Test getAvailabilityStatus_returnAvailableUnsearchable()301 public void getAvailabilityStatus_returnAvailableUnsearchable() { 302 assertThat(mController.getAvailabilityStatus()).isEqualTo( 303 BasePreferenceController.AVAILABLE_UNSEARCHABLE); 304 } 305 306 @Test displayPreference_batteryNotPresent_isInvisible()307 public void displayPreference_batteryNotPresent_isInvisible() { 308 ShadowUtils.setIsBatteryPresent(false); 309 310 mController.displayPreference(mPreferenceScreen); 311 312 assertThat(mBatteryUsageProgressBarPref.isVisible()).isFalse(); 313 } 314 315 @Test displayPreference_init_showLoading()316 public void displayPreference_init_showLoading() { 317 mController.displayPreference(mPreferenceScreen); 318 319 verify(mBatteryUsageProgressBarPref).setBottomSummary( 320 mContext.getString(R.string.settings_license_activity_loading)); 321 } 322 formatBatteryPercentageText()323 private CharSequence formatBatteryPercentageText() { 324 return TextUtils.expandTemplate(mContext.getText(R.string.battery_header_title_alternate), 325 NumberFormat.getIntegerInstance().format(BATTERY_LEVEL)); 326 } 327 setChargingState(boolean isDischarging, boolean updatedByStatusFeature)328 private void setChargingState(boolean isDischarging, boolean updatedByStatusFeature) { 329 mBatteryInfo.remainingLabel = TIME_LEFT; 330 mBatteryInfo.statusLabel = BATTERY_STATUS; 331 mBatteryInfo.discharging = isDischarging; 332 333 when(mBatteryStatusFeatureProvider.triggerBatteryStatusUpdate( 334 mController, mBatteryInfo)).thenReturn(updatedByStatusFeature); 335 } 336 } 337