1 /*
2  * Copyright (C) 2021 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.server.pm;
18 
19 import static android.content.pm.PackageManager.ONLY_IF_NO_MATCH_FOUND;
20 import static android.content.pm.PackageManager.SKIP_CURRENT_PROFILE;
21 import static android.speech.RecognizerIntent.ACTION_RECOGNIZE_SPEECH;
22 
23 import static com.android.server.pm.CrossProfileIntentFilter.FLAG_ALLOW_CHAINED_RESOLUTION;
24 import static com.android.server.pm.CrossProfileIntentFilter.FLAG_IS_PACKAGE_FOR_FILTER;
25 
26 import android.content.Intent;
27 import android.hardware.usb.UsbManager;
28 import android.nfc.NfcAdapter;
29 import android.provider.AlarmClock;
30 import android.provider.MediaStore;
31 
32 import java.util.ArrayList;
33 import java.util.Arrays;
34 import java.util.List;
35 
36 /**
37  * Utility Class for {@link DefaultCrossProfileIntentFilter}.
38  */
39 public class DefaultCrossProfileIntentFiltersUtils {
40 
DefaultCrossProfileIntentFiltersUtils()41     private DefaultCrossProfileIntentFiltersUtils() {
42     }
43 
44     // Intents from profile to parent user
45     /** Emergency call intent with mime type is always resolved by primary user. */
46     private static final DefaultCrossProfileIntentFilter
47             EMERGENCY_CALL_MIME =
48             new DefaultCrossProfileIntentFilter.Builder(
49                     DefaultCrossProfileIntentFilter.Direction.TO_PARENT,
50                     SKIP_CURRENT_PROFILE,
51                     /* letsPersonalDataIntoProfile= */ false)
52                     .addAction(Intent.ACTION_CALL_EMERGENCY)
53                     .addAction(Intent.ACTION_CALL_PRIVILEGED)
54                     .addCategory(Intent.CATEGORY_DEFAULT)
55                     .addCategory(Intent.CATEGORY_BROWSABLE)
56                     .addDataType("vnd.android.cursor.item/phone")
57                     .addDataType("vnd.android.cursor.item/phone_v2")
58                     .addDataType("vnd.android.cursor.item/person")
59                     .addDataType("vnd.android.cursor.dir/calls")
60                     .addDataType("vnd.android.cursor.item/calls")
61                     .build();
62 
63     /** Emergency call intent with data schemes is always resolved by primary user. */
64     private static final DefaultCrossProfileIntentFilter
65             EMERGENCY_CALL_DATA =
66             new DefaultCrossProfileIntentFilter.Builder(
67                     DefaultCrossProfileIntentFilter.Direction.TO_PARENT,
68                     SKIP_CURRENT_PROFILE,
69                     /* letsPersonalDataIntoProfile= */ false)
70                     .addAction(Intent.ACTION_CALL_EMERGENCY)
71                     .addAction(Intent.ACTION_CALL_PRIVILEGED)
72                     .addCategory(Intent.CATEGORY_DEFAULT)
73                     .addCategory(Intent.CATEGORY_BROWSABLE)
74                     .addDataScheme("tel")
75                     .addDataScheme("sip")
76                     .addDataScheme("voicemail")
77                     .build();
78 
79     /** Dial intent with mime type can be handled by either managed profile or its parent user. */
80     private static final DefaultCrossProfileIntentFilter DIAL_MIME =
81             new DefaultCrossProfileIntentFilter.Builder(
82                     DefaultCrossProfileIntentFilter.Direction.TO_PARENT,
83                     ONLY_IF_NO_MATCH_FOUND,
84                     /* letsPersonalDataIntoProfile= */ false)
85                     .addAction(Intent.ACTION_DIAL)
86                     .addAction(Intent.ACTION_VIEW)
87                     .addCategory(Intent.CATEGORY_DEFAULT)
88                     .addCategory(Intent.CATEGORY_BROWSABLE)
89                     .addDataType("vnd.android.cursor.item/phone")
90                     .addDataType("vnd.android.cursor.item/phone_v2")
91                     .addDataType("vnd.android.cursor.item/person")
92                     .addDataType("vnd.android.cursor.dir/calls")
93                     .addDataType("vnd.android.cursor.item/calls")
94                     .build();
95 
96     /** Dial intent with mime type exclusively handled by managed profile. */
97     private static final DefaultCrossProfileIntentFilter DIAL_MIME_MANAGED_PROFILE =
98             new DefaultCrossProfileIntentFilter.Builder(
99                     DefaultCrossProfileIntentFilter.Direction.TO_PROFILE,
100                     SKIP_CURRENT_PROFILE,
101                     /* letsPersonalDataIntoProfile= */ false)
102                     .addAction(Intent.ACTION_DIAL)
103                     .addAction(Intent.ACTION_VIEW)
104                     .addCategory(Intent.CATEGORY_DEFAULT)
105                     .addCategory(Intent.CATEGORY_BROWSABLE)
106                     .addDataType("vnd.android.cursor.item/phone")
107                     .addDataType("vnd.android.cursor.item/phone_v2")
108                     .addDataType("vnd.android.cursor.item/person")
109                     .addDataType("vnd.android.cursor.dir/calls")
110                     .addDataType("vnd.android.cursor.item/calls")
111                     .build();
112 
113     /** Dial intent with data scheme can be handled by either managed profile or its parent user. */
114     private static final DefaultCrossProfileIntentFilter DIAL_DATA =
115             new DefaultCrossProfileIntentFilter.Builder(
116                     DefaultCrossProfileIntentFilter.Direction.TO_PARENT,
117                     ONLY_IF_NO_MATCH_FOUND,
118                     /* letsPersonalDataIntoProfile= */ false)
119                     .addAction(Intent.ACTION_DIAL)
120                     .addAction(Intent.ACTION_VIEW)
121                     .addCategory(Intent.CATEGORY_DEFAULT)
122                     .addCategory(Intent.CATEGORY_BROWSABLE)
123                     .addDataScheme("tel")
124                     .addDataScheme("sip")
125                     .addDataScheme("voicemail")
126                     .build();
127 
128     /** Dial intent with data scheme exclusively handled by managed profile. */
129     private static final DefaultCrossProfileIntentFilter DIAL_DATA_MANAGED_PROFILE =
130             new DefaultCrossProfileIntentFilter.Builder(
131                     DefaultCrossProfileIntentFilter.Direction.TO_PROFILE,
132                     SKIP_CURRENT_PROFILE,
133                     /* letsPersonalDataIntoProfile= */ false)
134                     .addAction(Intent.ACTION_DIAL)
135                     .addAction(Intent.ACTION_VIEW)
136                     .addCategory(Intent.CATEGORY_DEFAULT)
137                     .addCategory(Intent.CATEGORY_BROWSABLE)
138                     .addDataScheme("tel")
139                     .addDataScheme("sip")
140                     .addDataScheme("voicemail")
141                     .build();
142 
143     /**
144      * Dial intent with no data scheme or type can be handled by either managed profile or its
145      * parent user.
146      */
147     private static final DefaultCrossProfileIntentFilter DIAL_RAW =
148             new DefaultCrossProfileIntentFilter.Builder(
149                     DefaultCrossProfileIntentFilter.Direction.TO_PARENT,
150                     ONLY_IF_NO_MATCH_FOUND,
151                     /* letsPersonalDataIntoProfile= */ false)
152                     .addAction(Intent.ACTION_DIAL)
153                     .addCategory(Intent.CATEGORY_DEFAULT)
154                     .addCategory(Intent.CATEGORY_BROWSABLE)
155                     .build();
156 
157     /**
158      * Dial intent with no data scheme or type exclusively handled by managed profile.
159      */
160     private static final DefaultCrossProfileIntentFilter DIAL_RAW_MANAGED_PROFILE =
161             new DefaultCrossProfileIntentFilter.Builder(
162                     DefaultCrossProfileIntentFilter.Direction.TO_PROFILE,
163                     SKIP_CURRENT_PROFILE,
164                     /* letsPersonalDataIntoProfile= */ false)
165                     .addAction(Intent.ACTION_DIAL)
166                     .addCategory(Intent.CATEGORY_DEFAULT)
167                     .addCategory(Intent.CATEGORY_BROWSABLE)
168                     .build();
169 
170     /** Pressing the call button can be handled by either managed profile or its parent user. */
171     private static final DefaultCrossProfileIntentFilter CALL_BUTTON =
172             new DefaultCrossProfileIntentFilter.Builder(
173                     DefaultCrossProfileIntentFilter.Direction.TO_PARENT,
174                     ONLY_IF_NO_MATCH_FOUND,
175                     /* letsPersonalDataIntoProfile= */ false)
176                     .addAction(Intent.ACTION_CALL_BUTTON)
177                     .addCategory(Intent.CATEGORY_DEFAULT)
178                     .build();
179 
180     /** SMS and MMS are exclusively handled by the primary user. */
181     private static final DefaultCrossProfileIntentFilter SMS_MMS =
182             new DefaultCrossProfileIntentFilter.Builder(
183                     DefaultCrossProfileIntentFilter.Direction.TO_PARENT,
184                     SKIP_CURRENT_PROFILE,
185                     /* letsPersonalDataIntoProfile= */ false)
186                     .addAction(Intent.ACTION_VIEW)
187                     .addAction(Intent.ACTION_SENDTO)
188                     .addCategory(Intent.CATEGORY_DEFAULT)
189                     .addCategory(Intent.CATEGORY_BROWSABLE)
190                     .addDataScheme("sms")
191                     .addDataScheme("smsto")
192                     .addDataScheme("mms")
193                     .addDataScheme("mmsto")
194                     .build();
195 
196     /** SMS and MMS intent exclusively handled by the managed profile. */
197     private static final DefaultCrossProfileIntentFilter SMS_MMS_MANAGED_PROFILE =
198             new DefaultCrossProfileIntentFilter.Builder(
199                     DefaultCrossProfileIntentFilter.Direction.TO_PROFILE,
200                     SKIP_CURRENT_PROFILE,
201                     /* letsPersonalDataIntoProfile= */ false)
202                     .addAction(Intent.ACTION_VIEW)
203                     .addAction(Intent.ACTION_SENDTO)
204                     .addCategory(Intent.CATEGORY_DEFAULT)
205                     .addCategory(Intent.CATEGORY_BROWSABLE)
206                     .addDataScheme("sms")
207                     .addDataScheme("smsto")
208                     .addDataScheme("mms")
209                     .addDataScheme("mmsto")
210                     .build();
211 
212     /** Mobile network settings is always shown in the primary user. */
213     private static final DefaultCrossProfileIntentFilter
214             MOBILE_NETWORK_SETTINGS =
215             new DefaultCrossProfileIntentFilter.Builder(
216                     DefaultCrossProfileIntentFilter.Direction.TO_PARENT,
217                     SKIP_CURRENT_PROFILE,
218                     /* letsPersonalDataIntoProfile= */ false)
219                     .addAction(android.provider.Settings.ACTION_DATA_ROAMING_SETTINGS)
220                     .addAction(android.provider.Settings.ACTION_NETWORK_OPERATOR_SETTINGS)
221                     .addCategory(Intent.CATEGORY_DEFAULT)
222                     .build();
223 
224     /** HOME intent is always resolved by the primary user. */
225     static final DefaultCrossProfileIntentFilter HOME =
226             new DefaultCrossProfileIntentFilter.Builder(
227                     DefaultCrossProfileIntentFilter.Direction.TO_PARENT,
228                     SKIP_CURRENT_PROFILE,
229                     /* letsPersonalDataIntoProfile= */ false)
230                     .addAction(Intent.ACTION_MAIN)
231                     .addCategory(Intent.CATEGORY_DEFAULT)
232                     .addCategory(Intent.CATEGORY_HOME)
233                     .build();
234 
235     /** Get content can be forwarded to parent user. */
236     private static final DefaultCrossProfileIntentFilter GET_CONTENT =
237             new DefaultCrossProfileIntentFilter.Builder(
238                     DefaultCrossProfileIntentFilter.Direction.TO_PARENT,
239                     /* flags= */0,
240                     /* letsPersonalDataIntoProfile= */ true)
241                     .addAction(Intent.ACTION_GET_CONTENT)
242                     .addCategory(Intent.CATEGORY_DEFAULT)
243                     .addCategory(Intent.CATEGORY_OPENABLE)
244                     .addDataType("*/*")
245                     .build();
246 
247     /** Pick images can be forwarded to parent user. */
248     private static final DefaultCrossProfileIntentFilter ACTION_PICK_IMAGES =
249             new DefaultCrossProfileIntentFilter.Builder(
250                     DefaultCrossProfileIntentFilter.Direction.TO_PARENT,
251                     /* flags= */ 0,
252                     /* letsPersonalDataIntoProfile= */ true)
253                     .addAction(MediaStore.ACTION_PICK_IMAGES)
254                     .addCategory(Intent.CATEGORY_DEFAULT)
255                     .build();
256     /** Pick images can be forwarded to parent user. */
257     private static final DefaultCrossProfileIntentFilter ACTION_PICK_IMAGES_WITH_DATA_TYPES =
258             new DefaultCrossProfileIntentFilter.Builder(
259                     DefaultCrossProfileIntentFilter.Direction.TO_PARENT,
260                     /* flags= */ 0,
261                     /* letsPersonalDataIntoProfile= */ true)
262                     .addAction(MediaStore.ACTION_PICK_IMAGES)
263                     .addCategory(Intent.CATEGORY_DEFAULT)
264                     .addDataType("image/*")
265                     .addDataType("video/*")
266                     .build();
267 
268     /** Open document intent can be forwarded to parent user. */
269     private static final DefaultCrossProfileIntentFilter OPEN_DOCUMENT =
270             new DefaultCrossProfileIntentFilter.Builder(
271                     DefaultCrossProfileIntentFilter.Direction.TO_PARENT,
272                     /* flags= */0,
273                     /* letsPersonalDataIntoProfile= */ true)
274                     .addAction(Intent.ACTION_OPEN_DOCUMENT)
275                     .addCategory(Intent.CATEGORY_DEFAULT)
276                     .addCategory(Intent.CATEGORY_OPENABLE)
277                     .addDataType("*/*")
278                     .build();
279 
280     /** Pick for any data type can be forwarded to parent user. */
281     private static final DefaultCrossProfileIntentFilter ACTION_PICK_DATA =
282             new DefaultCrossProfileIntentFilter.Builder(
283                     DefaultCrossProfileIntentFilter.Direction.TO_PARENT,
284                     /* flags= */0,
285                     /* letsPersonalDataIntoProfile= */ true)
286                     .addAction(Intent.ACTION_PICK)
287                     .addCategory(Intent.CATEGORY_DEFAULT)
288                     .addDataType("*/*")
289                     .build();
290 
291     /** Pick without data type can be forwarded to parent user. */
292     private static final DefaultCrossProfileIntentFilter ACTION_PICK_RAW =
293             new DefaultCrossProfileIntentFilter.Builder(
294                     DefaultCrossProfileIntentFilter.Direction.TO_PARENT,
295                     /* flags= */0,
296                     /* letsPersonalDataIntoProfile= */ true)
297                     .addAction(Intent.ACTION_PICK)
298                     .addCategory(Intent.CATEGORY_DEFAULT)
299                     .build();
300 
301     /** Speech recognition can be performed by primary user. */
302     private static final DefaultCrossProfileIntentFilter RECOGNIZE_SPEECH =
303             new DefaultCrossProfileIntentFilter.Builder(
304                     DefaultCrossProfileIntentFilter.Direction.TO_PARENT,
305                     /* flags= */ ONLY_IF_NO_MATCH_FOUND,
306                     /* letsPersonalDataIntoProfile= */ false)
307                     .addAction(ACTION_RECOGNIZE_SPEECH)
308                     .addCategory(Intent.CATEGORY_DEFAULT)
309                     .build();
310 
311     /** Media capture can be performed by primary user. */
312     private static final DefaultCrossProfileIntentFilter MEDIA_CAPTURE =
313             new DefaultCrossProfileIntentFilter.Builder(
314                     DefaultCrossProfileIntentFilter.Direction.TO_PARENT,
315                     /* flags= */ ONLY_IF_NO_MATCH_FOUND,
316                     /* letsPersonalDataIntoProfile= */ true)
317                     .addAction(MediaStore.ACTION_IMAGE_CAPTURE)
318                     .addAction(MediaStore.ACTION_IMAGE_CAPTURE_SECURE)
319                     .addAction(MediaStore.ACTION_VIDEO_CAPTURE)
320                     .addAction(MediaStore.Audio.Media.RECORD_SOUND_ACTION)
321                     .addAction(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA)
322                     .addAction(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE)
323                     .addAction(MediaStore.INTENT_ACTION_VIDEO_CAMERA)
324                     .addCategory(Intent.CATEGORY_DEFAULT)
325                     .build();
326 
327     /** Alarm setting can be performed by primary user. */
328     private static final DefaultCrossProfileIntentFilter SET_ALARM =
329             new DefaultCrossProfileIntentFilter.Builder(
330                     DefaultCrossProfileIntentFilter.Direction.TO_PARENT,
331                     /* flags= */0,
332                     /* letsPersonalDataIntoProfile= */ false)
333                     .addAction(AlarmClock.ACTION_SET_ALARM)
334                     .addAction(AlarmClock.ACTION_SHOW_ALARMS)
335                     .addAction(AlarmClock.ACTION_SET_TIMER)
336                     .addCategory(Intent.CATEGORY_DEFAULT)
337                     .build();
338 
339     // Intents from parent to profile user
340 
341     /** ACTION_SEND can be forwarded to the managed profile on user's choice. */
342     private static final DefaultCrossProfileIntentFilter ACTION_SEND =
343             new DefaultCrossProfileIntentFilter.Builder(
344                     DefaultCrossProfileIntentFilter.Direction.TO_PROFILE,
345                     /* flags= */0,
346                     /* letsPersonalDataIntoProfile= */ true)
347                     .addAction(Intent.ACTION_SEND)
348                     .addAction(Intent.ACTION_SEND_MULTIPLE)
349                     .addCategory(Intent.CATEGORY_DEFAULT)
350                     .addDataType("*/*")
351                     .build();
352 
353     /** USB devices attached can get forwarded to the profile. */
354     private static final DefaultCrossProfileIntentFilter
355             USB_DEVICE_ATTACHED =
356             new DefaultCrossProfileIntentFilter.Builder(
357                     DefaultCrossProfileIntentFilter.Direction.TO_PROFILE,
358                     /* flags= */0,
359                     /* letsPersonalDataIntoProfile= */ false)
360                     .addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED)
361                     .addAction(UsbManager.ACTION_USB_ACCESSORY_ATTACHED)
362                     .addCategory(Intent.CATEGORY_DEFAULT)
363                     .build();
364 
365 
getDefaultManagedProfileFilters()366     public static List<DefaultCrossProfileIntentFilter> getDefaultManagedProfileFilters() {
367         List<DefaultCrossProfileIntentFilter> filters =
368                 new ArrayList<DefaultCrossProfileIntentFilter>();
369         filters.addAll(Arrays.asList(
370                 EMERGENCY_CALL_MIME,
371                 EMERGENCY_CALL_DATA,
372                 CALL_BUTTON,
373                 SET_ALARM,
374                 MEDIA_CAPTURE,
375                 RECOGNIZE_SPEECH,
376                 ACTION_PICK_RAW,
377                 ACTION_PICK_DATA,
378                 ACTION_PICK_IMAGES,
379                 ACTION_PICK_IMAGES_WITH_DATA_TYPES,
380                 OPEN_DOCUMENT,
381                 GET_CONTENT,
382                 USB_DEVICE_ATTACHED,
383                 ACTION_SEND,
384                 HOME,
385                 MOBILE_NETWORK_SETTINGS));
386         filters.addAll(getDefaultCrossProfileTelephonyIntentFilters(false));
387         return filters;
388     }
389 
390     /** Call intent with tel scheme exclusively handled my managed profile.
391      * Note that work profile telephony relies on this intent filter to redirect intents to
392      * the IntentForwarderActivity. Work profile telephony error handling must be updated in
393      * the Telecomm package CallsManager if this filter is changed.
394      */
395     private static final DefaultCrossProfileIntentFilter CALL_MANAGED_PROFILE =
396             new DefaultCrossProfileIntentFilter.Builder(
397                     DefaultCrossProfileIntentFilter.Direction.TO_PROFILE,
398                     SKIP_CURRENT_PROFILE,
399                     /* letsPersonalDataIntoProfile= */ false)
400                     .addAction(Intent.ACTION_CALL)
401                     .addCategory(Intent.CATEGORY_DEFAULT)
402                     .addDataScheme("tel")
403                     .build();
404 
405     /**
406      * Returns default telephony related intent filters for managed profile.
407      */
408     public static List<DefaultCrossProfileIntentFilter>
getDefaultCrossProfileTelephonyIntentFilters(boolean telephonyOnlyInManagedProfile)409             getDefaultCrossProfileTelephonyIntentFilters(boolean telephonyOnlyInManagedProfile) {
410         if (telephonyOnlyInManagedProfile) {
411             return Arrays.asList(
412                     DIAL_DATA_MANAGED_PROFILE,
413                     DIAL_MIME_MANAGED_PROFILE,
414                     DIAL_RAW_MANAGED_PROFILE,
415                     CALL_MANAGED_PROFILE,
416                     SMS_MMS_MANAGED_PROFILE);
417         } else {
418             return Arrays.asList(
419                     DIAL_DATA,
420                     DIAL_MIME,
421                     DIAL_RAW,
422                     SMS_MMS);
423         }
424     }
425 
426     /**
427      * Clone profile's DefaultCrossProfileIntentFilter
428      */
429 
430     /*
431      Allowing media capture from clone to parent profile as clone profile would not have camera
432      */
433     private static final DefaultCrossProfileIntentFilter CLONE_TO_PARENT_MEDIA_CAPTURE =
434             new DefaultCrossProfileIntentFilter.Builder(
435                     DefaultCrossProfileIntentFilter.Direction.TO_PARENT,
436                     /* flags= */ 0x00000018, // 0x00000018 means FLAG_IS_PACKAGE_FOR_FILTER
437                                             // and FLAG_ALLOW_CHAINED_RESOLUTION set
438                     /* letsPersonalDataIntoProfile= */ false)
439                     .addAction(MediaStore.ACTION_IMAGE_CAPTURE)
440                     .addAction(MediaStore.ACTION_IMAGE_CAPTURE_SECURE)
441                     .addAction(MediaStore.ACTION_VIDEO_CAPTURE)
442                     .addAction(MediaStore.Audio.Media.RECORD_SOUND_ACTION)
443                     .addAction(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA)
444                     .addAction(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE)
445                     .addAction(MediaStore.INTENT_ACTION_VIDEO_CAMERA)
446                     .addCategory(Intent.CATEGORY_DEFAULT)
447                     .build();
448 
449     private static final DefaultCrossProfileIntentFilter CLONE_TO_PARENT_PHOTOPICKER_SELECTION =
450             new DefaultCrossProfileIntentFilter.Builder(
451                     DefaultCrossProfileIntentFilter.Direction.TO_PARENT,
452                     /* flags= */ 0x00000018, // 0x00000018 means FLAG_IS_PACKAGE_FOR_FILTER
453                     // and FLAG_ALLOW_CHAINED_RESOLUTION set
454                     /* letsPersonalDataIntoProfile= */ false)
455                     .addAction(MediaStore.ACTION_USER_SELECT_IMAGES_FOR_APP)
456                     .addCategory(Intent.CATEGORY_DEFAULT)
457                     .build();
458 
459     /*
460      Allowing send action from clone to parent profile to share content from clone apps to parent
461      apps
462      */
463     private static final DefaultCrossProfileIntentFilter CLONE_TO_PARENT_SEND_ACTION =
464             new DefaultCrossProfileIntentFilter.Builder(
465                     DefaultCrossProfileIntentFilter.Direction.TO_PARENT,
466                     /* flags= */ 0x00000018, // 0x00000018 means FLAG_IS_PACKAGE_FOR_FILTER
467                     // and FLAG_ALLOW_CHAINED_RESOLUTION set
468                     /* letsPersonalDataIntoProfile= */ false)
469                     .addAction(Intent.ACTION_SEND)
470                     .addAction(Intent.ACTION_SEND_MULTIPLE)
471                     .addAction(Intent.ACTION_SENDTO)
472                     .addDataType("*/*")
473                     .build();
474 
475     /*
476      Allowing send action from parent to clone profile to share content from parent apps to clone
477      apps
478      */
479     private static final DefaultCrossProfileIntentFilter PARENT_TO_CLONE_SEND_ACTION =
480             new DefaultCrossProfileIntentFilter.Builder(
481                     DefaultCrossProfileIntentFilter.Direction.TO_PROFILE,
482                     /* flags= */ 0x00000018, // 0x00000018 means FLAG_IS_PACKAGE_FOR_FILTER
483                                             // and FLAG_ALLOW_CHAINED_RESOLUTION set
484                     /* letsPersonalDataIntoProfile= */ false)
485                     .addAction(Intent.ACTION_SEND)
486                     .addAction(Intent.ACTION_SEND_MULTIPLE)
487                     .addAction(Intent.ACTION_SENDTO)
488                     .addDataType("*/*")
489                     .build();
490 
491     /*
492      Allowing view action from clone to parent profile to open any app-links or web links
493      */
494     private static final DefaultCrossProfileIntentFilter CLONE_TO_PARENT_WEB_VIEW_ACTION =
495             new DefaultCrossProfileIntentFilter.Builder(
496                     DefaultCrossProfileIntentFilter.Direction.TO_PARENT,
497                     /* flags= */ 0x00000018, // 0x00000018 means FLAG_IS_PACKAGE_FOR_FILTER
498                     // and FLAG_ALLOW_CHAINED_RESOLUTION set
499                     /* letsPersonalDataIntoProfile= */ false)
500                     .addAction(Intent.ACTION_VIEW)
501                     .addDataScheme("https")
502                     .addDataScheme("http")
503                     .build();
504 
505     /*
506      Allowing view action from parent to clone profile to open any app-links or web links
507      */
508     private static final DefaultCrossProfileIntentFilter PARENT_TO_CLONE_WEB_VIEW_ACTION =
509             new DefaultCrossProfileIntentFilter.Builder(
510                     DefaultCrossProfileIntentFilter.Direction.TO_PROFILE,
511                     /* flags= */ 0x00000018, // 0x00000018 means FLAG_IS_PACKAGE_FOR_FILTER
512                                             // and FLAG_ALLOW_CHAINED_RESOLUTION set
513                     /* letsPersonalDataIntoProfile= */ false)
514                     .addAction(Intent.ACTION_VIEW)
515                     .addDataScheme("https")
516                     .addDataScheme("http")
517                     .build();
518 
519     /*
520      Allowing view action from clone to parent profile to any data type e.g. pdf, including custom
521      content providers.
522      */
523     private static final DefaultCrossProfileIntentFilter CLONE_TO_PARENT_VIEW_ACTION =
524             new DefaultCrossProfileIntentFilter.Builder(
525                     DefaultCrossProfileIntentFilter.Direction.TO_PARENT,
526                     /* flags= */ 0x00000018, // 0x00000018 means FLAG_IS_PACKAGE_FOR_FILTER
527                     // and FLAG_ALLOW_CHAINED_RESOLUTION set
528                     /* letsPersonalDataIntoProfile= */ false)
529                     .addAction(Intent.ACTION_VIEW)
530                     .addDataType("*/*")
531                     .build();
532 
533 
534     /*
535      Allowing pick,insert and edit action from clone to parent profile to open picker or contacts
536      insert/edit.
537      */
538     private static final DefaultCrossProfileIntentFilter CLONE_TO_PARENT_PICK_INSERT_ACTION =
539             new DefaultCrossProfileIntentFilter.Builder(
540                     DefaultCrossProfileIntentFilter.Direction.TO_PARENT,
541                     /* flags= */ 0x00000018, // 0x00000018 means FLAG_IS_PACKAGE_FOR_FILTER
542                                             // and FLAG_ALLOW_CHAINED_RESOLUTION set
543                     /* letsPersonalDataIntoProfile= */ false)
544                     .addAction(Intent.ACTION_PICK)
545                     .addAction(Intent.ACTION_GET_CONTENT)
546                     .addAction(Intent.ACTION_EDIT)
547                     .addAction(Intent.ACTION_INSERT)
548                     .addAction(Intent.ACTION_INSERT_OR_EDIT)
549                     .addAction(Intent.ACTION_OPEN_DOCUMENT)
550                     .addDataType("*/*")
551                     .addCategory(Intent.CATEGORY_DEFAULT)
552                     .addCategory(Intent.CATEGORY_OPENABLE)
553                     .build();
554 
555     /*
556      Allowing pick,insert and edit action from parent to clone profile to open picker
557      */
558     private static final DefaultCrossProfileIntentFilter PARENT_TO_CLONE_PICK_INSERT_ACTION =
559             new DefaultCrossProfileIntentFilter.Builder(
560                     DefaultCrossProfileIntentFilter.Direction.TO_PROFILE,
561                     /* flags= */ 0x00000018, // 0x00000018 means FLAG_IS_PACKAGE_FOR_FILTER
562                                             // and FLAG_ALLOW_CHAINED_RESOLUTION set
563                     /* letsPersonalDataIntoProfile= */ false)
564                     .addAction(Intent.ACTION_PICK)
565                     .addAction(Intent.ACTION_GET_CONTENT)
566                     .addAction(Intent.ACTION_EDIT)
567                     .addAction(Intent.ACTION_INSERT)
568                     .addAction(Intent.ACTION_INSERT_OR_EDIT)
569                     .addAction(Intent.ACTION_OPEN_DOCUMENT)
570                     .addDataType("*/*")
571                     .addCategory(Intent.CATEGORY_DEFAULT)
572                     .addCategory(Intent.CATEGORY_OPENABLE)
573                     .build();
574 
575     private static final DefaultCrossProfileIntentFilter PARENT_TO_CLONE_DIAL_DATA =
576             new DefaultCrossProfileIntentFilter.Builder(
577                     DefaultCrossProfileIntentFilter.Direction.TO_PROFILE,
578                     /* flags= */ 0x00000018, // 0x00000018 means FLAG_IS_PACKAGE_FOR_FILTER
579                     // and FLAG_ALLOW_CHAINED_RESOLUTION set
580                     /* letsPersonalDataIntoProfile= */ false)
581                     .addAction(Intent.ACTION_DIAL)
582                     .addAction(Intent.ACTION_VIEW)
583                     .addCategory(Intent.CATEGORY_DEFAULT)
584                     .addCategory(Intent.CATEGORY_BROWSABLE)
585                     .addDataScheme("tel")
586                     .addDataScheme("sip")
587                     .addDataScheme("voicemail")
588                     .build();
589 
590     private static final DefaultCrossProfileIntentFilter CLONE_TO_PARENT_DIAL_DATA =
591             new DefaultCrossProfileIntentFilter.Builder(
592                     DefaultCrossProfileIntentFilter.Direction.TO_PARENT,
593                     /* flags= */ 0x00000018, // 0x00000018 means FLAG_IS_PACKAGE_FOR_FILTER
594                     // and FLAG_ALLOW_CHAINED_RESOLUTION set
595                     /* letsPersonalDataIntoProfile= */ false)
596                     .addAction(Intent.ACTION_DIAL)
597                     .addAction(Intent.ACTION_VIEW)
598                     .addCategory(Intent.CATEGORY_DEFAULT)
599                     .addCategory(Intent.CATEGORY_BROWSABLE)
600                     .addDataScheme("tel")
601                     .addDataScheme("sip")
602                     .addDataScheme("voicemail")
603                     .build();
604 
605     private static final DefaultCrossProfileIntentFilter CLONE_TO_PARENT_SMS_MMS =
606             new DefaultCrossProfileIntentFilter.Builder(
607                     DefaultCrossProfileIntentFilter.Direction.TO_PARENT,
608                     /* flags= */ 0x00000018, // 0x00000018 means FLAG_IS_PACKAGE_FOR_FILTER
609                     // and FLAG_ALLOW_CHAINED_RESOLUTION set
610                     /* letsPersonalDataIntoProfile= */ false)
611                     .addAction(Intent.ACTION_VIEW)
612                     .addAction(Intent.ACTION_SENDTO)
613                     .addCategory(Intent.CATEGORY_DEFAULT)
614                     .addCategory(Intent.CATEGORY_BROWSABLE)
615                     .addDataScheme("sms")
616                     .addDataScheme("smsto")
617                     .addDataScheme("mms")
618                     .addDataScheme("mmsto")
619                     .build();
620 
621     private static final DefaultCrossProfileIntentFilter CLONE_TO_PARENT_ACTION_PICK_IMAGES =
622             new DefaultCrossProfileIntentFilter.Builder(
623                     DefaultCrossProfileIntentFilter.Direction.TO_PARENT,
624                     /* flags= */ FLAG_IS_PACKAGE_FOR_FILTER | FLAG_ALLOW_CHAINED_RESOLUTION,
625                     /* letsPersonalDataIntoProfile= */ false)
626                     .addAction(MediaStore.ACTION_PICK_IMAGES)
627                     .addCategory(Intent.CATEGORY_DEFAULT)
628                     .build();
629 
630     private static final DefaultCrossProfileIntentFilter
631             CLONE_TO_PARENT_ACTION_PICK_IMAGES_WITH_DATA_TYPES =
632             new DefaultCrossProfileIntentFilter.Builder(
633                     DefaultCrossProfileIntentFilter.Direction.TO_PARENT,
634                     /* flags= */ FLAG_IS_PACKAGE_FOR_FILTER | FLAG_ALLOW_CHAINED_RESOLUTION,
635                     /* letsPersonalDataIntoProfile= */ false)
636                     .addAction(MediaStore.ACTION_PICK_IMAGES)
637                     .addCategory(Intent.CATEGORY_DEFAULT)
638                     .addDataType("image/*")
639                     .addDataType("video/*")
640                     .build();
641 
642     /** NFC TAG intent is always resolved by the primary user. */
643     static final DefaultCrossProfileIntentFilter PARENT_TO_CLONE_NFC_TAG_DISCOVERED =
644             new DefaultCrossProfileIntentFilter.Builder(
645                     DefaultCrossProfileIntentFilter.Direction.TO_PROFILE,
646                     /* flags= */0,
647                     /* letsPersonalDataIntoProfile= */ false)
648                     .addAction(NfcAdapter.ACTION_TAG_DISCOVERED)
649                     .build();
650 
651     /** NFC TAG intent is always resolved by the primary user. */
652     static final DefaultCrossProfileIntentFilter PARENT_TO_CLONE_NFC_TECH_DISCOVERED =
653             new DefaultCrossProfileIntentFilter.Builder(
654                     DefaultCrossProfileIntentFilter.Direction.TO_PROFILE,
655                     /* flags= */0,
656                     /* letsPersonalDataIntoProfile= */ false)
657                     .addAction(NfcAdapter.ACTION_TECH_DISCOVERED)
658                     .build();
659 
660     /** NFC TAG intent is always resolved by the primary user. */
661     static final DefaultCrossProfileIntentFilter PARENT_TO_CLONE_NFC_NDEF_DISCOVERED =
662             new DefaultCrossProfileIntentFilter.Builder(
663                     DefaultCrossProfileIntentFilter.Direction.TO_PROFILE,
664                     /* flags= */0,
665                     /* letsPersonalDataIntoProfile= */ false)
666                     .addAction(NfcAdapter.ACTION_NDEF_DISCOVERED)
667                     .build();
668 
getDefaultCloneProfileFilters()669     public static List<DefaultCrossProfileIntentFilter> getDefaultCloneProfileFilters() {
670         return Arrays.asList(
671                 PARENT_TO_CLONE_SEND_ACTION,
672                 PARENT_TO_CLONE_WEB_VIEW_ACTION,
673                 PARENT_TO_CLONE_PICK_INSERT_ACTION,
674                 PARENT_TO_CLONE_DIAL_DATA,
675                 CLONE_TO_PARENT_MEDIA_CAPTURE,
676                 CLONE_TO_PARENT_SEND_ACTION,
677                 CLONE_TO_PARENT_WEB_VIEW_ACTION,
678                 CLONE_TO_PARENT_VIEW_ACTION,
679                 CLONE_TO_PARENT_PICK_INSERT_ACTION,
680                 CLONE_TO_PARENT_DIAL_DATA,
681                 CLONE_TO_PARENT_SMS_MMS,
682                 CLONE_TO_PARENT_PHOTOPICKER_SELECTION,
683                 CLONE_TO_PARENT_ACTION_PICK_IMAGES,
684                 CLONE_TO_PARENT_ACTION_PICK_IMAGES_WITH_DATA_TYPES,
685                 PARENT_TO_CLONE_NFC_TAG_DISCOVERED,
686                 PARENT_TO_CLONE_NFC_TECH_DISCOVERED,
687                 PARENT_TO_CLONE_NFC_NDEF_DISCOVERED
688         );
689     }
690 
691     /** Call intent should be handled by the main user. */
692     private static final DefaultCrossProfileIntentFilter CALL_PRIVATE_PROFILE =
693             new DefaultCrossProfileIntentFilter.Builder(
694                     DefaultCrossProfileIntentFilter.Direction.TO_PARENT,
695                     SKIP_CURRENT_PROFILE,
696                     /* letsPersonalDataIntoProfile= */ false)
697                     .addAction(Intent.ACTION_CALL)
698                     .addCategory(Intent.CATEGORY_DEFAULT)
699                     .addDataScheme("tel")
700                     .addDataScheme("sip")
701                     .addDataScheme("voicemail")
702                     .build();
703 
704     /** Pressing the call button should be handled by the main user. */
705     private static final DefaultCrossProfileIntentFilter CALL_BUTTON_PRIVATE_PROFILE =
706             new DefaultCrossProfileIntentFilter.Builder(
707                     DefaultCrossProfileIntentFilter.Direction.TO_PARENT,
708                     ONLY_IF_NO_MATCH_FOUND,
709                     /* letsPersonalDataIntoProfile= */ false)
710                     .addAction(Intent.ACTION_CALL_BUTTON)
711                     .addCategory(Intent.CATEGORY_DEFAULT)
712                     .build();
713 
714     /** Dial intent with mime type can be handled by either private profile or its parent user. */
715     private static final DefaultCrossProfileIntentFilter DIAL_MIME_PRIVATE_PROFILE =
716             new DefaultCrossProfileIntentFilter.Builder(
717                     DefaultCrossProfileIntentFilter.Direction.TO_PARENT,
718                     ONLY_IF_NO_MATCH_FOUND,
719                     /* letsPersonalDataIntoProfile= */ false)
720                     .addAction(Intent.ACTION_DIAL)
721                     .addAction(Intent.ACTION_VIEW)
722                     .addCategory(Intent.CATEGORY_DEFAULT)
723                     .addCategory(Intent.CATEGORY_BROWSABLE)
724                     .addDataType("vnd.android.cursor.item/phone")
725                     .addDataType("vnd.android.cursor.item/phone_v2")
726                     .addDataType("vnd.android.cursor.item/person")
727                     .addDataType("vnd.android.cursor.dir/calls")
728                     .addDataType("vnd.android.cursor.item/calls")
729                     .build();
730 
731     /** Dial intent with data scheme can be handled by either private profile or its parent user. */
732     private static final DefaultCrossProfileIntentFilter DIAL_DATA_PRIVATE_PROFILE =
733             new DefaultCrossProfileIntentFilter.Builder(
734                     DefaultCrossProfileIntentFilter.Direction.TO_PARENT,
735                     ONLY_IF_NO_MATCH_FOUND,
736                     /* letsPersonalDataIntoProfile= */ false)
737                     .addAction(Intent.ACTION_DIAL)
738                     .addAction(Intent.ACTION_VIEW)
739                     .addCategory(Intent.CATEGORY_DEFAULT)
740                     .addCategory(Intent.CATEGORY_BROWSABLE)
741                     .addDataScheme("tel")
742                     .addDataScheme("sip")
743                     .addDataScheme("voicemail")
744                     .build();
745 
746     /**
747      * Dial intent with no data scheme or type can be handled by either private profile or its
748      * parent user.
749      */
750     private static final DefaultCrossProfileIntentFilter DIAL_RAW_PRIVATE_PROFILE =
751             new DefaultCrossProfileIntentFilter.Builder(
752                     DefaultCrossProfileIntentFilter.Direction.TO_PARENT,
753                     ONLY_IF_NO_MATCH_FOUND,
754                     /* letsPersonalDataIntoProfile= */ false)
755                     .addAction(Intent.ACTION_DIAL)
756                     .addCategory(Intent.CATEGORY_DEFAULT)
757                     .addCategory(Intent.CATEGORY_BROWSABLE)
758                     .build();
759 
760     /** SMS and MMS are always handled in the main user. */
761     private static final DefaultCrossProfileIntentFilter SMS_MMS_PRIVATE_PROFILE =
762             new DefaultCrossProfileIntentFilter.Builder(
763                     DefaultCrossProfileIntentFilter.Direction.TO_PARENT,
764                     SKIP_CURRENT_PROFILE,
765                     /* letsPersonalDataIntoProfile= */ false)
766                     .addAction(Intent.ACTION_VIEW)
767                     .addAction(Intent.ACTION_SENDTO)
768                     .addCategory(Intent.CATEGORY_DEFAULT)
769                     .addCategory(Intent.CATEGORY_BROWSABLE)
770                     .addDataScheme("sms")
771                     .addDataScheme("smsto")
772                     .addDataScheme("mms")
773                     .addDataScheme("mmsto")
774                     .build();
775 
getDefaultPrivateProfileFilters()776     public static List<DefaultCrossProfileIntentFilter> getDefaultPrivateProfileFilters() {
777         return Arrays.asList(
778                 DIAL_MIME_PRIVATE_PROFILE,
779                 DIAL_DATA_PRIVATE_PROFILE,
780                 DIAL_RAW_PRIVATE_PROFILE,
781                 CALL_PRIVATE_PROFILE,
782                 CALL_BUTTON_PRIVATE_PROFILE,
783                 EMERGENCY_CALL_DATA,
784                 EMERGENCY_CALL_MIME,
785                 SMS_MMS_PRIVATE_PROFILE
786         );
787     }
788 }
789