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 17 package com.android.settings.applications; 18 19 import static com.google.common.truth.Truth.assertThat; 20 21 import static org.mockito.ArgumentMatchers.any; 22 import static org.mockito.ArgumentMatchers.eq; 23 import static org.mockito.Mockito.mock; 24 import static org.mockito.Mockito.verify; 25 import static org.mockito.Mockito.when; 26 27 import android.content.BroadcastReceiver; 28 import android.content.Context; 29 import android.content.Intent; 30 import android.content.pm.ApplicationInfo; 31 import android.content.pm.PackageInfo; 32 import android.content.pm.PackageManager; 33 import android.net.Uri; 34 import android.os.UserHandle; 35 36 import androidx.appcompat.app.AlertDialog; 37 import androidx.preference.PreferenceManager; 38 import androidx.preference.PreferenceScreen; 39 40 import com.android.internal.logging.nano.MetricsProto; 41 import com.android.settings.testutils.FakeFeatureFactory; 42 import com.android.settings.testutils.shadow.ShadowEntityHeaderController; 43 import com.android.settings.testutils.shadow.ShadowSettingsLibUtils; 44 import com.android.settings.widget.EntityHeaderController; 45 import com.android.settingslib.applications.AppUtils; 46 import com.android.settingslib.applications.ApplicationsState; 47 import com.android.settingslib.applications.instantapps.InstantAppDataProvider; 48 import com.android.settingslib.widget.LayoutPreference; 49 50 import org.junit.After; 51 import org.junit.Before; 52 import org.junit.Rule; 53 import org.junit.Test; 54 import org.junit.runner.RunWith; 55 import org.mockito.Answers; 56 import org.mockito.Mock; 57 import org.mockito.junit.MockitoJUnit; 58 import org.mockito.junit.MockitoRule; 59 import org.robolectric.RobolectricTestRunner; 60 import org.robolectric.RuntimeEnvironment; 61 import org.robolectric.annotation.Config; 62 import org.robolectric.util.ReflectionHelpers; 63 64 @RunWith(RobolectricTestRunner.class) 65 @Config(shadows = {ShadowEntityHeaderController.class, ShadowSettingsLibUtils.class}) 66 public class AppInfoWithHeaderTest { 67 @Rule 68 public final MockitoRule mMockitoRule = MockitoJUnit.rule(); 69 70 @Mock(answer = Answers.RETURNS_DEEP_STUBS) 71 private EntityHeaderController mHeaderController; 72 73 private FakeFeatureFactory mFactory; 74 private TestFragment mAppInfoWithHeader; 75 76 @Before setUp()77 public void setUp() { 78 mFactory = FakeFeatureFactory.setupForTest(); 79 when(mFactory.metricsFeatureProvider.getMetricsCategory(any(Object.class))) 80 .thenReturn(MetricsProto.MetricsEvent.SETTINGS_APP_NOTIF_CATEGORY); 81 mAppInfoWithHeader = new TestFragment(); 82 ShadowEntityHeaderController.setUseMock(mHeaderController); 83 } 84 85 @After tearDown()86 public void tearDown() { 87 ShadowEntityHeaderController.reset(); 88 } 89 90 @Test testAppHeaderIsAdded()91 public void testAppHeaderIsAdded() { 92 mAppInfoWithHeader.onActivityCreated(null); 93 94 verify(mAppInfoWithHeader.mScreen).addPreference(any(LayoutPreference.class)); 95 } 96 97 @Test packageRemoved_noAppEntry_shouldFinishActivity()98 public void packageRemoved_noAppEntry_shouldFinishActivity() { 99 BroadcastReceiver packageRemovedReceiver = 100 ReflectionHelpers.getField(mAppInfoWithHeader, "mPackageRemovedReceiver"); 101 ReflectionHelpers.setField(mAppInfoWithHeader, "mAppEntry", null); 102 103 final Intent packageRemovedBroadcast = new Intent(); 104 packageRemovedBroadcast.setData(Uri.parse("package:com.android.settings")); 105 packageRemovedReceiver.onReceive(RuntimeEnvironment.application, packageRemovedBroadcast); 106 107 assertThat(mAppInfoWithHeader.mPackageRemovedCalled).isTrue(); 108 } 109 110 @Test packageRemoved_appEntryMatchesPackageName_shouldFinishActivity()111 public void packageRemoved_appEntryMatchesPackageName_shouldFinishActivity() { 112 BroadcastReceiver packageRemovedReceiver = 113 ReflectionHelpers.getField(mAppInfoWithHeader, "mPackageRemovedReceiver"); 114 final ApplicationsState.AppEntry entry = mock(ApplicationsState.AppEntry.class); 115 entry.info = new ApplicationInfo(); 116 entry.info.packageName = "com.android.settings"; 117 ReflectionHelpers.setField(mAppInfoWithHeader, "mAppEntry", entry); 118 119 final Intent packageRemovedBroadcast = new Intent(); 120 packageRemovedBroadcast.setData(Uri.parse("package:" + entry.info.packageName)); 121 packageRemovedReceiver.onReceive(RuntimeEnvironment.application, packageRemovedBroadcast); 122 123 assertThat(mAppInfoWithHeader.mPackageRemovedCalled).isTrue(); 124 } 125 126 @Test noExtraUserHandleInIntent_retrieveAppEntryWithMyUserId()127 public void noExtraUserHandleInIntent_retrieveAppEntryWithMyUserId() 128 throws PackageManager.NameNotFoundException { 129 final String packageName = "com.android.settings"; 130 131 mAppInfoWithHeader.mIntent.setData(Uri.fromParts("package", packageName, null)); 132 final ApplicationsState.AppEntry entry = mock(ApplicationsState.AppEntry.class); 133 entry.info = new ApplicationInfo(); 134 entry.info.packageName = packageName; 135 136 when(mAppInfoWithHeader.mState.getEntry(packageName, 137 UserHandle.myUserId())).thenReturn(entry); 138 when(mAppInfoWithHeader.mPm.getPackageInfoAsUser(eq(entry.info.packageName), 139 any(), eq(UserHandle.myUserId()))).thenReturn( 140 mAppInfoWithHeader.mPackageInfo); 141 142 mAppInfoWithHeader.retrieveAppEntry(); 143 144 assertThat(mAppInfoWithHeader.mUserId).isEqualTo(UserHandle.myUserId()); 145 assertThat(mAppInfoWithHeader.mPackageInfo).isNotNull(); 146 assertThat(mAppInfoWithHeader.mAppEntry).isNotNull(); 147 } 148 149 @Test extraUserHandleInIntent_retrieveAppEntryWithMyUserId()150 public void extraUserHandleInIntent_retrieveAppEntryWithMyUserId() 151 throws PackageManager.NameNotFoundException { 152 final int USER_ID = 1002; 153 final String packageName = "com.android.settings"; 154 155 mAppInfoWithHeader.mIntent.putExtra(Intent.EXTRA_USER_HANDLE, new UserHandle(USER_ID)); 156 mAppInfoWithHeader.mIntent.setData(Uri.fromParts("package", 157 packageName, null)); 158 final ApplicationsState.AppEntry entry = mock(ApplicationsState.AppEntry.class); 159 entry.info = new ApplicationInfo(); 160 entry.info.packageName = packageName; 161 162 when(mAppInfoWithHeader.mState.getEntry(packageName, USER_ID)).thenReturn(entry); 163 when(mAppInfoWithHeader.mPm.getPackageInfoAsUser(eq(entry.info.packageName), 164 any(), eq(USER_ID))).thenReturn( 165 mAppInfoWithHeader.mPackageInfo); 166 167 mAppInfoWithHeader.retrieveAppEntry(); 168 169 assertThat(mAppInfoWithHeader.mUserId).isEqualTo(USER_ID); 170 assertThat(mAppInfoWithHeader.mPackageInfo).isNotNull(); 171 assertThat(mAppInfoWithHeader.mAppEntry).isNotNull(); 172 } 173 174 public static class TestFragment extends AppInfoWithHeader { 175 176 PreferenceManager mManager; 177 PreferenceScreen mScreen; 178 Context mShadowContext; 179 boolean mPackageRemovedCalled; 180 Intent mIntent; 181 TestFragment()182 public TestFragment() { 183 mPm = mock(PackageManager.class); 184 mManager = mock(PreferenceManager.class); 185 mScreen = mock(PreferenceScreen.class); 186 mPackageInfo = new PackageInfo(); 187 mPackageInfo.applicationInfo = new ApplicationInfo(); 188 mState = mock(ApplicationsState.class); 189 mIntent = new Intent(); 190 mShadowContext = RuntimeEnvironment.application; 191 ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider", 192 (InstantAppDataProvider) (info -> false)); 193 when(mManager.getContext()).thenReturn(mShadowContext); 194 } 195 196 @Override getMetricsCategory()197 public int getMetricsCategory() { 198 return 0; 199 } 200 201 @Override refreshUi()202 protected boolean refreshUi() { 203 return false; 204 } 205 206 @Override createDialog(int id, int errorCode)207 protected AlertDialog createDialog(int id, int errorCode) { 208 return null; 209 } 210 211 @Override getPreferenceScreen()212 public PreferenceScreen getPreferenceScreen() { 213 return mScreen; 214 } 215 216 @Override getPreferenceManager()217 public PreferenceManager getPreferenceManager() { 218 return mManager; 219 } 220 221 @Override getContext()222 public Context getContext() { 223 return mShadowContext; 224 } 225 226 @Override onPackageRemoved()227 protected void onPackageRemoved() { 228 mPackageRemovedCalled = true; 229 } 230 231 @Override getIntent()232 protected Intent getIntent() { 233 return mIntent; 234 } 235 } 236 } 237