1 /* 2 * Copyright (C) 2016 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 package com.android.settings.fuelgauge; 17 18 import static com.android.settings.fuelgauge.PowerUsageSummary.BATTERY_INFO_LOADER; 19 import static com.android.settings.fuelgauge.PowerUsageSummary.KEY_BATTERY_ERROR; 20 import static com.android.settings.fuelgauge.PowerUsageSummary.KEY_BATTERY_USAGE; 21 22 import static com.google.common.truth.Truth.assertThat; 23 24 import static org.mockito.ArgumentMatchers.any; 25 import static org.mockito.ArgumentMatchers.anyInt; 26 import static org.mockito.ArgumentMatchers.eq; 27 import static org.mockito.Mockito.doNothing; 28 import static org.mockito.Mockito.doReturn; 29 import static org.mockito.Mockito.mock; 30 import static org.mockito.Mockito.never; 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.content.ContentResolver; 36 import android.content.Context; 37 import android.content.Intent; 38 import android.os.Bundle; 39 import android.provider.Settings; 40 41 import androidx.loader.app.LoaderManager; 42 import androidx.preference.Preference; 43 import androidx.preference.PreferenceScreen; 44 45 import com.android.settings.R; 46 import com.android.settings.SettingsActivity; 47 import com.android.settings.fuelgauge.batterytip.BatteryTipPreferenceController; 48 import com.android.settings.testutils.FakeFeatureFactory; 49 import com.android.settings.testutils.XmlTestUtils; 50 import com.android.settings.testutils.shadow.ShadowUtils; 51 import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin; 52 53 import org.junit.Before; 54 import org.junit.BeforeClass; 55 import org.junit.Test; 56 import org.junit.runner.RunWith; 57 import org.mockito.Mock; 58 import org.mockito.MockitoAnnotations; 59 import org.robolectric.RobolectricTestRunner; 60 import org.robolectric.RuntimeEnvironment; 61 import org.robolectric.annotation.Config; 62 import org.robolectric.util.ReflectionHelpers; 63 64 import java.util.List; 65 66 // TODO: Improve this test class so that it starts up the real activity and fragment. 67 @RunWith(RobolectricTestRunner.class) 68 public class PowerUsageSummaryTest { 69 70 private static final long TIME_SINCE_LAST_FULL_CHARGE_MS = 120 * 60 * 1000; 71 private static Intent sAdditionalBatteryInfoIntent; 72 73 @BeforeClass beforeClass()74 public static void beforeClass() { 75 sAdditionalBatteryInfoIntent = new Intent("com.example.app.ADDITIONAL_BATTERY_INFO"); 76 } 77 @Mock 78 private SettingsActivity mSettingsActivity; 79 @Mock 80 private LoaderManager mLoaderManager; 81 @Mock 82 private ContentResolver mContentResolver; 83 @Mock 84 private BatteryBroadcastReceiver mBatteryBroadcastReceiver; 85 @Mock 86 private VisibilityLoggerMixin mVisibilityLoggerMixin; 87 @Mock 88 private PreferenceScreen mPreferenceScreen; 89 @Mock 90 private Preference mBatteryUsagePreference; 91 @Mock 92 private Preference mHelpPreference; 93 94 private Context mRealContext; 95 private TestFragment mFragment; 96 private FakeFeatureFactory mFeatureFactory; 97 98 @Before setUp()99 public void setUp() { 100 MockitoAnnotations.initMocks(this); 101 102 mRealContext = spy(RuntimeEnvironment.application); 103 mFeatureFactory = FakeFeatureFactory.setupForTest(); 104 mFragment = spy(new TestFragment(mRealContext)); 105 mFragment.initFeatureProvider(); 106 doNothing().when(mFragment).restartBatteryStatsLoader(anyInt()); 107 doReturn(mock(LoaderManager.class)).when(mFragment).getLoaderManager(); 108 109 when(mFragment.getActivity()).thenReturn(mSettingsActivity); 110 when(mFeatureFactory.powerUsageFeatureProvider.getAdditionalBatteryInfoIntent()) 111 .thenReturn(sAdditionalBatteryInfoIntent); 112 when(mFeatureFactory.powerUsageFeatureProvider.isChartGraphEnabled(mRealContext)) 113 .thenReturn(true); 114 mFragment.mBatteryUtils = spy(new BatteryUtils(mRealContext)); 115 ReflectionHelpers.setField(mFragment, "mVisibilityLoggerMixin", mVisibilityLoggerMixin); 116 ReflectionHelpers.setField(mFragment, "mBatteryBroadcastReceiver", 117 mBatteryBroadcastReceiver); 118 doReturn(mPreferenceScreen).when(mFragment).getPreferenceScreen(); 119 when(mFragment.getContentResolver()).thenReturn(mContentResolver); 120 when(mFragment.findPreference(KEY_BATTERY_USAGE)).thenReturn(mBatteryUsagePreference); 121 when(mFragment.findPreference(KEY_BATTERY_ERROR)).thenReturn(mHelpPreference); 122 } 123 124 @Test 125 @Config(shadows = ShadowUtils.class) nonIndexableKeys_MatchPreferenceKeys()126 public void nonIndexableKeys_MatchPreferenceKeys() { 127 final Context context = RuntimeEnvironment.application; 128 final List<String> niks = 129 PowerUsageSummary.SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(context); 130 131 final List<String> keys = 132 XmlTestUtils.getKeysFromPreferenceXml(context, R.xml.power_usage_summary); 133 134 assertThat(keys).containsAtLeastElementsIn(niks); 135 } 136 137 @Test initPreference_chartGraphEnabled_hasCorrectSummary()138 public void initPreference_chartGraphEnabled_hasCorrectSummary() { 139 mFragment.initPreference(); 140 141 verify(mBatteryUsagePreference).setSummary("View usage for past 24 hours"); 142 } 143 144 @Test initPreference_chartGraphDisabled_hasCorrectSummary()145 public void initPreference_chartGraphDisabled_hasCorrectSummary() { 146 when(mFeatureFactory.powerUsageFeatureProvider.isChartGraphEnabled(mRealContext)) 147 .thenReturn(false); 148 149 mFragment.initPreference(); 150 151 verify(mBatteryUsagePreference).setSummary("View usage from last full charge"); 152 } 153 154 @Test initPreference_helpPreferenceInvisible()155 public void initPreference_helpPreferenceInvisible() { 156 mFragment.initPreference(); 157 158 verify(mHelpPreference).setVisible(false); 159 } 160 161 @Test restartBatteryTipLoader()162 public void restartBatteryTipLoader() { 163 //TODO: add policy logic here when BatteryTipPolicy is implemented 164 doReturn(mLoaderManager).when(mFragment).getLoaderManager(); 165 166 mFragment.restartBatteryTipLoader(); 167 168 verify(mLoaderManager) 169 .restartLoader(eq(PowerUsageSummary.BATTERY_TIP_LOADER), eq(Bundle.EMPTY), any()); 170 } 171 172 @Test refreshUi_deviceRotate_doNotUpdateBatteryTip()173 public void refreshUi_deviceRotate_doNotUpdateBatteryTip() { 174 mFragment.mBatteryTipPreferenceController = mock(BatteryTipPreferenceController.class); 175 when(mFragment.mBatteryTipPreferenceController.needUpdate()).thenReturn(false); 176 mFragment.updateBatteryTipFlag(new Bundle()); 177 178 mFragment.refreshUi(BatteryBroadcastReceiver.BatteryUpdateType.MANUAL); 179 180 verify(mFragment, never()).restartBatteryTipLoader(); 181 } 182 183 @Test refreshUi_batteryLevelChanged_doNotUpdateBatteryTip()184 public void refreshUi_batteryLevelChanged_doNotUpdateBatteryTip() { 185 mFragment.mBatteryTipPreferenceController = mock(BatteryTipPreferenceController.class); 186 when(mFragment.mBatteryTipPreferenceController.needUpdate()).thenReturn(true); 187 mFragment.updateBatteryTipFlag(new Bundle()); 188 189 mFragment.refreshUi(BatteryBroadcastReceiver.BatteryUpdateType.BATTERY_LEVEL); 190 191 verify(mFragment, never()).restartBatteryTipLoader(); 192 } 193 194 @Test refreshUi_tipNeedUpdate_updateBatteryTip()195 public void refreshUi_tipNeedUpdate_updateBatteryTip() { 196 mFragment.mBatteryTipPreferenceController = mock(BatteryTipPreferenceController.class); 197 when(mFragment.mBatteryTipPreferenceController.needUpdate()).thenReturn(true); 198 mFragment.updateBatteryTipFlag(new Bundle()); 199 200 mFragment.refreshUi(BatteryBroadcastReceiver.BatteryUpdateType.MANUAL); 201 202 verify(mFragment).restartBatteryTipLoader(); 203 } 204 205 @Test onResume_registerContentObserver()206 public void onResume_registerContentObserver() { 207 mFragment.onResume(); 208 209 verify(mContentResolver).registerContentObserver( 210 Settings.Global.getUriFor(Settings.Global.BATTERY_ESTIMATES_LAST_UPDATE_TIME), 211 false, 212 mFragment.mSettingsObserver); 213 } 214 215 @Test onPause_unregisterContentObserver()216 public void onPause_unregisterContentObserver() { 217 mFragment.onPause(); 218 219 verify(mContentResolver).unregisterContentObserver( 220 mFragment.mSettingsObserver); 221 } 222 223 @Test restartBatteryInfoLoader_contextNull_doNothing()224 public void restartBatteryInfoLoader_contextNull_doNothing() { 225 when(mFragment.getContext()).thenReturn(null); 226 when(mFragment.getLoaderManager()).thenReturn(mLoaderManager); 227 228 mFragment.restartBatteryInfoLoader(); 229 230 verify(mLoaderManager, never()).restartLoader(BATTERY_INFO_LOADER, Bundle.EMPTY, 231 mFragment.mBatteryInfoLoaderCallbacks); 232 } 233 234 public static class TestFragment extends PowerUsageSummary { 235 private Context mContext; 236 TestFragment(Context context)237 public TestFragment(Context context) { 238 mContext = context; 239 } 240 241 @Override getContext()242 public Context getContext() { 243 return mContext; 244 } 245 246 @Override getContentResolver()247 protected ContentResolver getContentResolver() { 248 // Override it so we can access this method in test 249 return super.getContentResolver(); 250 } 251 } 252 } 253