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 76 @Mock 77 private PackageManager mPackageManager; 78 @Mock 79 private ApplicationInfo mApplicationInfo; 80 @Mock 81 private IconDrawableFactory mIconDrawableFactory; 82 @Mock 83 private InstrumentedPreferenceFragment mFragment; 84 @Mock 85 private BatteryDatabaseManager mBatteryDatabaseManager; 86 private PreferenceManager mPreferenceManager; 87 private RestrictedAppDetails mRestrictedAppDetails; 88 private Context mContext; 89 private AppInfo mAppInfo; 90 private Intent mIntent; 91 private CheckBoxPreference mCheckBoxPreference; 92 93 @Before setUp()94 public void setUp() { 95 MockitoAnnotations.initMocks(this); 96 97 mContext = spy(RuntimeEnvironment.application); 98 mRestrictedAppDetails = spy(new RestrictedAppDetails()); 99 mAppInfo = new AppInfo.Builder() 100 .setPackageName(PACKAGE_NAME) 101 .setUid(UID) 102 .build(); 103 104 mPreferenceManager = new PreferenceManager(mContext); 105 106 doReturn(mPreferenceManager).when(mRestrictedAppDetails).getPreferenceManager(); 107 doReturn(mContext).when(mFragment).getContext(); 108 doReturn(mContext).when(mRestrictedAppDetails).getContext(); 109 mRestrictedAppDetails.mPackageManager = mPackageManager; 110 mRestrictedAppDetails.mIconDrawableFactory = mIconDrawableFactory; 111 mRestrictedAppDetails.mAppInfos = new ArrayList<>(); 112 mRestrictedAppDetails.mAppInfos.add(mAppInfo); 113 mRestrictedAppDetails.mRestrictedAppListGroup = spy(new PreferenceCategory(mContext)); 114 mRestrictedAppDetails.mBatteryUtils = spy(new BatteryUtils(mContext)); 115 mRestrictedAppDetails.mBatteryDatabaseManager = mBatteryDatabaseManager; 116 doReturn(mPreferenceManager).when( 117 mRestrictedAppDetails.mRestrictedAppListGroup).getPreferenceManager(); 118 119 mCheckBoxPreference = new CheckBoxPreference(mContext); 120 mCheckBoxPreference.setKey(mRestrictedAppDetails.getKeyFromAppInfo(mAppInfo)); 121 } 122 123 @Test refreshUi_displayPreference()124 public void refreshUi_displayPreference() throws Exception { 125 doReturn(mApplicationInfo).when(mPackageManager) 126 .getApplicationInfoAsUser(PACKAGE_NAME, 0, USER_ID); 127 doReturn(APP_NAME).when(mPackageManager).getApplicationLabel(mApplicationInfo); 128 doReturn(true).when(mRestrictedAppDetails.mBatteryUtils).isForceAppStandbyEnabled(UID, 129 PACKAGE_NAME); 130 final SparseLongArray timestampArray = new SparseLongArray(); 131 timestampArray.put(UID, System.currentTimeMillis() - TimeUnit.HOURS.toMillis(5)); 132 doReturn(timestampArray).when(mBatteryDatabaseManager) 133 .queryActionTime(AnomalyDatabaseHelper.ActionType.RESTRICTION); 134 135 mRestrictedAppDetails.refreshUi(); 136 137 assertThat(mRestrictedAppDetails.mRestrictedAppListGroup.getPreferenceCount()).isEqualTo(1); 138 final CheckBoxPreference preference = 139 (CheckBoxPreference) mRestrictedAppDetails.mRestrictedAppListGroup.getPreference(0); 140 assertThat(preference.getTitle()).isEqualTo(APP_NAME); 141 assertThat(preference.isChecked()).isTrue(); 142 assertThat(preference.getSummary()).isEqualTo("Restricted 5 hours ago"); 143 } 144 145 @Test startRestrictedAppDetails_startWithCorrectData()146 public void startRestrictedAppDetails_startWithCorrectData() { 147 final ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class); 148 doAnswer(invocation -> { 149 // Get the intent in which it has the app info bundle 150 mIntent = captor.getValue(); 151 return true; 152 }).when(mContext).startActivity(captor.capture()); 153 154 RestrictedAppDetails.startRestrictedAppDetails(mFragment, 155 mRestrictedAppDetails.mAppInfos); 156 157 final Bundle bundle = mIntent.getBundleExtra( 158 SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS); 159 // Verify the bundle has the correct info 160 final List<AppInfo> appInfos = bundle.getParcelableArrayList( 161 RestrictedAppDetails.EXTRA_APP_INFO_LIST); 162 assertThat(appInfos).containsExactly(mAppInfo); 163 } 164 165 @Test createDialogFragment_toRestrict_createRestrictDialog()166 public void createDialogFragment_toRestrict_createRestrictDialog() { 167 final BatteryTipDialogFragment dialogFragment = mRestrictedAppDetails.createDialogFragment( 168 mAppInfo, true); 169 170 FragmentController.setupFragment(dialogFragment, FragmentActivity.class, 171 0 /* containerViewId */, null /* bundle */); 172 173 final AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog(); 174 ShadowAlertDialogCompat shadowDialog = ShadowAlertDialogCompat.shadowOf(dialog); 175 assertThat(shadowDialog.getTitle()).isEqualTo("Restrict app?"); 176 } 177 178 @Test createDialogFragment_toUnrestrict_createUnrestrictDialog()179 public void createDialogFragment_toUnrestrict_createUnrestrictDialog() { 180 final BatteryTipDialogFragment dialogFragment = mRestrictedAppDetails.createDialogFragment( 181 mAppInfo, false); 182 183 FragmentController.setupFragment(dialogFragment, FragmentActivity.class, 184 0 /* containerViewId */, null /* bundle */); 185 186 final AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog(); 187 ShadowAlertDialogCompat shadowDialog = ShadowAlertDialogCompat.shadowOf(dialog); 188 assertThat(shadowDialog.getTitle()).isEqualTo("Remove restriction?"); 189 } 190 191 @Test onBatteryTipHandled_restrict_setChecked()192 public void onBatteryTipHandled_restrict_setChecked() { 193 final RestrictAppTip restrictAppTip = new RestrictAppTip(BatteryTip.StateType.NEW, 194 mAppInfo); 195 mRestrictedAppDetails.mRestrictedAppListGroup.addPreference(mCheckBoxPreference); 196 197 mRestrictedAppDetails.onBatteryTipHandled(restrictAppTip); 198 199 assertThat(mCheckBoxPreference.isChecked()).isTrue(); 200 } 201 202 @Test onBatteryTipHandled_unrestrict_setUnchecked()203 public void onBatteryTipHandled_unrestrict_setUnchecked() { 204 final UnrestrictAppTip unrestrictAppTip = new UnrestrictAppTip(BatteryTip.StateType.NEW, 205 mAppInfo); 206 mRestrictedAppDetails.mRestrictedAppListGroup.addPreference(mCheckBoxPreference); 207 208 mRestrictedAppDetails.onBatteryTipHandled(unrestrictAppTip); 209 210 assertThat(mCheckBoxPreference.isChecked()).isFalse(); 211 } 212 } 213