• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 package com.android.internal.app;
18 
19 import static androidx.test.espresso.Espresso.onView;
20 import static androidx.test.espresso.action.ViewActions.click;
21 import static androidx.test.espresso.assertion.ViewAssertions.matches;
22 import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
23 import static androidx.test.espresso.matcher.ViewMatchers.withId;
24 
25 import static junit.framework.Assert.assertEquals;
26 import static junit.framework.Assert.assertNotNull;
27 import static junit.framework.Assert.assertNull;
28 
29 import static org.mockito.ArgumentMatchers.any;
30 import static org.mockito.ArgumentMatchers.anyInt;
31 import static org.mockito.ArgumentMatchers.anyString;
32 import static org.mockito.ArgumentMatchers.eq;
33 import static org.mockito.ArgumentMatchers.nullable;
34 import static org.mockito.Mockito.mock;
35 import static org.mockito.Mockito.never;
36 import static org.mockito.Mockito.spy;
37 import static org.mockito.Mockito.verify;
38 import static org.mockito.Mockito.when;
39 
40 import android.annotation.Nullable;
41 import android.content.ComponentName;
42 import android.content.Context;
43 import android.content.Intent;
44 import android.content.pm.ActivityInfo;
45 import android.content.pm.ApplicationInfo;
46 import android.content.pm.IPackageManager;
47 import android.content.pm.PackageManager;
48 import android.content.pm.ResolveInfo;
49 import android.content.pm.UserInfo;
50 import android.metrics.LogMaker;
51 import android.net.Uri;
52 import android.os.Bundle;
53 import android.os.RemoteException;
54 import android.os.UserHandle;
55 import android.os.UserManager;
56 import android.platform.test.flag.junit.SetFlagsRule;
57 import android.provider.Settings;
58 
59 import androidx.test.InstrumentationRegistry;
60 import androidx.test.ext.junit.runners.AndroidJUnit4;
61 import androidx.test.rule.ActivityTestRule;
62 
63 import com.android.internal.R;
64 import com.android.internal.logging.MetricsLogger;
65 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
66 
67 import org.junit.After;
68 import org.junit.Before;
69 import org.junit.Rule;
70 import org.junit.Test;
71 import org.junit.runner.RunWith;
72 import org.mockito.ArgumentCaptor;
73 import org.mockito.Mock;
74 import org.mockito.MockitoAnnotations;
75 
76 import java.util.ArrayList;
77 import java.util.List;
78 import java.util.concurrent.CompletableFuture;
79 import java.util.concurrent.TimeUnit;
80 
81 @RunWith(AndroidJUnit4.class)
82 public class IntentForwarderActivityTest {
83 
84     private static final ComponentName FORWARD_TO_MANAGED_PROFILE_COMPONENT_NAME =
85             new ComponentName(
86                     "android",
87                     IntentForwarderActivity.FORWARD_INTENT_TO_MANAGED_PROFILE
88             );
89     private static final ComponentName FORWARD_TO_PARENT_COMPONENT_NAME =
90             new ComponentName(
91                     "android",
92                     IntentForwarderActivity.FORWARD_INTENT_TO_PARENT
93             );
94     private static final String TYPE_PLAIN_TEXT = "text/plain";
95 
96     private static UserInfo MANAGED_PROFILE_INFO = new UserInfo();
97     private static UserInfo PRIVATE_PROFILE_INFO = new UserInfo(12, "Private", null,
98             UserInfo.FLAG_PROFILE, UserManager.USER_TYPE_PROFILE_PRIVATE);
99     @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
100 
101     static {
102         MANAGED_PROFILE_INFO.id = 10;
103         MANAGED_PROFILE_INFO.flags = UserInfo.FLAG_MANAGED_PROFILE;
104         MANAGED_PROFILE_INFO.userType = UserManager.USER_TYPE_PROFILE_MANAGED;
105     }
106 
107     private static UserInfo CURRENT_USER_INFO = new UserInfo();
108 
109     static {
110         CURRENT_USER_INFO.id = UserHandle.myUserId();
111         CURRENT_USER_INFO.flags = 0;
112     }
113 
114     private static IntentForwarderActivity.Injector sInjector;
115     private static ComponentName sComponentName;
116     private static String sActivityName;
117     private static String sPackageName;
118 
119     @Mock
120     private IPackageManager mIPm;
121     @Mock
122     private PackageManager mPm;
123     @Mock
124     private UserManager mUserManager;
125     @Mock
126     private ApplicationInfo mApplicationInfo;
127 
128     @Rule
129     public ActivityTestRule<IntentForwarderWrapperActivity> mActivityRule =
130             new ActivityTestRule<>(IntentForwarderWrapperActivity.class, true, false);
131 
132     private Context mContext;
133     public static final String PHONE_NUMBER = "123-456-789";
134     private int mDeviceProvisionedInitialValue;
135 
136     @Before
setup()137     public void setup() {
138 
139         MockitoAnnotations.initMocks(this);
140         mContext = InstrumentationRegistry.getTargetContext();
141         sInjector = spy(new TestInjector());
142         mDeviceProvisionedInitialValue = Settings.Global.getInt(mContext.getContentResolver(),
143                 Settings.Global.DEVICE_PROVISIONED, /* def= */ 0);
144     }
145 
146     @After
tearDown()147     public void tearDown() {
148         Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.DEVICE_PROVISIONED,
149                 mDeviceProvisionedInitialValue);
150     }
151 
152     @Test
forwardToManagedProfile_canForward_sendIntent()153     public void forwardToManagedProfile_canForward_sendIntent() throws Exception {
154         sComponentName = FORWARD_TO_MANAGED_PROFILE_COMPONENT_NAME;
155         sActivityName = "MyTestActivity";
156         sPackageName = "test.package.name";
157 
158         // Intent can be forwarded.
159         when(mIPm.canForwardTo(
160                 any(Intent.class), nullable(String.class), anyInt(), anyInt())).thenReturn(true);
161 
162         // Managed profile exists.
163         List<UserInfo> profiles = new ArrayList<>();
164         profiles.add(CURRENT_USER_INFO);
165         profiles.add(MANAGED_PROFILE_INFO);
166         when(mUserManager.getProfiles(anyInt())).thenReturn(profiles);
167 
168         Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class);
169         intent.setAction(Intent.ACTION_SEND);
170         intent.setType(TYPE_PLAIN_TEXT);
171         IntentForwarderWrapperActivity activity = mActivityRule.launchActivity(intent);
172 
173         ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
174         verify(mIPm).canForwardTo(intentCaptor.capture(), eq(TYPE_PLAIN_TEXT), anyInt(), anyInt());
175         assertEquals(Intent.ACTION_SEND, intentCaptor.getValue().getAction());
176 
177         InstrumentationRegistry.getInstrumentation().waitForIdleSync();
178         onView(withId(R.id.icon)).check(matches(isDisplayed()));
179         onView(withId(R.id.open_cross_profile)).check(matches(isDisplayed()));
180         onView(withId(R.id.use_same_profile_browser)).check(matches(isDisplayed()));
181         onView(withId(R.id.button_open)).perform(click());
182         InstrumentationRegistry.getInstrumentation().waitForIdleSync();
183 
184         assertNotNull(activity.mStartActivityIntent);
185         assertEquals(Intent.ACTION_SEND, activity.mStartActivityIntent.getAction());
186         assertNull(activity.mStartActivityIntent.getPackage());
187         assertNull(activity.mStartActivityIntent.getComponent());
188         assertEquals(CURRENT_USER_INFO.id, activity.mStartActivityIntent.getContentUserHint());
189 
190         assertEquals(MANAGED_PROFILE_INFO.id, activity.mUserIdActivityLaunchedIn);
191     }
192 
193     @Test
forwardToManagedProfile_cannotForward_sendIntent()194     public void forwardToManagedProfile_cannotForward_sendIntent() throws Exception {
195         sComponentName = FORWARD_TO_MANAGED_PROFILE_COMPONENT_NAME;
196 
197         // Intent cannot be forwarded.
198         when(mIPm.canForwardTo(
199                 any(Intent.class), nullable(String.class), anyInt(), anyInt())).thenReturn(false);
200 
201         // Managed profile exists.
202         List<UserInfo> profiles = new ArrayList<>();
203         profiles.add(CURRENT_USER_INFO);
204         profiles.add(MANAGED_PROFILE_INFO);
205         when(mUserManager.getProfiles(anyInt())).thenReturn(profiles);
206 
207         // Create ACTION_SEND intent.
208         Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class);
209         intent.setAction(Intent.ACTION_SEND);
210         IntentForwarderWrapperActivity activity = mActivityRule.launchActivity(intent);
211 
212         assertNull(activity.mStartActivityIntent);
213     }
214 
215     @Test
forwardToManagedProfile_noManagedProfile_sendIntent()216     public void forwardToManagedProfile_noManagedProfile_sendIntent() throws Exception {
217         sComponentName = FORWARD_TO_MANAGED_PROFILE_COMPONENT_NAME;
218 
219         // Intent can be forwarded.
220         when(mIPm.canForwardTo(
221                 any(Intent.class), anyString(), anyInt(), anyInt())).thenReturn(true);
222 
223         // Managed profile does not exist.
224         List<UserInfo> profiles = new ArrayList<>();
225         profiles.add(CURRENT_USER_INFO);
226         when(mUserManager.getProfiles(anyInt())).thenReturn(profiles);
227 
228         // Create ACTION_SEND intent.
229         Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class);
230         intent.setAction(Intent.ACTION_SEND);
231         IntentForwarderWrapperActivity activity = mActivityRule.launchActivity(intent);
232 
233         assertNull(activity.mStartActivityIntent);
234     }
235 
236     @Test
launchInSameProfile_chooserIntent()237     public void launchInSameProfile_chooserIntent() {
238         sComponentName = FORWARD_TO_MANAGED_PROFILE_COMPONENT_NAME;
239 
240         // Manage profile exists.
241         List<UserInfo> profiles = new ArrayList<>();
242         profiles.add(CURRENT_USER_INFO);
243         profiles.add(MANAGED_PROFILE_INFO);
244         when(mUserManager.getProfiles(anyInt())).thenReturn(profiles);
245 
246         // Create chooser Intent
247         Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class);
248         intent.setAction(Intent.ACTION_CHOOSER);
249         Intent sendIntent = new Intent(Intent.ACTION_SEND);
250         sendIntent.setComponent(new ComponentName("xx", "yyy"));
251         sendIntent.setType(TYPE_PLAIN_TEXT);
252         intent.putExtra(Intent.EXTRA_INTENT, sendIntent);
253         IntentForwarderWrapperActivity activity = mActivityRule.launchActivity(intent);
254 
255         assertNotNull(activity.mStartActivityIntent);
256         assertEquals(Intent.ACTION_CHOOSER, activity.mStartActivityIntent.getAction());
257         assertNull(activity.mStartActivityIntent.getPackage());
258         assertNull(activity.mStartActivityIntent.getComponent());
259 
260         Intent innerIntent = activity.mStartActivityIntent.getParcelableExtra(Intent.EXTRA_INTENT);
261         assertNotNull(innerIntent);
262         assertEquals(Intent.ACTION_SEND, innerIntent.getAction());
263         assertNull(innerIntent.getComponent());
264         assertNull(innerIntent.getPackage());
265         assertEquals(UserHandle.USER_CURRENT, innerIntent.getContentUserHint());
266 
267         assertEquals(CURRENT_USER_INFO.id, activity.mUserIdActivityLaunchedIn);
268     }
269 
270     @Test
forwardToManagedProfile_canForward_selectorIntent()271     public void forwardToManagedProfile_canForward_selectorIntent() throws Exception {
272         sComponentName = FORWARD_TO_MANAGED_PROFILE_COMPONENT_NAME;
273         sActivityName = "MyTestActivity";
274         sPackageName = "test.package.name";
275 
276         // Intent can be forwarded.
277         when(mIPm.canForwardTo(
278                 any(Intent.class), nullable(String.class), anyInt(), anyInt())).thenReturn(true);
279 
280         // Manage profile exists.
281         List<UserInfo> profiles = new ArrayList<>();
282         profiles.add(CURRENT_USER_INFO);
283         profiles.add(MANAGED_PROFILE_INFO);
284         when(mUserManager.getProfiles(anyInt())).thenReturn(profiles);
285 
286         // Create selector intent.
287         Intent intent = Intent.makeMainSelectorActivity(
288                 Intent.ACTION_VIEW, Intent.CATEGORY_BROWSABLE);
289 
290         IntentForwarderWrapperActivity activity = mActivityRule.launchActivity(intent);
291 
292         ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
293         verify(mIPm).canForwardTo(
294                 intentCaptor.capture(), nullable(String.class), anyInt(), anyInt());
295         assertEquals(Intent.ACTION_VIEW, intentCaptor.getValue().getAction());
296 
297         InstrumentationRegistry.getInstrumentation().waitForIdleSync();
298         onView(withId(R.id.icon)).check(matches(isDisplayed()));
299         onView(withId(R.id.open_cross_profile)).check(matches(isDisplayed()));
300         onView(withId(R.id.use_same_profile_browser)).check(matches(isDisplayed()));
301         onView(withId(R.id.button_open)).perform(click());
302         InstrumentationRegistry.getInstrumentation().waitForIdleSync();
303 
304         assertNotNull(activity.mStartActivityIntent);
305         assertEquals(Intent.ACTION_MAIN, activity.mStartActivityIntent.getAction());
306         assertNull(activity.mStartActivityIntent.getPackage());
307         assertNull(activity.mStartActivityIntent.getComponent());
308         assertEquals(CURRENT_USER_INFO.id, activity.mStartActivityIntent.getContentUserHint());
309 
310         Intent innerIntent = activity.mStartActivityIntent.getSelector();
311         assertNotNull(innerIntent);
312         assertEquals(Intent.ACTION_VIEW, innerIntent.getAction());
313         assertNull(innerIntent.getComponent());
314         assertNull(innerIntent.getPackage());
315 
316         assertEquals(MANAGED_PROFILE_INFO.id, activity.mUserIdActivityLaunchedIn);
317     }
318 
319     @Test
shouldSkipDisclosure_notWhitelisted()320     public void shouldSkipDisclosure_notWhitelisted() throws RemoteException {
321         setupShouldSkipDisclosureTest();
322         Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class)
323                 .setAction(Intent.ACTION_SEND)
324                 .setType(TYPE_PLAIN_TEXT);
325 
326         mActivityRule.launchActivity(intent);
327 
328         verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt());
329         verify(sInjector).showToast(anyString(), anyInt());
330     }
331 
332     @Test
shouldSkipDisclosure_withResolverActivity()333     public void shouldSkipDisclosure_withResolverActivity() throws RemoteException {
334         setupShouldSkipDisclosureTest();
335         sActivityName = ResolverActivity.class.getName();
336         sPackageName = "android";
337         Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class)
338                 .setAction(Intent.ACTION_SEND)
339                 .setType(TYPE_PLAIN_TEXT);
340 
341         mActivityRule.launchActivity(intent);
342 
343         verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt());
344         verify(sInjector, never()).showToast(anyString(), anyInt());
345     }
346 
347     @Test
shouldSkipDisclosure_callIntent_call()348     public void shouldSkipDisclosure_callIntent_call() throws RemoteException {
349         setupShouldSkipDisclosureTest();
350         Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class)
351                 .setAction(Intent.ACTION_CALL);
352 
353         mActivityRule.launchActivity(intent);
354 
355         verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt());
356         verify(sInjector, never()).showToast(anyString(), anyInt());
357     }
358 
359     @Test
shouldSkipDisclosure_callIntent_callPrivileged()360     public void shouldSkipDisclosure_callIntent_callPrivileged() throws RemoteException {
361         setupShouldSkipDisclosureTest();
362         Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class)
363                 .setAction(Intent.ACTION_CALL_PRIVILEGED);
364 
365         mActivityRule.launchActivity(intent);
366 
367         verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt());
368         verify(sInjector, never()).showToast(anyString(), anyInt());
369     }
370 
371     @Test
shouldSkipDisclosure_callIntent_callEmergency()372     public void shouldSkipDisclosure_callIntent_callEmergency() throws RemoteException {
373         setupShouldSkipDisclosureTest();
374         Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class)
375                 .setAction(Intent.ACTION_CALL_EMERGENCY);
376 
377         mActivityRule.launchActivity(intent);
378 
379         verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt());
380         verify(sInjector, never()).showToast(anyString(), anyInt());
381     }
382 
383     @Test
shouldSkipDisclosure_callIntent_dial()384     public void shouldSkipDisclosure_callIntent_dial() throws RemoteException {
385         setupShouldSkipDisclosureTest();
386         Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class)
387                 .setAction(Intent.ACTION_DIAL);
388 
389         mActivityRule.launchActivity(intent);
390 
391         verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt());
392         verify(sInjector, never()).showToast(anyString(), anyInt());
393     }
394 
395     @Test
shouldSkipDisclosure_callIntent_notCallOrDial()396     public void shouldSkipDisclosure_callIntent_notCallOrDial() throws RemoteException {
397         setupShouldSkipDisclosureTest();
398         Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class)
399                 .setAction(Intent.ACTION_ALARM_CHANGED);
400 
401         mActivityRule.launchActivity(intent);
402 
403         verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt());
404         verify(sInjector).showToast(anyString(), anyInt());
405     }
406 
407     @Test
shouldSkipDisclosure_callIntent_actionViewTel()408     public void shouldSkipDisclosure_callIntent_actionViewTel() throws RemoteException {
409         setupShouldSkipDisclosureTest();
410         Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class)
411                 .setAction(Intent.ACTION_VIEW)
412                 .addCategory(Intent.CATEGORY_BROWSABLE)
413                 .setData(Uri.fromParts("tel", PHONE_NUMBER, null));
414 
415         mActivityRule.launchActivity(intent);
416 
417         verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt());
418         verify(sInjector, never()).showToast(anyString(), anyInt());
419     }
420 
421     @Test
shouldSkipDisclosure_textMessageIntent_sms()422     public void shouldSkipDisclosure_textMessageIntent_sms() throws RemoteException {
423         setupShouldSkipDisclosureTest();
424         Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class)
425                 .setAction(Intent.ACTION_SENDTO)
426                 .setData(Uri.fromParts("sms", PHONE_NUMBER, null));
427 
428         mActivityRule.launchActivity(intent);
429 
430         verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt());
431         verify(sInjector, never()).showToast(anyString(), anyInt());
432     }
433 
434     @Test
shouldSkipDisclosure_textMessageIntent_smsto()435     public void shouldSkipDisclosure_textMessageIntent_smsto() throws RemoteException {
436         setupShouldSkipDisclosureTest();
437         Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class)
438                 .setAction(Intent.ACTION_SENDTO)
439                 .setData(Uri.fromParts("smsto", PHONE_NUMBER, null));
440 
441         mActivityRule.launchActivity(intent);
442 
443         verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt());
444         verify(sInjector, never()).showToast(anyString(), anyInt());
445     }
446 
447     @Test
shouldSkipDisclosure_textMessageIntent_mms()448     public void shouldSkipDisclosure_textMessageIntent_mms() throws RemoteException {
449         setupShouldSkipDisclosureTest();
450         Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class)
451                 .setAction(Intent.ACTION_SENDTO)
452                 .setData(Uri.fromParts("mms", PHONE_NUMBER, null));
453 
454         mActivityRule.launchActivity(intent);
455 
456         verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt());
457         verify(sInjector, never()).showToast(anyString(), anyInt());
458     }
459 
460     @Test
shouldSkipDisclosure_textMessageIntent_mmsto()461     public void shouldSkipDisclosure_textMessageIntent_mmsto() throws RemoteException {
462         setupShouldSkipDisclosureTest();
463         Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class)
464                 .setAction(Intent.ACTION_SENDTO)
465                 .setData(Uri.fromParts("mmsto", PHONE_NUMBER, null));
466 
467         mActivityRule.launchActivity(intent);
468 
469         verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt());
470         verify(sInjector, never()).showToast(anyString(), anyInt());
471     }
472 
473     @Test
shouldSkipDisclosure_textMessageIntent_actionViewSms()474     public void shouldSkipDisclosure_textMessageIntent_actionViewSms() throws RemoteException {
475         setupShouldSkipDisclosureTest();
476         Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class)
477                 .setAction(Intent.ACTION_VIEW)
478                 .addCategory(Intent.CATEGORY_BROWSABLE)
479                 .setData(Uri.fromParts("sms", PHONE_NUMBER, null));
480 
481         mActivityRule.launchActivity(intent);
482 
483         verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt());
484         verify(sInjector, never()).showToast(anyString(), anyInt());
485     }
486 
487     @Test
shouldSkipDisclosure_textMessageIntent_actionViewSmsto()488     public void shouldSkipDisclosure_textMessageIntent_actionViewSmsto() throws RemoteException {
489         setupShouldSkipDisclosureTest();
490         Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class)
491                 .setAction(Intent.ACTION_VIEW)
492                 .addCategory(Intent.CATEGORY_BROWSABLE)
493                 .setData(Uri.fromParts("smsto", PHONE_NUMBER, null));
494 
495         mActivityRule.launchActivity(intent);
496 
497         verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt());
498         verify(sInjector, never()).showToast(anyString(), anyInt());
499     }
500 
501     @Test
shouldSkipDisclosure_textMessageIntent_actionViewMms()502     public void shouldSkipDisclosure_textMessageIntent_actionViewMms() throws RemoteException {
503         setupShouldSkipDisclosureTest();
504         Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class)
505                 .setAction(Intent.ACTION_VIEW)
506                 .addCategory(Intent.CATEGORY_BROWSABLE)
507                 .setData(Uri.fromParts("mms", PHONE_NUMBER, null));
508 
509         mActivityRule.launchActivity(intent);
510 
511         verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt());
512         verify(sInjector, never()).showToast(anyString(), anyInt());
513     }
514 
515     @Test
shouldSkipDisclosure_textMessageIntent_actionViewMmsto()516     public void shouldSkipDisclosure_textMessageIntent_actionViewMmsto() throws RemoteException {
517         setupShouldSkipDisclosureTest();
518         Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class)
519                 .setAction(Intent.ACTION_VIEW)
520                 .addCategory(Intent.CATEGORY_BROWSABLE)
521                 .setData(Uri.fromParts("mmsto", PHONE_NUMBER, null));
522 
523         mActivityRule.launchActivity(intent);
524 
525         verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt());
526         verify(sInjector, never()).showToast(anyString(), anyInt());
527     }
528 
529     @Test
shouldSkipDisclosure_textMessageIntent_invalidUri()530     public void shouldSkipDisclosure_textMessageIntent_invalidUri() throws RemoteException {
531         setupShouldSkipDisclosureTest();
532         Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class)
533                 .setAction(Intent.ACTION_SENDTO)
534                 .setData(Uri.fromParts("invalid", PHONE_NUMBER, null));
535 
536         mActivityRule.launchActivity(intent);
537 
538         verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt());
539         verify(sInjector).showToast(anyString(), anyInt());
540     }
541 
542     @Test
shouldSkipDisclosure_viewBrowsableIntent_invalidUri()543     public void shouldSkipDisclosure_viewBrowsableIntent_invalidUri() throws RemoteException {
544         setupShouldSkipDisclosureTest();
545         Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class)
546                 .setAction(Intent.ACTION_VIEW)
547                 .addCategory(Intent.CATEGORY_BROWSABLE)
548                 .setData(Uri.fromParts("invalid", PHONE_NUMBER, null));
549 
550         mActivityRule.launchActivity(intent);
551 
552         verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt());
553         verify(sInjector).showToast(anyString(), anyInt());
554     }
555 
556     @Test
shouldSkipDisclosure_viewBrowsableIntent_normalUrl()557     public void shouldSkipDisclosure_viewBrowsableIntent_normalUrl() throws RemoteException {
558         setupShouldSkipDisclosureTest();
559         Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class)
560                 .setAction(Intent.ACTION_VIEW)
561                 .addCategory(Intent.CATEGORY_BROWSABLE)
562                 .setData(Uri.fromParts("http", "apache.org", null));
563 
564         mActivityRule.launchActivity(intent);
565 
566         verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt());
567         verify(sInjector).showToast(anyString(), anyInt());
568     }
569 
570     @Test
shouldSkipDisclosure_duringDeviceSetup()571     public void shouldSkipDisclosure_duringDeviceSetup() throws RemoteException {
572         setupShouldSkipDisclosureTest();
573         Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.DEVICE_PROVISIONED,
574                 /* value= */ 0);
575         Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class)
576                 .setAction(Intent.ACTION_VIEW)
577                 .addCategory(Intent.CATEGORY_BROWSABLE)
578                 .setData(Uri.fromParts("http", "apache.org", null));
579 
580         mActivityRule.launchActivity(intent);
581 
582         verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt());
583         verify(sInjector, never()).showToast(anyString(), anyInt());
584     }
585 
586     @Test
forwardToManagedProfile_LoggingTest()587     public void forwardToManagedProfile_LoggingTest() throws Exception {
588         sComponentName = FORWARD_TO_MANAGED_PROFILE_COMPONENT_NAME;
589 
590         // Intent can be forwarded.
591         when(mIPm.canForwardTo(
592                 any(Intent.class), nullable(String.class), anyInt(), anyInt())).thenReturn(true);
593 
594         // Managed profile exists.
595         List<UserInfo> profiles = new ArrayList<>();
596         profiles.add(CURRENT_USER_INFO);
597         profiles.add(MANAGED_PROFILE_INFO);
598         when(mUserManager.getProfiles(anyInt())).thenReturn(profiles);
599 
600         Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class);
601         intent.setAction(Intent.ACTION_SEND);
602         intent.setType(TYPE_PLAIN_TEXT);
603         IntentForwarderWrapperActivity activity = mActivityRule.launchActivity(intent);
604 
605         ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
606         verify(activity.getMetricsLogger()).write(logMakerCaptor.capture());
607         assertEquals(MetricsEvent.ACTION_SWITCH_SHARE_PROFILE,
608                 logMakerCaptor.getValue().getCategory());
609         assertEquals(MetricsEvent.MANAGED_PROFILE,
610                 logMakerCaptor.getValue().getSubtype());
611     }
612 
613     @Test
forwardToParent_LoggingTest()614     public void forwardToParent_LoggingTest() throws Exception {
615         sComponentName = FORWARD_TO_PARENT_COMPONENT_NAME;
616 
617         // Intent can be forwarded.
618         when(mIPm.canForwardTo(
619                 any(Intent.class), nullable(String.class), anyInt(), anyInt())).thenReturn(true);
620 
621         // Managed profile exists.
622         List<UserInfo> profiles = new ArrayList<>();
623         profiles.add(CURRENT_USER_INFO);
624         profiles.add(MANAGED_PROFILE_INFO);
625         when(mUserManager.getProfiles(anyInt())).thenReturn(profiles);
626 
627         Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class);
628         intent.setAction(Intent.ACTION_SEND);
629         intent.setType(TYPE_PLAIN_TEXT);
630         IntentForwarderWrapperActivity activity = mActivityRule.launchActivity(intent);
631 
632         ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
633         verify(activity.getMetricsLogger()).write(logMakerCaptor.capture());
634         assertEquals(MetricsEvent.ACTION_SWITCH_SHARE_PROFILE,
635                 logMakerCaptor.getValue().getCategory());
636         assertEquals(MetricsEvent.PARENT_PROFILE,
637                 logMakerCaptor.getValue().getSubtype());
638     }
639 
640     @Test
shouldForwardToParent_telephony_privateProfile()641     public void shouldForwardToParent_telephony_privateProfile() throws Exception {
642         mSetFlagsRule.enableFlags(
643                 android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE,
644                 android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES,
645                 android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_INTENT_REDIRECTION);
646 
647         sComponentName = FORWARD_TO_PARENT_COMPONENT_NAME;
648         when(mIPm.canForwardTo(
649                 any(Intent.class), nullable(String.class), anyInt(), anyInt())).thenReturn(true);
650 
651         List<UserInfo> profiles = new ArrayList<>();
652         profiles.add(CURRENT_USER_INFO);
653         profiles.add(PRIVATE_PROFILE_INFO);
654         when(mUserManager.getProfiles(anyInt())).thenReturn(profiles);
655         when(mUserManager.getProfileParent(anyInt())).thenReturn(CURRENT_USER_INFO);
656         Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class);
657         intent.setAction(Intent.ACTION_DIAL);
658         IntentForwarderWrapperActivity activity = mActivityRule.launchActivity(intent);
659         verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt());
660         assertEquals(activity.getStartActivityIntent().getAction(), intent.getAction());
661         assertEquals(activity.getUserIdActivityLaunchedIn(), CURRENT_USER_INFO.id);
662     }
663 
664     @Test
shouldForwardToParent_mms_privateProfile()665     public void shouldForwardToParent_mms_privateProfile() throws Exception {
666         mSetFlagsRule.enableFlags(
667                 android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE,
668                 android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_INTENT_REDIRECTION);
669 
670         sComponentName = FORWARD_TO_PARENT_COMPONENT_NAME;
671         when(mIPm.canForwardTo(
672                 any(Intent.class), nullable(String.class), anyInt(), anyInt())).thenReturn(true);
673 
674         List<UserInfo> profiles = new ArrayList<>();
675         profiles.add(CURRENT_USER_INFO);
676         profiles.add(PRIVATE_PROFILE_INFO);
677         when(mUserManager.getProfiles(anyInt())).thenReturn(profiles);
678         when(mUserManager.getProfileParent(anyInt())).thenReturn(CURRENT_USER_INFO);
679         Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class);
680         intent.setAction(Intent.ACTION_SEND);
681         intent.setType(TYPE_PLAIN_TEXT);
682         IntentForwarderWrapperActivity activity = mActivityRule.launchActivity(intent);
683         verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt());
684         assertEquals(activity.getStartActivityIntent().getAction(), intent.getAction());
685         assertEquals(activity.getStartActivityIntent().getType(), intent.getType());
686         assertEquals(activity.getUserIdActivityLaunchedIn(), CURRENT_USER_INFO.id);
687     }
688 
setupShouldSkipDisclosureTest()689     private void setupShouldSkipDisclosureTest() throws RemoteException {
690         sComponentName = FORWARD_TO_PARENT_COMPONENT_NAME;
691         sActivityName = "MyTestActivity";
692         sPackageName = "test.package.name";
693         Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.DEVICE_PROVISIONED,
694                 /* value= */ 1);
695         when(mApplicationInfo.isSystemApp()).thenReturn(true);
696         // Managed profile exists.
697         List<UserInfo> profiles = new ArrayList<>();
698         profiles.add(CURRENT_USER_INFO);
699         profiles.add(MANAGED_PROFILE_INFO);
700         when(mUserManager.getProfiles(anyInt())).thenReturn(profiles);
701         when(mUserManager.getProfileParent(anyInt())).thenReturn(CURRENT_USER_INFO);
702         // Intent can be forwarded.
703         when(mIPm.canForwardTo(
704                 any(Intent.class), nullable(String.class), anyInt(), anyInt())).thenReturn(true);
705     }
706 
707     public static class IntentForwarderWrapperActivity extends IntentForwarderActivity {
708 
709         private Intent mStartActivityIntent;
710         private int mUserIdActivityLaunchedIn;
711         private MetricsLogger mMetricsLogger = mock(MetricsLogger.class);
712 
713         @Override
onCreate(@ullable Bundle savedInstanceState)714         public void onCreate(@Nullable Bundle savedInstanceState) {
715             getIntent().setComponent(sComponentName);
716             super.onCreate(savedInstanceState);
717             try {
718                 mExecutorService.awaitTermination(/* timeout= */ 30, TimeUnit.SECONDS);
719             } catch (InterruptedException e) {
720                 e.printStackTrace();
721             }
722         }
723 
724         @Override
createInjector()725         protected Injector createInjector() {
726             return sInjector;
727         }
728 
729         @Override
startActivityAsCaller(Intent intent, @Nullable Bundle options, boolean ignoreTargetSecurity, int userId)730         public void startActivityAsCaller(Intent intent, @Nullable Bundle options,
731                 boolean ignoreTargetSecurity, int userId) {
732             mStartActivityIntent = intent;
733             mUserIdActivityLaunchedIn = userId;
734         }
735 
736         @Override
createContextAsUser(UserHandle user, int flags)737         public Context createContextAsUser(UserHandle user, int flags) {
738             return this;
739         }
740 
741         @Override
getMetricsLogger()742         protected MetricsLogger getMetricsLogger() {
743             return mMetricsLogger;
744         }
745 
getStartActivityIntent()746         Intent getStartActivityIntent() {
747             return mStartActivityIntent;
748         }
749 
getUserIdActivityLaunchedIn()750         int getUserIdActivityLaunchedIn() {
751             return mUserIdActivityLaunchedIn;
752         }
753     }
754 
755     public class TestInjector implements IntentForwarderActivity.Injector {
756 
757         @Override
getIPackageManager()758         public IPackageManager getIPackageManager() {
759             return mIPm;
760         }
761 
762         @Override
getUserManager()763         public UserManager getUserManager() {
764             return mUserManager;
765         }
766 
767         @Override
getPackageManager()768         public PackageManager getPackageManager() {
769             return mPm;
770         }
771 
772         @Override
resolveActivityAsUser( Intent intent, int flags, int userId)773         public CompletableFuture<ResolveInfo> resolveActivityAsUser(
774                 Intent intent, int flags, int userId) {
775             ActivityInfo activityInfo = new ActivityInfo();
776             activityInfo.packageName = sPackageName;
777             activityInfo.name = sActivityName;
778             activityInfo.applicationInfo = mApplicationInfo;
779 
780             ResolveInfo resolveInfo = new ResolveInfo();
781             resolveInfo.activityInfo = activityInfo;
782 
783             return CompletableFuture.completedFuture(resolveInfo);
784         }
785 
786         @Override
showToast(String message, int duration)787         public void showToast(String message, int duration) {}
788     }
789 }
790