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.fuelgauge; 18 19 import static com.google.common.truth.Truth.assertThat; 20 21 import static org.mockito.Mockito.doAnswer; 22 import static org.mockito.Mockito.doReturn; 23 import static org.mockito.Mockito.spy; 24 25 import android.content.Context; 26 import android.content.Intent; 27 import android.content.pm.ApplicationInfo; 28 import android.content.pm.PackageManager; 29 import android.os.Bundle; 30 import android.os.UserHandle; 31 import android.util.IconDrawableFactory; 32 import android.util.SparseLongArray; 33 34 import androidx.appcompat.app.AlertDialog; 35 import androidx.fragment.app.FragmentActivity; 36 import androidx.preference.CheckBoxPreference; 37 import androidx.preference.PreferenceCategory; 38 import androidx.preference.PreferenceManager; 39 40 import com.android.settings.SettingsActivity; 41 import com.android.settings.core.InstrumentedPreferenceFragment; 42 import com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper; 43 import com.android.settings.fuelgauge.batterytip.AppInfo; 44 import com.android.settings.fuelgauge.batterytip.BatteryDatabaseManager; 45 import com.android.settings.fuelgauge.batterytip.BatteryTipDialogFragment; 46 import com.android.settings.fuelgauge.batterytip.tips.BatteryTip; 47 import com.android.settings.fuelgauge.batterytip.tips.RestrictAppTip; 48 import com.android.settings.fuelgauge.batterytip.tips.UnrestrictAppTip; 49 import com.android.settings.testutils.shadow.ShadowAlertDialogCompat; 50 51 import org.junit.Before; 52 import org.junit.Test; 53 import org.junit.runner.RunWith; 54 import org.mockito.ArgumentCaptor; 55 import org.mockito.Mock; 56 import org.mockito.MockitoAnnotations; 57 import org.robolectric.RobolectricTestRunner; 58 import org.robolectric.RuntimeEnvironment; 59 import org.robolectric.annotation.Config; 60 import org.robolectric.shadows.androidx.fragment.FragmentController; 61 62 import java.util.ArrayList; 63 import java.util.List; 64 import java.util.concurrent.TimeUnit; 65 66 @RunWith(RobolectricTestRunner.class) 67 @Config(shadows = ShadowAlertDialogCompat.class) 68 public class RestrictedAppDetailsTest { 69 70 private static final String PACKAGE_NAME = "com.android.app"; 71 private static final int USER_ID = 10; 72 private static final int UID = UserHandle.getUid(USER_ID, 234); 73 private static final String APP_NAME = "app"; 74 75 @Mock private PackageManager mPackageManager; 76 @Mock private ApplicationInfo mApplicationInfo; 77 @Mock private IconDrawableFactory mIconDrawableFactory; 78 @Mock private InstrumentedPreferenceFragment mFragment; 79 @Mock private BatteryDatabaseManager mBatteryDatabaseManager; 80 private PreferenceManager mPreferenceManager; 81 private RestrictedAppDetails mRestrictedAppDetails; 82 private Context mContext; 83 private AppInfo mAppInfo; 84 private Intent mIntent; 85 private CheckBoxPreference mCheckBoxPreference; 86 87 @Before setUp()88 public void setUp() { 89 MockitoAnnotations.initMocks(this); 90 91 mContext = spy(RuntimeEnvironment.application); 92 mRestrictedAppDetails = spy(new RestrictedAppDetails()); 93 mAppInfo = new AppInfo.Builder().setPackageName(PACKAGE_NAME).setUid(UID).build(); 94 95 mPreferenceManager = new PreferenceManager(mContext); 96 97 doReturn(mPreferenceManager).when(mRestrictedAppDetails).getPreferenceManager(); 98 doReturn(mContext).when(mFragment).getContext(); 99 doReturn(mContext).when(mRestrictedAppDetails).getContext(); 100 mRestrictedAppDetails.mPackageManager = mPackageManager; 101 mRestrictedAppDetails.mIconDrawableFactory = mIconDrawableFactory; 102 mRestrictedAppDetails.mAppInfos = new ArrayList<>(); 103 mRestrictedAppDetails.mAppInfos.add(mAppInfo); 104 mRestrictedAppDetails.mRestrictedAppListGroup = spy(new PreferenceCategory(mContext)); 105 mRestrictedAppDetails.mBatteryUtils = spy(new BatteryUtils(mContext)); 106 mRestrictedAppDetails.mBatteryDatabaseManager = mBatteryDatabaseManager; 107 doReturn(mPreferenceManager) 108 .when(mRestrictedAppDetails.mRestrictedAppListGroup) 109 .getPreferenceManager(); 110 111 mCheckBoxPreference = new CheckBoxPreference(mContext); 112 mCheckBoxPreference.setKey(mRestrictedAppDetails.getKeyFromAppInfo(mAppInfo)); 113 } 114 115 @Test refreshUi_displayPreference()116 public void refreshUi_displayPreference() throws Exception { 117 doReturn(mApplicationInfo) 118 .when(mPackageManager) 119 .getApplicationInfoAsUser(PACKAGE_NAME, 0, USER_ID); 120 doReturn(APP_NAME).when(mPackageManager).getApplicationLabel(mApplicationInfo); 121 doReturn(true) 122 .when(mRestrictedAppDetails.mBatteryUtils) 123 .isForceAppStandbyEnabled(UID, PACKAGE_NAME); 124 final SparseLongArray timestampArray = new SparseLongArray(); 125 timestampArray.put(UID, System.currentTimeMillis() - TimeUnit.HOURS.toMillis(5)); 126 doReturn(timestampArray) 127 .when(mBatteryDatabaseManager) 128 .queryActionTime(AnomalyDatabaseHelper.ActionType.RESTRICTION); 129 130 mRestrictedAppDetails.refreshUi(); 131 132 assertThat(mRestrictedAppDetails.mRestrictedAppListGroup.getPreferenceCount()).isEqualTo(1); 133 final CheckBoxPreference preference = 134 (CheckBoxPreference) mRestrictedAppDetails.mRestrictedAppListGroup.getPreference(0); 135 assertThat(preference.getTitle()).isEqualTo(APP_NAME); 136 assertThat(preference.isChecked()).isTrue(); 137 assertThat(preference.getSummary()).isEqualTo("Restricted 5 hours ago"); 138 } 139 140 @Test startRestrictedAppDetails_startWithCorrectData()141 public void startRestrictedAppDetails_startWithCorrectData() { 142 final ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class); 143 doAnswer( 144 invocation -> { 145 // Get the intent in which it has the app info bundle 146 mIntent = captor.getValue(); 147 return true; 148 }) 149 .when(mContext) 150 .startActivity(captor.capture()); 151 152 RestrictedAppDetails.startRestrictedAppDetails(mFragment, mRestrictedAppDetails.mAppInfos); 153 154 final Bundle bundle = 155 mIntent.getBundleExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS); 156 // Verify the bundle has the correct info 157 final List<AppInfo> appInfos = 158 bundle.getParcelableArrayList(RestrictedAppDetails.EXTRA_APP_INFO_LIST); 159 assertThat(appInfos).containsExactly(mAppInfo); 160 } 161 162 @Test createDialogFragment_toRestrict_createRestrictDialog()163 public void createDialogFragment_toRestrict_createRestrictDialog() { 164 final BatteryTipDialogFragment dialogFragment = 165 mRestrictedAppDetails.createDialogFragment(mAppInfo, true); 166 167 FragmentController.setupFragment( 168 dialogFragment, FragmentActivity.class, 0 /* containerViewId */, null /* bundle */); 169 170 final AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog(); 171 ShadowAlertDialogCompat shadowDialog = ShadowAlertDialogCompat.shadowOf(dialog); 172 assertThat(shadowDialog.getTitle()).isEqualTo("Restrict app?"); 173 } 174 175 @Test createDialogFragment_toUnrestrict_createUnrestrictDialog()176 public void createDialogFragment_toUnrestrict_createUnrestrictDialog() { 177 final BatteryTipDialogFragment dialogFragment = 178 mRestrictedAppDetails.createDialogFragment(mAppInfo, false); 179 180 FragmentController.setupFragment( 181 dialogFragment, FragmentActivity.class, 0 /* containerViewId */, null /* bundle */); 182 183 final AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog(); 184 ShadowAlertDialogCompat shadowDialog = ShadowAlertDialogCompat.shadowOf(dialog); 185 assertThat(shadowDialog.getTitle()).isEqualTo("Remove restriction?"); 186 } 187 188 @Test onBatteryTipHandled_restrict_setChecked()189 public void onBatteryTipHandled_restrict_setChecked() { 190 final RestrictAppTip restrictAppTip = 191 new RestrictAppTip(BatteryTip.StateType.NEW, mAppInfo); 192 mRestrictedAppDetails.mRestrictedAppListGroup.addPreference(mCheckBoxPreference); 193 194 mRestrictedAppDetails.onBatteryTipHandled(restrictAppTip); 195 196 assertThat(mCheckBoxPreference.isChecked()).isTrue(); 197 } 198 199 @Test onBatteryTipHandled_unrestrict_setUnchecked()200 public void onBatteryTipHandled_unrestrict_setUnchecked() { 201 final UnrestrictAppTip unrestrictAppTip = 202 new UnrestrictAppTip(BatteryTip.StateType.NEW, mAppInfo); 203 mRestrictedAppDetails.mRestrictedAppListGroup.addPreference(mCheckBoxPreference); 204 205 mRestrictedAppDetails.onBatteryTipHandled(unrestrictAppTip); 206 207 assertThat(mCheckBoxPreference.isChecked()).isFalse(); 208 } 209 } 210