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