blob: c165b6be525e1d559c64385a8a1b2aef66354fc5 [file] [log] [blame]
Tony Mak96d78f52017-05-03 18:53:21 +01001/*
2 * Copyright (C) 2017 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.internal.app;
18
Tony Mak96d78f52017-05-03 18:53:21 +010019import static junit.framework.Assert.assertEquals;
20import static junit.framework.Assert.assertNotNull;
21import static junit.framework.Assert.assertNull;
22import static org.mockito.ArgumentMatchers.any;
23import static org.mockito.ArgumentMatchers.anyInt;
24import static org.mockito.ArgumentMatchers.anyString;
25import static org.mockito.ArgumentMatchers.eq;
26import static org.mockito.ArgumentMatchers.nullable;
arangelov64439c1e2018-07-31 14:18:47 +010027import static org.mockito.Mockito.never;
28import static org.mockito.Mockito.spy;
Tony Mak96d78f52017-05-03 18:53:21 +010029import static org.mockito.Mockito.verify;
30import static org.mockito.Mockito.when;
31
arangelov64439c1e2018-07-31 14:18:47 +010032import android.annotation.Nullable;
33import android.content.ComponentName;
34import android.content.Context;
35import android.content.Intent;
36import android.content.pm.ActivityInfo;
37import android.content.pm.ApplicationInfo;
38import android.content.pm.IPackageManager;
39import android.content.pm.PackageManager;
40import android.content.pm.ResolveInfo;
41import android.content.pm.UserInfo;
42import android.net.Uri;
43import android.os.Bundle;
44import android.os.RemoteException;
45import android.os.UserHandle;
46import android.os.UserManager;
47import android.support.test.InstrumentationRegistry;
48import android.support.test.rule.ActivityTestRule;
49import android.support.test.runner.AndroidJUnit4;
50import java.util.ArrayList;
51import java.util.List;
52import org.junit.Before;
53import org.junit.Rule;
54import org.junit.Test;
55import org.junit.runner.RunWith;
56import org.mockito.ArgumentCaptor;
57import org.mockito.Mock;
58import org.mockito.MockitoAnnotations;
59
Tony Mak96d78f52017-05-03 18:53:21 +010060@RunWith(AndroidJUnit4.class)
61public class IntentForwarderActivityTest {
arangelov64439c1e2018-07-31 14:18:47 +010062
Tony Mak96d78f52017-05-03 18:53:21 +010063 private static final ComponentName FORWARD_TO_MANAGED_PROFILE_COMPONENT_NAME =
64 new ComponentName(
65 "android",
66 IntentForwarderActivity.FORWARD_INTENT_TO_MANAGED_PROFILE
67 );
68 private static final String TYPE_PLAIN_TEXT = "text/plain";
69
70 private static UserInfo MANAGED_PROFILE_INFO = new UserInfo();
71 static {
72 MANAGED_PROFILE_INFO.id = 10;
73 MANAGED_PROFILE_INFO.flags = UserInfo.FLAG_MANAGED_PROFILE;
74 }
75
76 private static UserInfo CURRENT_USER_INFO = new UserInfo();
77 static {
78 CURRENT_USER_INFO.id = UserHandle.myUserId();
79 CURRENT_USER_INFO.flags = 0;
80 }
81
82 private static IntentForwarderActivity.Injector sInjector;
83 private static ComponentName sComponentName;
arangelov64439c1e2018-07-31 14:18:47 +010084 private static String sActivityName;
85 private static String sPackageName;
Tony Mak96d78f52017-05-03 18:53:21 +010086
87 @Mock private IPackageManager mIPm;
88 @Mock private PackageManager mPm;
89 @Mock private UserManager mUserManager;
arangelov64439c1e2018-07-31 14:18:47 +010090 @Mock private ApplicationInfo mApplicationInfo;
Tony Mak96d78f52017-05-03 18:53:21 +010091
92 @Rule
93 public ActivityTestRule<IntentForwarderWrapperActivity> mActivityRule =
94 new ActivityTestRule<>(IntentForwarderWrapperActivity.class, true, false);
95
96 private Context mContext;
arangelov64439c1e2018-07-31 14:18:47 +010097 public static final String PHONE_NUMBER = "123-456-789";
Tony Mak96d78f52017-05-03 18:53:21 +010098
99 @Before
100 public void setup() {
101 MockitoAnnotations.initMocks(this);
102 mContext = InstrumentationRegistry.getTargetContext();
arangelov64439c1e2018-07-31 14:18:47 +0100103 sInjector = spy(new TestInjector());
Tony Mak96d78f52017-05-03 18:53:21 +0100104 }
105
106 @Test
107 public void forwardToManagedProfile_canForward_sendIntent() throws Exception {
108 sComponentName = FORWARD_TO_MANAGED_PROFILE_COMPONENT_NAME;
109
110 // Intent can be forwarded.
111 when(mIPm.canForwardTo(
112 any(Intent.class), nullable(String.class), anyInt(), anyInt())).thenReturn(true);
113
114 // Managed profile exists.
115 List<UserInfo> profiles = new ArrayList<>();
116 profiles.add(CURRENT_USER_INFO);
117 profiles.add(MANAGED_PROFILE_INFO);
118 when(mUserManager.getProfiles(anyInt())).thenReturn(profiles);
119
120 Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class);
121 intent.setAction(Intent.ACTION_SEND);
122 intent.setType(TYPE_PLAIN_TEXT);
123 IntentForwarderWrapperActivity activity = mActivityRule.launchActivity(intent);
124
125 ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
126 verify(mIPm).canForwardTo(intentCaptor.capture(), eq(TYPE_PLAIN_TEXT), anyInt(), anyInt());
127 assertEquals(Intent.ACTION_SEND, intentCaptor.getValue().getAction());
128
129 assertEquals(Intent.ACTION_SEND, intentCaptor.getValue().getAction());
130 assertNotNull(activity.mStartActivityIntent);
131 assertEquals(Intent.ACTION_SEND, activity.mStartActivityIntent.getAction());
132 assertNull(activity.mStartActivityIntent.getPackage());
133 assertNull(activity.mStartActivityIntent.getComponent());
134 assertEquals(CURRENT_USER_INFO.id, activity.mStartActivityIntent.getContentUserHint());
135
136 assertEquals(MANAGED_PROFILE_INFO.id, activity.mUserIdActivityLaunchedIn);
137 }
138
139 @Test
140 public void forwardToManagedProfile_cannotForward_sendIntent() throws Exception {
141 sComponentName = FORWARD_TO_MANAGED_PROFILE_COMPONENT_NAME;
142
143 // Intent cannot be forwarded.
144 when(mIPm.canForwardTo(
145 any(Intent.class), nullable(String.class), anyInt(), anyInt())).thenReturn(false);
146
147 // Managed profile exists.
148 List<UserInfo> profiles = new ArrayList<>();
149 profiles.add(CURRENT_USER_INFO);
150 profiles.add(MANAGED_PROFILE_INFO);
151 when(mUserManager.getProfiles(anyInt())).thenReturn(profiles);
152
153 // Create ACTION_SEND intent.
154 Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class);
155 intent.setAction(Intent.ACTION_SEND);
156 IntentForwarderWrapperActivity activity = mActivityRule.launchActivity(intent);
157
158 assertNull(activity.mStartActivityIntent);
159 }
160
161 @Test
162 public void forwardToManagedProfile_noManagedProfile_sendIntent() throws Exception {
163 sComponentName = FORWARD_TO_MANAGED_PROFILE_COMPONENT_NAME;
164
165 // Intent can be forwarded.
166 when(mIPm.canForwardTo(
167 any(Intent.class), anyString(), anyInt(), anyInt())).thenReturn(true);
168
169 // Managed profile does not exist.
170 List<UserInfo> profiles = new ArrayList<>();
171 profiles.add(CURRENT_USER_INFO);
172 when(mUserManager.getProfiles(anyInt())).thenReturn(profiles);
173
174 // Create ACTION_SEND intent.
175 Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class);
176 intent.setAction(Intent.ACTION_SEND);
177 IntentForwarderWrapperActivity activity = mActivityRule.launchActivity(intent);
178
179 assertNull(activity.mStartActivityIntent);
180 }
181
182 @Test
183 public void forwardToManagedProfile_canForward_chooserIntent() throws Exception {
184 sComponentName = FORWARD_TO_MANAGED_PROFILE_COMPONENT_NAME;
185
186 // Intent can be forwarded.
187 when(mIPm.canForwardTo(
188 any(Intent.class), nullable(String.class), anyInt(), anyInt())).thenReturn(true);
189
190 // Manage profile exists.
191 List<UserInfo> profiles = new ArrayList<>();
192 profiles.add(CURRENT_USER_INFO);
193 profiles.add(MANAGED_PROFILE_INFO);
194 when(mUserManager.getProfiles(anyInt())).thenReturn(profiles);
195
196 // Create chooser Intent
197 Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class);
198 intent.setAction(Intent.ACTION_CHOOSER);
199 Intent sendIntent = new Intent(Intent.ACTION_SEND);
200 sendIntent.setComponent(new ComponentName("xx", "yyy"));
201 sendIntent.setType(TYPE_PLAIN_TEXT);
202 intent.putExtra(Intent.EXTRA_INTENT, sendIntent);
203 IntentForwarderWrapperActivity activity = mActivityRule.launchActivity(intent);
204
205 ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
206 verify(mIPm).canForwardTo(intentCaptor.capture(), eq(TYPE_PLAIN_TEXT), anyInt(), anyInt());
207 assertEquals(Intent.ACTION_SEND, intentCaptor.getValue().getAction());
208
209 assertNotNull(activity.mStartActivityIntent);
210 assertEquals(Intent.ACTION_CHOOSER, activity.mStartActivityIntent.getAction());
211 assertNull(activity.mStartActivityIntent.getPackage());
212 assertNull(activity.mStartActivityIntent.getComponent());
213
214 Intent innerIntent = activity.mStartActivityIntent.getParcelableExtra(Intent.EXTRA_INTENT);
215 assertNotNull(innerIntent);
216 assertEquals(Intent.ACTION_SEND, innerIntent.getAction());
217 assertNull(innerIntent.getComponent());
218 assertNull(innerIntent.getPackage());
219 assertEquals(CURRENT_USER_INFO.id, innerIntent.getContentUserHint());
220
221 assertEquals(MANAGED_PROFILE_INFO.id, activity.mUserIdActivityLaunchedIn);
222 }
223
224 @Test
225 public void forwardToManagedProfile_canForward_selectorIntent() throws Exception {
226 sComponentName = FORWARD_TO_MANAGED_PROFILE_COMPONENT_NAME;
227
228 // Intent can be forwarded.
229 when(mIPm.canForwardTo(
230 any(Intent.class), nullable(String.class), anyInt(), anyInt())).thenReturn(true);
231
232 // Manage profile exists.
233 List<UserInfo> profiles = new ArrayList<>();
234 profiles.add(CURRENT_USER_INFO);
235 profiles.add(MANAGED_PROFILE_INFO);
236 when(mUserManager.getProfiles(anyInt())).thenReturn(profiles);
237
238 // Create selector intent.
239 Intent intent = Intent.makeMainSelectorActivity(
240 Intent.ACTION_VIEW, Intent.CATEGORY_BROWSABLE);
241 IntentForwarderWrapperActivity activity = mActivityRule.launchActivity(intent);
242
243 ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
244 verify(mIPm).canForwardTo(
245 intentCaptor.capture(), nullable(String.class), anyInt(), anyInt());
246 assertEquals(Intent.ACTION_VIEW, intentCaptor.getValue().getAction());
247
248 assertNotNull(activity.mStartActivityIntent);
249 assertEquals(Intent.ACTION_MAIN, activity.mStartActivityIntent.getAction());
250 assertNull(activity.mStartActivityIntent.getPackage());
251 assertNull(activity.mStartActivityIntent.getComponent());
252 assertEquals(CURRENT_USER_INFO.id, activity.mStartActivityIntent.getContentUserHint());
253
254 Intent innerIntent = activity.mStartActivityIntent.getSelector();
255 assertNotNull(innerIntent);
256 assertEquals(Intent.ACTION_VIEW, innerIntent.getAction());
257 assertNull(innerIntent.getComponent());
258 assertNull(innerIntent.getPackage());
259
260 assertEquals(MANAGED_PROFILE_INFO.id, activity.mUserIdActivityLaunchedIn);
261 }
262
arangelov64439c1e2018-07-31 14:18:47 +0100263 @Test
264 public void shouldSkipDisclosure_notWhitelisted() throws RemoteException {
265 setupShouldSkipDisclosureTest();
266 Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class)
267 .setAction(Intent.ACTION_SEND)
268 .setType(TYPE_PLAIN_TEXT);
269
270 mActivityRule.launchActivity(intent);
271
272 verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt());
273 verify(sInjector).showToast(anyInt(), anyInt());
274 }
275
276 @Test
277 public void shouldSkipDisclosure_withResolverActivity() throws RemoteException {
278 setupShouldSkipDisclosureTest();
279 sActivityName = ResolverActivity.class.getName();
280 sPackageName = "android";
281 Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class)
282 .setAction(Intent.ACTION_SEND)
283 .setType(TYPE_PLAIN_TEXT);
284
285 mActivityRule.launchActivity(intent);
286
287 verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt());
288 verify(sInjector, never()).showToast(anyInt(), anyInt());
289 }
290
291 @Test
292 public void shouldSkipDisclosure_callIntent_call() throws RemoteException {
293 setupShouldSkipDisclosureTest();
294 Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class)
295 .setAction(Intent.ACTION_CALL);
296
297 mActivityRule.launchActivity(intent);
298
299 verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt());
300 verify(sInjector, never()).showToast(anyInt(), anyInt());
301 }
302
303 @Test
304 public void shouldSkipDisclosure_callIntent_dial() throws RemoteException {
305 setupShouldSkipDisclosureTest();
306 Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class)
307 .setAction(Intent.ACTION_DIAL);
308
309 mActivityRule.launchActivity(intent);
310
311 verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt());
312 verify(sInjector, never()).showToast(anyInt(), anyInt());
313 }
314
315 @Test
316 public void shouldSkipDisclosure_callIntent_notCallOrDial() throws RemoteException {
317 setupShouldSkipDisclosureTest();
318 Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class)
319 .setAction(Intent.ACTION_ALARM_CHANGED);
320
321 mActivityRule.launchActivity(intent);
322
323 verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt());
324 verify(sInjector).showToast(anyInt(), anyInt());
325 }
326
327 @Test
328 public void shouldSkipDisclosure_textMessageIntent_sms() throws RemoteException {
329 setupShouldSkipDisclosureTest();
330 Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class)
331 .setAction(Intent.ACTION_SENDTO)
332 .setData(Uri.fromParts("sms", PHONE_NUMBER, null));
333
334 mActivityRule.launchActivity(intent);
335
336 verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt());
337 verify(sInjector, never()).showToast(anyInt(), anyInt());
338 }
339
340 @Test
341 public void shouldSkipDisclosure_textMessageIntent_smsto() throws RemoteException {
342 setupShouldSkipDisclosureTest();
343 Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class)
344 .setAction(Intent.ACTION_SENDTO)
345 .setData(Uri.fromParts("smsto", PHONE_NUMBER, null));
346
347 mActivityRule.launchActivity(intent);
348
349 verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt());
350 verify(sInjector, never()).showToast(anyInt(), anyInt());
351 }
352
353 @Test
354 public void shouldSkipDisclosure_textMessageIntent_mms() throws RemoteException {
355 setupShouldSkipDisclosureTest();
356 Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class)
357 .setAction(Intent.ACTION_SENDTO)
358 .setData(Uri.fromParts("mms", PHONE_NUMBER, null));
359
360 mActivityRule.launchActivity(intent);
361
362 verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt());
363 verify(sInjector, never()).showToast(anyInt(), anyInt());
364 }
365
366 @Test
367 public void shouldSkipDisclosure_textMessageIntent_mmsto() throws RemoteException {
368 setupShouldSkipDisclosureTest();
369 Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class)
370 .setAction(Intent.ACTION_SENDTO)
371 .setData(Uri.fromParts("mmsto", PHONE_NUMBER, null));
372
373 mActivityRule.launchActivity(intent);
374
375 verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt());
376 verify(sInjector, never()).showToast(anyInt(), anyInt());
377 }
378
379 @Test
380 public void shouldSkipDisclosure_textMessageIntent_invalidUri() throws RemoteException {
381 setupShouldSkipDisclosureTest();
382 Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class)
383 .setAction(Intent.ACTION_SENDTO)
384 .setData(Uri.fromParts("invalid", PHONE_NUMBER, null));
385
386 mActivityRule.launchActivity(intent);
387
388 verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt());
389 verify(sInjector).showToast(anyInt(), anyInt());
390 }
391
392 private void setupShouldSkipDisclosureTest() throws RemoteException {
393 sComponentName = FORWARD_TO_MANAGED_PROFILE_COMPONENT_NAME;
394 sActivityName = "MyTestActivity";
395 sPackageName = "test.package.name";
396 when(mApplicationInfo.isSystemApp()).thenReturn(true);
397 // Managed profile exists.
398 List<UserInfo> profiles = new ArrayList<>();
399 profiles.add(CURRENT_USER_INFO);
400 profiles.add(MANAGED_PROFILE_INFO);
401 when(mUserManager.getProfiles(anyInt())).thenReturn(profiles);
402 // Intent can be forwarded.
403 when(mIPm.canForwardTo(
404 any(Intent.class), nullable(String.class), anyInt(), anyInt())).thenReturn(true);
405 }
Tony Mak96d78f52017-05-03 18:53:21 +0100406
407 public static class IntentForwarderWrapperActivity extends IntentForwarderActivity {
408 private Intent mStartActivityIntent;
409 private int mUserIdActivityLaunchedIn;
410
411 @Override
412 public void onCreate(@Nullable Bundle savedInstanceState) {
413 getIntent().setComponent(sComponentName);
414 super.onCreate(savedInstanceState);
415 }
416
417 @Override
418 protected Injector createInjector() {
419 return sInjector;
420 }
421
422 @Override
Alison Cichowlas76f0ccb2018-01-29 16:34:33 -0500423 public void startActivityAsCaller(Intent intent, @Nullable Bundle options, boolean
424 ignoreTargetSecurity, int userId) {
Tony Mak96d78f52017-05-03 18:53:21 +0100425 mStartActivityIntent = intent;
426 mUserIdActivityLaunchedIn = userId;
427 }
428 }
429
arangelov64439c1e2018-07-31 14:18:47 +0100430 public class TestInjector implements IntentForwarderActivity.Injector {
Tony Mak96d78f52017-05-03 18:53:21 +0100431
432 @Override
433 public IPackageManager getIPackageManager() {
434 return mIPm;
435 }
436
437 @Override
438 public UserManager getUserManager() {
439 return mUserManager;
440 }
441
442 @Override
443 public PackageManager getPackageManager() {
444 return mPm;
445 }
arangelov64439c1e2018-07-31 14:18:47 +0100446
447 @Override
448 public ResolveInfo resolveActivityAsUser(Intent intent, int flags, int userId) {
449 ActivityInfo activityInfo = new ActivityInfo();
450 activityInfo.packageName = sPackageName;
451 activityInfo.name = sActivityName;
452 activityInfo.applicationInfo = mApplicationInfo;
453
454 ResolveInfo resolveInfo = new ResolveInfo();
455 resolveInfo.activityInfo = activityInfo;
456
457 return resolveInfo;
458 }
459
460 @Override
461 public void showToast(int messageId, int duration) {}
Tony Mak96d78f52017-05-03 18:53:21 +0100462 }
Alison Cichowlas76f0ccb2018-01-29 16:34:33 -0500463}