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.Mockito.mock; 23 import static org.mockito.Mockito.verify; 24 import static org.mockito.Mockito.when; 25 26 import android.content.BroadcastReceiver; 27 import android.content.Context; 28 import android.content.Intent; 29 import android.content.pm.ApplicationInfo; 30 import android.content.pm.PackageInfo; 31 import android.content.pm.PackageManager; 32 import android.net.Uri; 33 import android.os.UserHandle; 34 35 import androidx.appcompat.app.AlertDialog; 36 import androidx.preference.PreferenceManager; 37 import androidx.preference.PreferenceScreen; 38 39 import com.android.internal.logging.nano.MetricsProto; 40 import com.android.settings.testutils.FakeFeatureFactory; 41 import com.android.settings.testutils.shadow.ShadowEntityHeaderController; 42 import com.android.settings.testutils.shadow.ShadowSettingsLibUtils; 43 import com.android.settings.widget.EntityHeaderController; 44 import com.android.settingslib.applications.AppUtils; 45 import com.android.settingslib.applications.ApplicationsState; 46 import com.android.settingslib.applications.instantapps.InstantAppDataProvider; 47 import com.android.settingslib.widget.LayoutPreference; 48 49 import org.junit.After; 50 import org.junit.Before; 51 import org.junit.Test; 52 import org.junit.runner.RunWith; 53 import org.mockito.Answers; 54 import org.mockito.Mock; 55 import org.mockito.MockitoAnnotations; 56 import org.robolectric.RobolectricTestRunner; 57 import org.robolectric.RuntimeEnvironment; 58 import org.robolectric.annotation.Config; 59 import org.robolectric.util.ReflectionHelpers; 60 61 @RunWith(RobolectricTestRunner.class) 62 @Config(shadows = {ShadowEntityHeaderController.class, ShadowSettingsLibUtils.class}) 63 public class AppInfoWithHeaderTest { 64 65 @Mock(answer = Answers.RETURNS_DEEP_STUBS) 66 private EntityHeaderController mHeaderController; 67 68 private FakeFeatureFactory mFactory; 69 private TestFragment mAppInfoWithHeader; 70 71 @Before setUp()72 public void setUp() { 73 MockitoAnnotations.initMocks(this); 74 mFactory = FakeFeatureFactory.setupForTest(); 75 when(mFactory.metricsFeatureProvider.getMetricsCategory(any(Object.class))) 76 .thenReturn(MetricsProto.MetricsEvent.SETTINGS_APP_NOTIF_CATEGORY); 77 mAppInfoWithHeader = new TestFragment(); 78 ShadowEntityHeaderController.setUseMock(mHeaderController); 79 } 80 81 @After tearDown()82 public void tearDown() { 83 ShadowEntityHeaderController.reset(); 84 } 85 86 @Test testAppHeaderIsAdded()87 public void testAppHeaderIsAdded() { 88 mAppInfoWithHeader.onActivityCreated(null); 89 90 verify(mAppInfoWithHeader.mScreen).addPreference(any(LayoutPreference.class)); 91 } 92 93 @Test packageRemoved_noAppEntry_shouldFinishActivity()94 public void packageRemoved_noAppEntry_shouldFinishActivity() { 95 BroadcastReceiver packageRemovedReceiver = 96 ReflectionHelpers.getField(mAppInfoWithHeader, "mPackageRemovedReceiver"); 97 ReflectionHelpers.setField(mAppInfoWithHeader, "mAppEntry", null); 98 99 final Intent packageRemovedBroadcast = new Intent(); 100 packageRemovedBroadcast.setData(Uri.parse("package:com.android.settings")); 101 packageRemovedReceiver.onReceive(RuntimeEnvironment.application, packageRemovedBroadcast); 102 103 assertThat(mAppInfoWithHeader.mPackageRemovedCalled).isTrue(); 104 } 105 106 @Test packageRemoved_appEntryMatchesPackageName_shouldFinishActivity()107 public void packageRemoved_appEntryMatchesPackageName_shouldFinishActivity() { 108 BroadcastReceiver packageRemovedReceiver = 109 ReflectionHelpers.getField(mAppInfoWithHeader, "mPackageRemovedReceiver"); 110 final ApplicationsState.AppEntry entry = mock(ApplicationsState.AppEntry.class); 111 entry.info = new ApplicationInfo(); 112 entry.info.packageName = "com.android.settings"; 113 ReflectionHelpers.setField(mAppInfoWithHeader, "mAppEntry", entry); 114 115 final Intent packageRemovedBroadcast = new Intent(); 116 packageRemovedBroadcast.setData(Uri.parse("package:" + entry.info.packageName)); 117 packageRemovedReceiver.onReceive(RuntimeEnvironment.application, packageRemovedBroadcast); 118 119 assertThat(mAppInfoWithHeader.mPackageRemovedCalled).isTrue(); 120 } 121 122 @Test noExtraUserHandleInIntent_retrieveAppEntryWithMyUserId()123 public void noExtraUserHandleInIntent_retrieveAppEntryWithMyUserId() 124 throws PackageManager.NameNotFoundException { 125 final String packageName = "com.android.settings"; 126 127 mAppInfoWithHeader.mIntent.setData(Uri.fromParts("package", packageName, null)); 128 final ApplicationsState.AppEntry entry = mock(ApplicationsState.AppEntry.class); 129 entry.info = new ApplicationInfo(); 130 entry.info.packageName = packageName; 131 132 when(mAppInfoWithHeader.mState.getEntry(packageName, 133 UserHandle.myUserId())).thenReturn(entry); 134 when(mAppInfoWithHeader.mPm.getPackageInfoAsUser(entry.info.packageName, 135 PackageManager.MATCH_DISABLED_COMPONENTS | 136 PackageManager.GET_SIGNING_CERTIFICATES | 137 PackageManager.GET_PERMISSIONS, UserHandle.myUserId())).thenReturn( 138 mAppInfoWithHeader.mPackageInfo); 139 140 mAppInfoWithHeader.retrieveAppEntry(); 141 142 assertThat(mAppInfoWithHeader.mUserId).isEqualTo(UserHandle.myUserId()); 143 assertThat(mAppInfoWithHeader.mPackageInfo).isNotNull(); 144 assertThat(mAppInfoWithHeader.mAppEntry).isNotNull(); 145 } 146 147 @Test extraUserHandleInIntent_retrieveAppEntryWithMyUserId()148 public void extraUserHandleInIntent_retrieveAppEntryWithMyUserId() 149 throws PackageManager.NameNotFoundException { 150 final int USER_ID = 1002; 151 final String packageName = "com.android.settings"; 152 153 mAppInfoWithHeader.mIntent.putExtra(Intent.EXTRA_USER_HANDLE, new UserHandle(USER_ID)); 154 mAppInfoWithHeader.mIntent.setData(Uri.fromParts("package", 155 packageName, null)); 156 final ApplicationsState.AppEntry entry = mock(ApplicationsState.AppEntry.class); 157 entry.info = new ApplicationInfo(); 158 entry.info.packageName = packageName; 159 160 when(mAppInfoWithHeader.mState.getEntry(packageName, USER_ID)).thenReturn(entry); 161 when(mAppInfoWithHeader.mPm.getPackageInfoAsUser(entry.info.packageName, 162 PackageManager.MATCH_DISABLED_COMPONENTS | 163 PackageManager.GET_SIGNING_CERTIFICATES | 164 PackageManager.GET_PERMISSIONS, 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() { return mIntent; } 233 } 234 } 235