1 /* 2 * Copyright (C) 2014 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 package com.android.cts.launchertests; 17 18 import android.app.Instrumentation; 19 import android.content.BroadcastReceiver; 20 import android.content.ComponentName; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.content.IntentFilter; 24 import android.content.ServiceConnection; 25 import android.content.pm.ApplicationInfo; 26 import android.content.pm.LauncherActivityInfo; 27 import android.content.pm.LauncherApps; 28 import android.content.pm.PackageManager; 29 import android.net.Uri; 30 import android.os.Bundle; 31 import android.os.Handler; 32 import android.os.IBinder; 33 import android.os.Looper; 34 import android.os.Message; 35 import android.os.Messenger; 36 import android.os.UserHandle; 37 import android.os.UserManager; 38 import android.support.test.InstrumentationRegistry; 39 import android.test.AndroidTestCase; 40 41 import java.util.List; 42 import java.util.concurrent.Semaphore; 43 import java.util.concurrent.TimeUnit; 44 45 /** 46 * Tests for LauncherApps service 47 */ 48 public class LauncherAppsTests extends AndroidTestCase { 49 50 public static final String SIMPLE_APP_PACKAGE = "com.android.cts.launcherapps.simpleapp"; 51 52 public static final String USER_EXTRA = "user_extra"; 53 public static final String PACKAGE_EXTRA = "package_extra"; 54 public static final String REPLY_EXTRA = "reply_extra"; 55 56 public static final int MSG_RESULT = 0; 57 public static final int MSG_CHECK_PACKAGE_ADDED = 1; 58 public static final int MSG_CHECK_PACKAGE_REMOVED = 2; 59 public static final int MSG_CHECK_PACKAGE_CHANGED = 3; 60 public static final int MSG_CHECK_NO_PACKAGE_ADDED = 4; 61 62 public static final int RESULT_PASS = 1; 63 public static final int RESULT_FAIL = 2; 64 public static final int RESULT_TIMEOUT = 3; 65 66 private LauncherApps mLauncherApps; 67 private UserHandle mUser; 68 private Instrumentation mInstrumentation; 69 private Messenger mService; 70 private Connection mConnection; 71 private Result mResult; 72 private Messenger mResultMessenger; 73 74 @Override setUp()75 protected void setUp() throws Exception { 76 super.setUp(); 77 mInstrumentation = InstrumentationRegistry.getInstrumentation(); 78 Bundle arguments = InstrumentationRegistry.getArguments(); 79 UserManager userManager = (UserManager) mInstrumentation.getContext().getSystemService( 80 Context.USER_SERVICE); 81 mUser = getUserHandleArgument(userManager, "testUser", arguments); 82 mLauncherApps = (LauncherApps) mInstrumentation.getContext().getSystemService( 83 Context.LAUNCHER_APPS_SERVICE); 84 85 final Intent intent = new Intent(); 86 intent.setComponent(new ComponentName("com.android.cts.launchertests.support", 87 "com.android.cts.launchertests.support.LauncherCallbackTestsService")); 88 89 mConnection = new Connection(); 90 mInstrumentation.getContext().bindService(intent, mConnection, Context.BIND_AUTO_CREATE); 91 mConnection.waitForService(); 92 mResult = new Result(Looper.getMainLooper()); 93 mResultMessenger = new Messenger(mResult); 94 } 95 testGetActivitiesForUserFails()96 public void testGetActivitiesForUserFails() throws Exception { 97 expectSecurityException(() -> mLauncherApps.getActivityList(null, mUser), 98 "getActivities for non-profile user failed to throw exception"); 99 } 100 testSimpleAppInstalledForUser()101 public void testSimpleAppInstalledForUser() throws Exception { 102 List<LauncherActivityInfo> activities = 103 mLauncherApps.getActivityList(null, mUser); 104 // Check simple app is there. 105 boolean foundSimpleApp = false; 106 for (LauncherActivityInfo activity : activities) { 107 if (activity.getComponentName().getPackageName().equals( 108 SIMPLE_APP_PACKAGE)) { 109 foundSimpleApp = true; 110 } 111 assertTrue(activity.getUser().equals(mUser)); 112 } 113 assertTrue(foundSimpleApp); 114 115 // Also make sure getApplicationInfo works too. 116 final ApplicationInfo ai = 117 mLauncherApps.getApplicationInfo(SIMPLE_APP_PACKAGE, /* flags= */ 0, mUser); 118 assertEquals(SIMPLE_APP_PACKAGE, ai.packageName); 119 assertEquals(mUser, UserHandle.getUserHandleForUid(ai.uid)); 120 } 121 testAccessPrimaryProfileFromManagedProfile()122 public void testAccessPrimaryProfileFromManagedProfile() throws Exception { 123 assertTrue(mLauncherApps.getActivityList(null, mUser).isEmpty()); 124 125 expectNameNotFoundException( 126 () -> mLauncherApps.getApplicationInfo(SIMPLE_APP_PACKAGE, /* flags= */ 0, mUser), 127 "get applicationInfo failed to throw name not found exception"); 128 assertFalse(mLauncherApps.isPackageEnabled(SIMPLE_APP_PACKAGE, mUser)); 129 130 final Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.android.com/")); 131 assertNull(mLauncherApps.resolveActivity(intent, mUser)); 132 } 133 testGetProfiles_fromMainProfile()134 public void testGetProfiles_fromMainProfile() { 135 final List<UserHandle> profiles = mLauncherApps.getProfiles(); 136 assertEquals(2, profiles.size()); 137 assertTrue(profiles.contains(android.os.Process.myUserHandle())); 138 assertEquals(getContext().getSystemService(UserManager.class).getUserProfiles(), 139 profiles); 140 } 141 testGetProfiles_fromManagedProfile()142 public void testGetProfiles_fromManagedProfile() { 143 final List<UserHandle> profiles = mLauncherApps.getProfiles(); 144 assertEquals(1, profiles.size()); 145 assertEquals(android.os.Process.myUserHandle(), profiles.get(0)); 146 } 147 testPackageAddedCallbackForUser()148 public void testPackageAddedCallbackForUser() throws Throwable { 149 int result = sendMessageToCallbacksService(MSG_CHECK_PACKAGE_ADDED, 150 mUser, SIMPLE_APP_PACKAGE); 151 assertEquals(RESULT_PASS, result); 152 } 153 testPackageRemovedCallbackForUser()154 public void testPackageRemovedCallbackForUser() throws Throwable { 155 int result = sendMessageToCallbacksService(MSG_CHECK_PACKAGE_REMOVED, 156 mUser, SIMPLE_APP_PACKAGE); 157 assertEquals(RESULT_PASS, result); 158 } testPackageChangedCallbackForUser()159 public void testPackageChangedCallbackForUser() throws Throwable { 160 int result = sendMessageToCallbacksService(MSG_CHECK_PACKAGE_CHANGED, 161 mUser, SIMPLE_APP_PACKAGE); 162 assertEquals(RESULT_PASS, result); 163 } 164 testNoPackageAddedCallbackForUser()165 public void testNoPackageAddedCallbackForUser() throws Throwable { 166 int result = sendMessageToCallbacksService(MSG_CHECK_NO_PACKAGE_ADDED, 167 mUser, SIMPLE_APP_PACKAGE); 168 assertEquals(RESULT_PASS, result); 169 } 170 testLaunchNonExportActivityFails()171 public void testLaunchNonExportActivityFails() throws Exception { 172 expectSecurityException(() -> mLauncherApps.startMainActivity(new ComponentName( 173 SIMPLE_APP_PACKAGE, SIMPLE_APP_PACKAGE + ".NonExportedActivity"), 174 mUser, null, null), 175 "starting non-exported activity failed to throw exception"); 176 } 177 testLaunchNonExportLauncherFails()178 public void testLaunchNonExportLauncherFails() throws Exception { 179 expectSecurityException(() -> mLauncherApps.startMainActivity(new ComponentName( 180 SIMPLE_APP_PACKAGE, SIMPLE_APP_PACKAGE + ".NonLauncherActivity"), 181 mUser, null, null), 182 "starting non-launcher activity failed to throw exception"); 183 } 184 testLaunchMainActivity()185 public void testLaunchMainActivity() throws Exception { 186 ActivityLaunchedReceiver receiver = new ActivityLaunchedReceiver(); 187 IntentFilter filter = new IntentFilter(); 188 filter.addAction(ActivityLaunchedReceiver.ACTIVITY_LAUNCHED_ACTION); 189 mInstrumentation.getContext().registerReceiver(receiver, filter); 190 mLauncherApps.startMainActivity(new ComponentName( 191 SIMPLE_APP_PACKAGE, 192 SIMPLE_APP_PACKAGE + ".SimpleActivity"), 193 mUser, null, null); 194 assertEquals(RESULT_PASS, receiver.waitForActivity()); 195 mInstrumentation.getContext().unregisterReceiver(receiver); 196 } 197 testReverseAccessNoThrow()198 public void testReverseAccessNoThrow() throws Exception { 199 // Trying to access the main profile from a managed profile -> shouldn't throw but 200 // should just return false. 201 assertFalse(mLauncherApps.isPackageEnabled("android", mUser)); 202 } 203 expectSecurityException(ExceptionRunnable action, String failMessage)204 private void expectSecurityException(ExceptionRunnable action, String failMessage) 205 throws Exception { 206 try { 207 action.run(); 208 fail(failMessage); 209 } catch (SecurityException e) { 210 // expected 211 } 212 } 213 expectNameNotFoundException(ExceptionRunnable action, String failMessage)214 private void expectNameNotFoundException(ExceptionRunnable action, String failMessage) 215 throws Exception { 216 try { 217 action.run(); 218 fail(failMessage); 219 } catch (PackageManager.NameNotFoundException e) { 220 // expected 221 } 222 } 223 224 @FunctionalInterface 225 public interface ExceptionRunnable { run()226 void run() throws Exception; 227 } 228 getUserHandleArgument(UserManager userManager, String key, Bundle arguments)229 private UserHandle getUserHandleArgument(UserManager userManager, String key, 230 Bundle arguments) throws Exception { 231 String serial = arguments.getString(key); 232 if (serial == null) { 233 return null; 234 } 235 int serialNo = Integer.parseInt(serial); 236 return userManager.getUserForSerialNumber(serialNo); 237 } 238 239 private class Connection implements ServiceConnection { 240 private final Semaphore mSemaphore = new Semaphore(0); 241 242 @Override onServiceConnected(ComponentName className, IBinder service)243 public void onServiceConnected(ComponentName className, IBinder service) { 244 mService = new Messenger(service); 245 mSemaphore.release(); 246 } 247 248 @Override onServiceDisconnected(ComponentName className)249 public void onServiceDisconnected(ComponentName className) { 250 mService = null; 251 } 252 waitForService()253 public void waitForService() { 254 try { 255 if (mSemaphore.tryAcquire(5, TimeUnit.SECONDS)) { 256 return; 257 } 258 } catch (InterruptedException e) { 259 } 260 fail("failed to connec to service"); 261 } 262 }; 263 264 private static class Result extends Handler { 265 266 private final Semaphore mSemaphore = new Semaphore(0); 267 public int result = 0; 268 Result(Looper looper)269 public Result(Looper looper) { 270 super(looper); 271 } 272 273 @Override handleMessage(Message msg)274 public void handleMessage(Message msg) { 275 if (msg.what == MSG_RESULT) { 276 result = msg.arg1; 277 mSemaphore.release(); 278 } else { 279 super.handleMessage(msg); 280 } 281 } 282 waitForResult()283 public int waitForResult() { 284 try { 285 if (mSemaphore.tryAcquire(120, TimeUnit.SECONDS)) { 286 return result; 287 } 288 } catch (InterruptedException e) { 289 } 290 return RESULT_TIMEOUT; 291 } 292 } 293 294 public class ActivityLaunchedReceiver extends BroadcastReceiver { 295 public static final String ACTIVITY_LAUNCHED_ACTION = 296 "com.android.cts.launchertests.LauncherAppsTests.LAUNCHED_ACTION"; 297 298 private final Semaphore mSemaphore = new Semaphore(0); 299 300 @Override onReceive(Context context, Intent intent)301 public void onReceive(Context context, Intent intent) { 302 if (intent.getAction().equals(ACTIVITY_LAUNCHED_ACTION)) { 303 mSemaphore.release(); 304 } 305 } 306 waitForActivity()307 public int waitForActivity() { 308 try { 309 if (mSemaphore.tryAcquire(5, TimeUnit.SECONDS)) { 310 return RESULT_PASS; 311 } 312 } catch (InterruptedException e) { 313 } 314 return RESULT_TIMEOUT; 315 } 316 } 317 sendMessageToCallbacksService(int msg, UserHandle user, String packageName)318 private int sendMessageToCallbacksService(int msg, UserHandle user, String packageName) 319 throws Throwable { 320 Bundle params = new Bundle(); 321 params.putParcelable(USER_EXTRA, user); 322 params.putString(PACKAGE_EXTRA, packageName); 323 324 Message message = Message.obtain(null, msg, params); 325 message.replyTo = mResultMessenger; 326 327 mService.send(message); 328 329 return mResult.waitForResult(); 330 } 331 } 332