1 /* 2 * Copyright (C) 2018 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.homepage.contextualcards.slices; 18 19 import static com.google.common.truth.Truth.assertThat; 20 21 import static org.mockito.Mockito.mock; 22 import static org.mockito.Mockito.when; 23 24 import android.content.Context; 25 import android.net.Uri; 26 import android.os.BatteryUsageStats; 27 28 import androidx.slice.Slice; 29 import androidx.slice.SliceMetadata; 30 import androidx.slice.SliceProvider; 31 import androidx.slice.widget.SliceLiveData; 32 33 import com.android.settings.R; 34 import com.android.settings.fuelgauge.BatteryUsageStatsLoader; 35 import com.android.settings.fuelgauge.batterytip.AppInfo; 36 import com.android.settings.fuelgauge.batterytip.BatteryTipLoader; 37 import com.android.settings.fuelgauge.batterytip.tips.BatteryTip; 38 import com.android.settings.fuelgauge.batterytip.tips.EarlyWarningTip; 39 import com.android.settings.fuelgauge.batterytip.tips.HighUsageTip; 40 import com.android.settings.fuelgauge.batterytip.tips.LowBatteryTip; 41 import com.android.settings.slices.SliceBackgroundWorker; 42 43 import org.junit.After; 44 import org.junit.Before; 45 import org.junit.Test; 46 import org.junit.runner.RunWith; 47 import org.mockito.MockitoAnnotations; 48 import org.robolectric.RobolectricTestRunner; 49 import org.robolectric.RuntimeEnvironment; 50 import org.robolectric.annotation.Config; 51 import org.robolectric.annotation.Implementation; 52 import org.robolectric.annotation.Implements; 53 import org.robolectric.annotation.Resetter; 54 55 import java.util.ArrayList; 56 import java.util.List; 57 58 @RunWith(RobolectricTestRunner.class) 59 @Config(shadows = { 60 BatteryFixSliceTest.ShadowBatteryUsageStatsLoader.class, 61 BatteryFixSliceTest.ShadowBatteryTipLoader.class 62 }) 63 public class BatteryFixSliceTest { 64 65 private Context mContext; 66 private BatteryFixSlice mSlice; 67 68 @Before setUp()69 public void setUp() { 70 MockitoAnnotations.initMocks(this); 71 mContext = RuntimeEnvironment.application; 72 mSlice = new BatteryFixSlice(mContext); 73 74 // Set-up specs for SliceMetadata. 75 SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS); 76 } 77 78 @After tearDown()79 public void tearDown() { 80 ShadowBatteryTipLoader.reset(); 81 ShadowSliceBackgroundWorker.reset(); 82 ShadowEarlyWarningTip.reset(); 83 } 84 85 @Test refreshBatteryTips_hasImportantTip_shouldReturnTrue()86 public void refreshBatteryTips_hasImportantTip_shouldReturnTrue() { 87 final List<BatteryTip> tips = new ArrayList<>(); 88 tips.add(new LowBatteryTip(BatteryTip.StateType.INVISIBLE, false)); 89 tips.add(new EarlyWarningTip(BatteryTip.StateType.NEW, false)); 90 ShadowBatteryTipLoader.setBatteryTips(tips); 91 92 BatteryFixSlice.refreshBatteryTips(mContext); 93 94 assertThat(BatteryFixSlice.isBatteryTipAvailableFromCache(mContext)).isTrue(); 95 } 96 97 @Test getSlice_unimportantSlice_shouldSkip()98 public void getSlice_unimportantSlice_shouldSkip() { 99 final List<BatteryTip> tips = new ArrayList<>(); 100 final List<AppInfo> appList = new ArrayList<>(); 101 appList.add(new AppInfo.Builder() 102 .setPackageName("com.android.settings") 103 .setScreenOnTimeMs(10000L) 104 .build()); 105 tips.add(new LowBatteryTip(BatteryTip.StateType.INVISIBLE, false)); 106 tips.add(new EarlyWarningTip(BatteryTip.StateType.HANDLED, false)); 107 tips.add(new HighUsageTip(1000L, appList)); 108 ShadowBatteryTipLoader.setBatteryTips(tips); 109 110 BatteryFixSlice.refreshBatteryTips(mContext); 111 final Slice slice = mSlice.getSlice(); 112 113 assertThat(SliceMetadata.from(mContext, slice).isErrorSlice()).isTrue(); 114 } 115 116 @Test 117 @Config(shadows = { 118 BatteryFixSliceTest.ShadowEarlyWarningTip.class, 119 BatteryFixSliceTest.ShadowSliceBackgroundWorker.class 120 }) getSlice_hasImportantTip_shouldTintIcon()121 public void getSlice_hasImportantTip_shouldTintIcon() { 122 final List<BatteryTip> tips = new ArrayList<>(); 123 tips.add(new EarlyWarningTip(BatteryTip.StateType.NEW, false)); 124 // Create fake cache data 125 ShadowBatteryTipLoader.setBatteryTips(tips); 126 BatteryFixSlice.refreshBatteryTips(mContext); 127 // Create fake background worker data 128 BatteryFixSlice.BatteryTipWorker batteryTipWorker = mock( 129 BatteryFixSlice.BatteryTipWorker.class); 130 when(batteryTipWorker.getResults()).thenReturn(tips); 131 ShadowSliceBackgroundWorker.setBatteryTipWorkerWorker(batteryTipWorker); 132 133 final Slice slice = mSlice.getSlice(); 134 135 assertThat(ShadowEarlyWarningTip.isIconTintColorIdCalled()).isTrue(); 136 } 137 138 @Implements(BatteryUsageStatsLoader.class) 139 public static class ShadowBatteryUsageStatsLoader { 140 141 @Implementation loadInBackground()142 protected BatteryUsageStats loadInBackground() { 143 return null; 144 } 145 } 146 147 @Implements(BatteryTipLoader.class) 148 public static class ShadowBatteryTipLoader { 149 150 private static List<BatteryTip> sBatteryTips = new ArrayList<>(); 151 152 @Resetter reset()153 public static void reset() { 154 sBatteryTips = new ArrayList<>(); 155 } 156 157 @Implementation loadInBackground()158 protected List<BatteryTip> loadInBackground() { 159 return sBatteryTips; 160 } 161 setBatteryTips(List<BatteryTip> tips)162 private static void setBatteryTips(List<BatteryTip> tips) { 163 sBatteryTips = tips; 164 } 165 } 166 167 @Implements(SliceBackgroundWorker.class) 168 public static class ShadowSliceBackgroundWorker { 169 170 private static BatteryFixSlice.BatteryTipWorker sBatteryTipWorkerWorker; 171 172 @Resetter reset()173 public static void reset() { 174 sBatteryTipWorkerWorker = null; 175 } 176 177 @Implementation getInstance(Uri uri)178 protected static <T extends SliceBackgroundWorker> T getInstance(Uri uri) { 179 return (T) sBatteryTipWorkerWorker; 180 } 181 setBatteryTipWorkerWorker(BatteryFixSlice.BatteryTipWorker worker)182 public static void setBatteryTipWorkerWorker(BatteryFixSlice.BatteryTipWorker worker) { 183 sBatteryTipWorkerWorker = worker; 184 } 185 } 186 187 @Implements(EarlyWarningTip.class) 188 public static class ShadowEarlyWarningTip { 189 190 private static boolean mIsGetIconTintColorIdCalled; 191 192 @Resetter reset()193 public static void reset() { 194 mIsGetIconTintColorIdCalled = false; 195 } 196 197 @Implementation getIconTintColorId()198 protected int getIconTintColorId() { 199 mIsGetIconTintColorIdCalled = true; 200 return R.color.battery_bad_color_light; 201 } 202 isIconTintColorIdCalled()203 public static boolean isIconTintColorIdCalled() { 204 return mIsGetIconTintColorIdCalled; 205 } 206 } 207 } 208