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 17package com.android.settingslib.users; 18 19import static org.mockito.Matchers.any; 20import static org.mockito.Matchers.anyInt; 21import static org.mockito.Matchers.argThat; 22import static org.mockito.Matchers.eq; 23import static org.mockito.Matchers.nullable; 24import static org.mockito.Mockito.mock; 25import static org.mockito.Mockito.times; 26import static org.mockito.Mockito.when; 27import static org.mockito.Mockito.verify; 28 29import android.appwidget.AppWidgetManager; 30import android.content.Context; 31import android.content.Intent; 32import android.content.pm.ActivityInfo; 33import android.content.pm.ApplicationInfo; 34import android.content.pm.IPackageDeleteObserver; 35import android.content.pm.IPackageManager; 36import android.content.pm.PackageInfo; 37import android.content.pm.PackageManager; 38import android.content.pm.ResolveInfo; 39import android.content.pm.ServiceInfo; 40import android.content.pm.UserInfo; 41import android.os.RemoteException; 42import android.os.UserHandle; 43import android.os.UserManager; 44import android.test.suitebuilder.annotation.SmallTest; 45import android.view.inputmethod.InputMethodInfo; 46import com.android.settingslib.BaseTest; 47 48import org.mockito.ArgumentMatcher; 49import org.mockito.Mock; 50import org.mockito.MockitoAnnotations; 51 52import java.util.ArrayList; 53import java.util.List; 54 55@SmallTest 56public class AppRestrictionsHelperTest extends BaseTest { 57 private @Mock Context mContext; 58 private @Mock PackageManager mPm; 59 private @Mock IPackageManager mIpm; 60 private @Mock UserManager mUm; 61 62 private TestInjector mInjector; 63 private UserHandle mTestUser = UserHandle.of(1111); 64 private AppRestrictionsHelper mHelper; 65 66 private ArrayList<String> mInstalledApps; 67 private ArrayList<ApplicationInfo> mInstalledAppInfos; 68 69 @Override 70 protected void setUp() throws Exception { 71 super.setUp(); 72 MockitoAnnotations.initMocks(this); 73 74 mInjector = new TestInjector(); 75 final UserInfo user = new UserInfo( 76 mTestUser.getIdentifier(), "test_user", UserInfo.FLAG_RESTRICTED); 77 when(mUm.getUserInfo(mTestUser.getIdentifier())).thenReturn(user); 78 mHelper = new AppRestrictionsHelper(mInjector); 79 mInstalledApps = new ArrayList<>(); 80 mInstalledAppInfos = new ArrayList<>(); 81 } 82 83 public void testFetchAndMergeApps() throws Exception { 84 addSystemAppsWithRequiredAccounts("sys.app0"); 85 addsystemImes(new String[] {"sys.app1", "sys.app2"}, 86 new String[] {"sys.app3", "sys.app4", "sys.app5"}); 87 addSystemAppsForIntent(new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_LAUNCHER), 88 "sys.app1", "sys.app4", "sys.app6"); 89 addSystemAppsForIntent(new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE), 90 "sys.app2", "sys.app5", "sys.app7"); 91 addDownloadedApps("app1", "app2"); 92 when(mPm.getInstalledApplications(anyInt())).thenReturn(mInstalledAppInfos); 93 94 mHelper.fetchAndMergeApps(); 95 96 final ArrayList<String> notExpectedInVisibleApps = new ArrayList<>(); 97 // System apps that require an account and doesn't see restricted account are 98 // not part of visibleApps. 99 notExpectedInVisibleApps.add("sys.app0"); 100 // Default system IMEs are not part of visibleApps. 101 notExpectedInVisibleApps.add("sys.app1"); 102 notExpectedInVisibleApps.add("sys.app2"); 103 104 final ArrayList<String> expectedInVisibleApps = new ArrayList<>(); 105 expectedInVisibleApps.add("sys.app4"); 106 expectedInVisibleApps.add("sys.app5"); 107 expectedInVisibleApps.add("sys.app6"); 108 expectedInVisibleApps.add("sys.app7"); 109 expectedInVisibleApps.add("app1"); 110 expectedInVisibleApps.add("app2"); 111 112 for (AppRestrictionsHelper.SelectableAppInfo info : mHelper.getVisibleApps()) { 113 if (expectedInVisibleApps.contains(info.packageName)) { 114 expectedInVisibleApps.remove(info.packageName); 115 } else if (notExpectedInVisibleApps.contains(info.packageName)) { 116 fail("Package: " + info.packageName + " should not be included in visibleApps"); 117 } else { 118 fail("Unknown package: " + info.packageName); 119 } 120 } 121 assertEquals("Some expected apps are not inclued in visibleApps: " + expectedInVisibleApps, 122 0, expectedInVisibleApps.size()); 123 124 assertFalse("System apps that require an account and doesn't see restricted account " 125 + "should be marked for removal", mHelper.isPackageSelected("sys.app0")); 126 } 127 128 public void testApplyUserAppsStates() throws Exception { 129 final int testUserId = mTestUser.getIdentifier(); 130 mHelper.setPackageSelected("app1", true); 131 132 mHelper.setPackageSelected("app2", true); 133 ApplicationInfo info = new ApplicationInfo(); 134 info.privateFlags |= ApplicationInfo.PRIVATE_FLAG_HIDDEN; 135 info.flags |= ApplicationInfo.FLAG_INSTALLED; 136 when(mIpm.getApplicationInfo(eq("app2"), anyInt(), eq(testUserId))) 137 .thenReturn(info); 138 139 mHelper.setPackageSelected("app3", false); 140 info = new ApplicationInfo(); 141 when(mIpm.getApplicationInfo(eq("app3"), anyInt(), eq(testUserId))) 142 .thenReturn(info); 143 144 AppRestrictionsHelper.OnDisableUiForPackageListener mockListener = 145 mock(AppRestrictionsHelper.OnDisableUiForPackageListener.class); 146 mHelper.applyUserAppsStates(mockListener); 147 148 verify(mIpm, times(1)).installExistingPackageAsUser("app1", testUserId, 149 0 /*installFlags*/, PackageManager.INSTALL_REASON_UNKNOWN); 150 verify(mIpm, times(1)).setApplicationHiddenSettingAsUser("app2", false, testUserId); 151 verify(mockListener).onDisableUiForPackage("app2"); 152 verify(mPm, times(1)).deletePackageAsUser(eq("app3"), 153 nullable(IPackageDeleteObserver.class), anyInt(), eq(mTestUser.getIdentifier())); 154 } 155 156 private void addsystemImes(String[] defaultImes, String[] otherImes) throws 157 PackageManager.NameNotFoundException, RemoteException { 158 final ArrayList<InputMethodInfo> inputMethods = new ArrayList<>(); 159 for (String pkg : defaultImes) { 160 final ResolveInfo ri = createResolveInfoForSystemApp(pkg); 161 final InputMethodInfo inputMethodInfo = new InputMethodInfo( 162 ri, false, null, null, 0, true, true, false); 163 inputMethods.add(inputMethodInfo); 164 addInstalledApp(ri); 165 } 166 for (String pkg : otherImes) { 167 final ResolveInfo ri = createResolveInfoForSystemApp(pkg); 168 final InputMethodInfo inputMethodInfo = new InputMethodInfo( 169 ri, false, null, null, 0, false, true, false); 170 inputMethods.add(inputMethodInfo); 171 addInstalledApp(ri); 172 } 173 174 mInjector.setInputMethodList(inputMethods); 175 } 176 177 private void addSystemAppsForIntent(Intent intent, String... packages) throws Exception { 178 List<ResolveInfo> resolveInfos = new ArrayList<>(); 179 for (String pkg : packages) { 180 final ResolveInfo ri = createResolveInfoForSystemApp(pkg); 181 resolveInfos.add(ri); 182 addInstalledApp(ri); 183 } 184 when(mPm.queryIntentActivities(argThat(new IntentMatcher(intent)), anyInt())) 185 .thenReturn(resolveInfos); 186 } 187 188 private void addSystemAppsWithRequiredAccounts(String... packages) throws Exception { 189 for (String pkg : packages) { 190 final ResolveInfo ri = createResolveInfoForSystemApp(pkg); 191 final PackageInfo packageInfo = new PackageInfo(); 192 packageInfo.applicationInfo = ri.activityInfo.applicationInfo; 193 packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_INSTALLED; 194 packageInfo.requiredAccountType = "account"; 195 packageInfo.restrictedAccountType = null; 196 mInstalledAppInfos.add(packageInfo.applicationInfo); 197 when(mPm.getPackageInfo(eq(pkg), anyInt())).thenReturn(packageInfo); 198 } 199 } 200 201 private void addDownloadedApps(String... packages) throws Exception { 202 for (String pkg : packages) { 203 final ResolveInfo ri = createResolveInfo(pkg); 204 addInstalledApp(ri); 205 } 206 } 207 208 private void addInstalledApp(ResolveInfo ri) throws PackageManager.NameNotFoundException { 209 final String pkgName = ri.activityInfo.packageName; 210 if (mInstalledApps.contains(pkgName)) { 211 return; 212 } 213 final PackageInfo packageInfo = new PackageInfo(); 214 packageInfo.applicationInfo = ri.activityInfo.applicationInfo; 215 packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_INSTALLED; 216 mInstalledAppInfos.add(packageInfo.applicationInfo); 217 when(mPm.getPackageInfo(eq(pkgName), anyInt())).thenReturn(packageInfo); 218 } 219 220 private ResolveInfo createResolveInfoForSystemApp(String packageName) { 221 final ResolveInfo ri = createResolveInfo(packageName); 222 ri.activityInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM; 223 ri.serviceInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM; 224 return ri; 225 } 226 227 private ResolveInfo createResolveInfo(String packageName) { 228 final ResolveInfo ri = new ResolveInfo(); 229 final ApplicationInfo applicationInfo = new ApplicationInfo(); 230 applicationInfo.packageName = packageName; 231 final ActivityInfo activityInfo = new ActivityInfo(); 232 activityInfo.applicationInfo = applicationInfo; 233 activityInfo.packageName = packageName; 234 activityInfo.name = ""; 235 ri.activityInfo = activityInfo; 236 final ServiceInfo serviceInfo = new ServiceInfo(); 237 serviceInfo.applicationInfo = applicationInfo; 238 serviceInfo.packageName = packageName; 239 serviceInfo.name = ""; 240 ri.serviceInfo = serviceInfo; 241 return ri; 242 } 243 244 private class IntentMatcher implements ArgumentMatcher<Intent> { 245 private final Intent mIntent; 246 247 IntentMatcher(Intent intent) { 248 mIntent = intent; 249 } 250 251 @Override 252 public boolean matches(Intent argument) { 253 return argument != null && argument.filterEquals(mIntent); 254 } 255 256 @Override 257 public String toString() { 258 return "Expected: " + mIntent; 259 } 260 } 261 262 private class TestInjector extends AppRestrictionsHelper.Injector { 263 List<InputMethodInfo> mImis; 264 265 TestInjector() { 266 super(mContext, mTestUser); 267 } 268 269 @Override 270 Context getContext() { 271 return mContext; 272 } 273 274 @Override 275 UserHandle getUser() { 276 return mTestUser; 277 } 278 279 @Override 280 PackageManager getPackageManager() { 281 return mPm; 282 } 283 284 @Override 285 IPackageManager getIPackageManager() { 286 return mIpm; 287 } 288 289 @Override 290 UserManager getUserManager() { 291 return mUm; 292 } 293 294 @Override 295 List<InputMethodInfo> getInputMethodList() { 296 return mImis; 297 } 298 299 void setInputMethodList(List<InputMethodInfo> imis) { 300 mImis = imis; 301 } 302 } 303} 304