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_MOTION_PHOTO_CAPTURE) 320 .addAction(MediaStore.ACTION_MOTION_PHOTO_CAPTURE_SECURE) 321 .addAction(MediaStore.ACTION_VIDEO_CAPTURE) 322 .addAction(MediaStore.Audio.Media.RECORD_SOUND_ACTION) 323 .addAction(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA) 324 .addAction(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE) 325 .addAction(MediaStore.INTENT_ACTION_VIDEO_CAMERA) 326 .addCategory(Intent.CATEGORY_DEFAULT) 327 .build(); 328 329 /** Alarm setting can be performed by primary user. */ 330 private static final DefaultCrossProfileIntentFilter SET_ALARM = 331 new DefaultCrossProfileIntentFilter.Builder( 332 DefaultCrossProfileIntentFilter.Direction.TO_PARENT, 333 /* flags= */0, 334 /* letsPersonalDataIntoProfile= */ false) 335 .addAction(AlarmClock.ACTION_SET_ALARM) 336 .addAction(AlarmClock.ACTION_SHOW_ALARMS) 337 .addAction(AlarmClock.ACTION_SET_TIMER) 338 .addCategory(Intent.CATEGORY_DEFAULT) 339 .build(); 340 341 // Intents from parent to profile user 342 343 /** ACTION_SEND can be forwarded to the managed profile on user's choice. */ 344 private static final DefaultCrossProfileIntentFilter ACTION_SEND = 345 new DefaultCrossProfileIntentFilter.Builder( 346 DefaultCrossProfileIntentFilter.Direction.TO_PROFILE, 347 /* flags= */0, 348 /* letsPersonalDataIntoProfile= */ true) 349 .addAction(Intent.ACTION_SEND) 350 .addAction(Intent.ACTION_SEND_MULTIPLE) 351 .addCategory(Intent.CATEGORY_DEFAULT) 352 .addDataType("*/*") 353 .build(); 354 355 /** USB devices attached can get forwarded to the profile. */ 356 private static final DefaultCrossProfileIntentFilter 357 USB_DEVICE_ATTACHED = 358 new DefaultCrossProfileIntentFilter.Builder( 359 DefaultCrossProfileIntentFilter.Direction.TO_PROFILE, 360 /* flags= */0, 361 /* letsPersonalDataIntoProfile= */ false) 362 .addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED) 363 .addAction(UsbManager.ACTION_USB_ACCESSORY_ATTACHED) 364 .addCategory(Intent.CATEGORY_DEFAULT) 365 .build(); 366 367 getDefaultManagedProfileFilters()368 public static List<DefaultCrossProfileIntentFilter> getDefaultManagedProfileFilters() { 369 List<DefaultCrossProfileIntentFilter> filters = 370 new ArrayList<DefaultCrossProfileIntentFilter>(); 371 filters.addAll(Arrays.asList( 372 EMERGENCY_CALL_MIME, 373 EMERGENCY_CALL_DATA, 374 CALL_BUTTON, 375 SET_ALARM, 376 MEDIA_CAPTURE, 377 RECOGNIZE_SPEECH, 378 ACTION_PICK_RAW, 379 ACTION_PICK_DATA, 380 ACTION_PICK_IMAGES, 381 ACTION_PICK_IMAGES_WITH_DATA_TYPES, 382 OPEN_DOCUMENT, 383 GET_CONTENT, 384 USB_DEVICE_ATTACHED, 385 ACTION_SEND, 386 HOME, 387 MOBILE_NETWORK_SETTINGS)); 388 filters.addAll(getDefaultCrossProfileTelephonyIntentFilters(false)); 389 return filters; 390 } 391 392 /** Call intent with tel scheme exclusively handled my managed profile. 393 * Note that work profile telephony relies on this intent filter to redirect intents to 394 * the IntentForwarderActivity. Work profile telephony error handling must be updated in 395 * the Telecomm package CallsManager if this filter is changed. 396 */ 397 private static final DefaultCrossProfileIntentFilter CALL_MANAGED_PROFILE = 398 new DefaultCrossProfileIntentFilter.Builder( 399 DefaultCrossProfileIntentFilter.Direction.TO_PROFILE, 400 SKIP_CURRENT_PROFILE, 401 /* letsPersonalDataIntoProfile= */ false) 402 .addAction(Intent.ACTION_CALL) 403 .addCategory(Intent.CATEGORY_DEFAULT) 404 .addDataScheme("tel") 405 .build(); 406 407 /** 408 * Returns default telephony related intent filters for managed profile. 409 */ 410 public static List<DefaultCrossProfileIntentFilter> getDefaultCrossProfileTelephonyIntentFilters(boolean telephonyOnlyInManagedProfile)411 getDefaultCrossProfileTelephonyIntentFilters(boolean telephonyOnlyInManagedProfile) { 412 if (telephonyOnlyInManagedProfile) { 413 return Arrays.asList( 414 DIAL_DATA_MANAGED_PROFILE, 415 DIAL_MIME_MANAGED_PROFILE, 416 DIAL_RAW_MANAGED_PROFILE, 417 CALL_MANAGED_PROFILE, 418 SMS_MMS_MANAGED_PROFILE); 419 } else { 420 return Arrays.asList( 421 DIAL_DATA, 422 DIAL_MIME, 423 DIAL_RAW, 424 SMS_MMS); 425 } 426 } 427 428 /** 429 * Clone profile's DefaultCrossProfileIntentFilter 430 */ 431 432 /* 433 Allowing media capture from clone to parent profile as clone profile would not have camera 434 */ 435 private static final DefaultCrossProfileIntentFilter CLONE_TO_PARENT_MEDIA_CAPTURE = 436 new DefaultCrossProfileIntentFilter.Builder( 437 DefaultCrossProfileIntentFilter.Direction.TO_PARENT, 438 /* flags= */ 0x00000018, // 0x00000018 means FLAG_IS_PACKAGE_FOR_FILTER 439 // and FLAG_ALLOW_CHAINED_RESOLUTION set 440 /* letsPersonalDataIntoProfile= */ false) 441 .addAction(MediaStore.ACTION_IMAGE_CAPTURE) 442 .addAction(MediaStore.ACTION_IMAGE_CAPTURE_SECURE) 443 .addAction(MediaStore.ACTION_MOTION_PHOTO_CAPTURE) 444 .addAction(MediaStore.ACTION_MOTION_PHOTO_CAPTURE_SECURE) 445 .addAction(MediaStore.ACTION_VIDEO_CAPTURE) 446 .addAction(MediaStore.Audio.Media.RECORD_SOUND_ACTION) 447 .addAction(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA) 448 .addAction(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE) 449 .addAction(MediaStore.INTENT_ACTION_VIDEO_CAMERA) 450 .addCategory(Intent.CATEGORY_DEFAULT) 451 .build(); 452 453 private static final DefaultCrossProfileIntentFilter CLONE_TO_PARENT_PHOTOPICKER_SELECTION = 454 new DefaultCrossProfileIntentFilter.Builder( 455 DefaultCrossProfileIntentFilter.Direction.TO_PARENT, 456 /* flags= */ 0x00000018, // 0x00000018 means FLAG_IS_PACKAGE_FOR_FILTER 457 // and FLAG_ALLOW_CHAINED_RESOLUTION set 458 /* letsPersonalDataIntoProfile= */ false) 459 .addAction(MediaStore.ACTION_USER_SELECT_IMAGES_FOR_APP) 460 .addCategory(Intent.CATEGORY_DEFAULT) 461 .build(); 462 463 /* 464 Allowing send action from clone to parent profile to share content from clone apps to parent 465 apps 466 */ 467 private static final DefaultCrossProfileIntentFilter CLONE_TO_PARENT_SEND_ACTION = 468 new DefaultCrossProfileIntentFilter.Builder( 469 DefaultCrossProfileIntentFilter.Direction.TO_PARENT, 470 /* flags= */ 0x00000018, // 0x00000018 means FLAG_IS_PACKAGE_FOR_FILTER 471 // and FLAG_ALLOW_CHAINED_RESOLUTION set 472 /* letsPersonalDataIntoProfile= */ false) 473 .addAction(Intent.ACTION_SEND) 474 .addAction(Intent.ACTION_SEND_MULTIPLE) 475 .addAction(Intent.ACTION_SENDTO) 476 .addDataType("*/*") 477 .build(); 478 479 /* 480 Allowing send action from parent to clone profile to share content from parent apps to clone 481 apps 482 */ 483 private static final DefaultCrossProfileIntentFilter PARENT_TO_CLONE_SEND_ACTION = 484 new DefaultCrossProfileIntentFilter.Builder( 485 DefaultCrossProfileIntentFilter.Direction.TO_PROFILE, 486 /* flags= */ 0x00000018, // 0x00000018 means FLAG_IS_PACKAGE_FOR_FILTER 487 // and FLAG_ALLOW_CHAINED_RESOLUTION set 488 /* letsPersonalDataIntoProfile= */ false) 489 .addAction(Intent.ACTION_SEND) 490 .addAction(Intent.ACTION_SEND_MULTIPLE) 491 .addAction(Intent.ACTION_SENDTO) 492 .addDataType("*/*") 493 .build(); 494 495 /* 496 Allowing view action from clone to parent profile to open any app-links or web links 497 */ 498 private static final DefaultCrossProfileIntentFilter CLONE_TO_PARENT_WEB_VIEW_ACTION = 499 new DefaultCrossProfileIntentFilter.Builder( 500 DefaultCrossProfileIntentFilter.Direction.TO_PARENT, 501 /* flags= */ 0x00000018, // 0x00000018 means FLAG_IS_PACKAGE_FOR_FILTER 502 // and FLAG_ALLOW_CHAINED_RESOLUTION set 503 /* letsPersonalDataIntoProfile= */ false) 504 .addAction(Intent.ACTION_VIEW) 505 .addDataScheme("https") 506 .addDataScheme("http") 507 .build(); 508 509 /* 510 Allowing view action from parent to clone profile to open any app-links or web links 511 */ 512 private static final DefaultCrossProfileIntentFilter PARENT_TO_CLONE_WEB_VIEW_ACTION = 513 new DefaultCrossProfileIntentFilter.Builder( 514 DefaultCrossProfileIntentFilter.Direction.TO_PROFILE, 515 /* flags= */ 0x00000018, // 0x00000018 means FLAG_IS_PACKAGE_FOR_FILTER 516 // and FLAG_ALLOW_CHAINED_RESOLUTION set 517 /* letsPersonalDataIntoProfile= */ false) 518 .addAction(Intent.ACTION_VIEW) 519 .addDataScheme("https") 520 .addDataScheme("http") 521 .build(); 522 523 /* 524 Allowing view action from clone to parent profile to any data type e.g. pdf, including custom 525 content providers. 526 */ 527 private static final DefaultCrossProfileIntentFilter CLONE_TO_PARENT_VIEW_ACTION = 528 new DefaultCrossProfileIntentFilter.Builder( 529 DefaultCrossProfileIntentFilter.Direction.TO_PARENT, 530 /* flags= */ 0x00000018, // 0x00000018 means FLAG_IS_PACKAGE_FOR_FILTER 531 // and FLAG_ALLOW_CHAINED_RESOLUTION set 532 /* letsPersonalDataIntoProfile= */ false) 533 .addAction(Intent.ACTION_VIEW) 534 .addDataType("*/*") 535 .build(); 536 537 538 /* 539 Allowing pick,insert and edit action from clone to parent profile to open picker or contacts 540 insert/edit. 541 */ 542 private static final DefaultCrossProfileIntentFilter CLONE_TO_PARENT_PICK_INSERT_ACTION = 543 new DefaultCrossProfileIntentFilter.Builder( 544 DefaultCrossProfileIntentFilter.Direction.TO_PARENT, 545 /* flags= */ 0x00000018, // 0x00000018 means FLAG_IS_PACKAGE_FOR_FILTER 546 // and FLAG_ALLOW_CHAINED_RESOLUTION set 547 /* letsPersonalDataIntoProfile= */ false) 548 .addAction(Intent.ACTION_PICK) 549 .addAction(Intent.ACTION_GET_CONTENT) 550 .addAction(Intent.ACTION_EDIT) 551 .addAction(Intent.ACTION_INSERT) 552 .addAction(Intent.ACTION_INSERT_OR_EDIT) 553 .addAction(Intent.ACTION_OPEN_DOCUMENT) 554 .addDataType("*/*") 555 .addCategory(Intent.CATEGORY_DEFAULT) 556 .addCategory(Intent.CATEGORY_OPENABLE) 557 .build(); 558 559 /* 560 Allowing pick,insert and edit action from parent to clone profile to open picker 561 */ 562 private static final DefaultCrossProfileIntentFilter PARENT_TO_CLONE_PICK_INSERT_ACTION = 563 new DefaultCrossProfileIntentFilter.Builder( 564 DefaultCrossProfileIntentFilter.Direction.TO_PROFILE, 565 /* flags= */ 0x00000018, // 0x00000018 means FLAG_IS_PACKAGE_FOR_FILTER 566 // and FLAG_ALLOW_CHAINED_RESOLUTION set 567 /* letsPersonalDataIntoProfile= */ false) 568 .addAction(Intent.ACTION_PICK) 569 .addAction(Intent.ACTION_GET_CONTENT) 570 .addAction(Intent.ACTION_EDIT) 571 .addAction(Intent.ACTION_INSERT) 572 .addAction(Intent.ACTION_INSERT_OR_EDIT) 573 .addAction(Intent.ACTION_OPEN_DOCUMENT) 574 .addDataType("*/*") 575 .addCategory(Intent.CATEGORY_DEFAULT) 576 .addCategory(Intent.CATEGORY_OPENABLE) 577 .build(); 578 579 private static final DefaultCrossProfileIntentFilter PARENT_TO_CLONE_DIAL_DATA = 580 new DefaultCrossProfileIntentFilter.Builder( 581 DefaultCrossProfileIntentFilter.Direction.TO_PROFILE, 582 /* flags= */ 0x00000018, // 0x00000018 means FLAG_IS_PACKAGE_FOR_FILTER 583 // and FLAG_ALLOW_CHAINED_RESOLUTION set 584 /* letsPersonalDataIntoProfile= */ false) 585 .addAction(Intent.ACTION_DIAL) 586 .addAction(Intent.ACTION_VIEW) 587 .addCategory(Intent.CATEGORY_DEFAULT) 588 .addCategory(Intent.CATEGORY_BROWSABLE) 589 .addDataScheme("tel") 590 .addDataScheme("sip") 591 .addDataScheme("voicemail") 592 .build(); 593 594 private static final DefaultCrossProfileIntentFilter CLONE_TO_PARENT_DIAL_DATA = 595 new DefaultCrossProfileIntentFilter.Builder( 596 DefaultCrossProfileIntentFilter.Direction.TO_PARENT, 597 /* flags= */ 0x00000018, // 0x00000018 means FLAG_IS_PACKAGE_FOR_FILTER 598 // and FLAG_ALLOW_CHAINED_RESOLUTION set 599 /* letsPersonalDataIntoProfile= */ false) 600 .addAction(Intent.ACTION_DIAL) 601 .addAction(Intent.ACTION_VIEW) 602 .addCategory(Intent.CATEGORY_DEFAULT) 603 .addCategory(Intent.CATEGORY_BROWSABLE) 604 .addDataScheme("tel") 605 .addDataScheme("sip") 606 .addDataScheme("voicemail") 607 .build(); 608 609 private static final DefaultCrossProfileIntentFilter CLONE_TO_PARENT_SMS_MMS = 610 new DefaultCrossProfileIntentFilter.Builder( 611 DefaultCrossProfileIntentFilter.Direction.TO_PARENT, 612 /* flags= */ 0x00000018, // 0x00000018 means FLAG_IS_PACKAGE_FOR_FILTER 613 // and FLAG_ALLOW_CHAINED_RESOLUTION set 614 /* letsPersonalDataIntoProfile= */ false) 615 .addAction(Intent.ACTION_VIEW) 616 .addAction(Intent.ACTION_SENDTO) 617 .addCategory(Intent.CATEGORY_DEFAULT) 618 .addCategory(Intent.CATEGORY_BROWSABLE) 619 .addDataScheme("sms") 620 .addDataScheme("smsto") 621 .addDataScheme("mms") 622 .addDataScheme("mmsto") 623 .build(); 624 625 private static final DefaultCrossProfileIntentFilter CLONE_TO_PARENT_ACTION_PICK_IMAGES = 626 new DefaultCrossProfileIntentFilter.Builder( 627 DefaultCrossProfileIntentFilter.Direction.TO_PARENT, 628 /* flags= */ FLAG_IS_PACKAGE_FOR_FILTER | FLAG_ALLOW_CHAINED_RESOLUTION, 629 /* letsPersonalDataIntoProfile= */ false) 630 .addAction(MediaStore.ACTION_PICK_IMAGES) 631 .addCategory(Intent.CATEGORY_DEFAULT) 632 .build(); 633 634 private static final DefaultCrossProfileIntentFilter 635 CLONE_TO_PARENT_ACTION_PICK_IMAGES_WITH_DATA_TYPES = 636 new DefaultCrossProfileIntentFilter.Builder( 637 DefaultCrossProfileIntentFilter.Direction.TO_PARENT, 638 /* flags= */ FLAG_IS_PACKAGE_FOR_FILTER | FLAG_ALLOW_CHAINED_RESOLUTION, 639 /* letsPersonalDataIntoProfile= */ false) 640 .addAction(MediaStore.ACTION_PICK_IMAGES) 641 .addCategory(Intent.CATEGORY_DEFAULT) 642 .addDataType("image/*") 643 .addDataType("video/*") 644 .build(); 645 646 /** NFC TAG intent is always resolved by the primary user. */ 647 static final DefaultCrossProfileIntentFilter PARENT_TO_CLONE_NFC_TAG_DISCOVERED = 648 new DefaultCrossProfileIntentFilter.Builder( 649 DefaultCrossProfileIntentFilter.Direction.TO_PROFILE, 650 /* flags= */0, 651 /* letsPersonalDataIntoProfile= */ false) 652 .addAction(NfcAdapter.ACTION_TAG_DISCOVERED) 653 .build(); 654 655 /** NFC TAG intent is always resolved by the primary user. */ 656 static final DefaultCrossProfileIntentFilter PARENT_TO_CLONE_NFC_TECH_DISCOVERED = 657 new DefaultCrossProfileIntentFilter.Builder( 658 DefaultCrossProfileIntentFilter.Direction.TO_PROFILE, 659 /* flags= */0, 660 /* letsPersonalDataIntoProfile= */ false) 661 .addAction(NfcAdapter.ACTION_TECH_DISCOVERED) 662 .build(); 663 664 /** NFC TAG intent is always resolved by the primary user. */ 665 static final DefaultCrossProfileIntentFilter PARENT_TO_CLONE_NFC_NDEF_DISCOVERED = 666 new DefaultCrossProfileIntentFilter.Builder( 667 DefaultCrossProfileIntentFilter.Direction.TO_PROFILE, 668 /* flags= */0, 669 /* letsPersonalDataIntoProfile= */ false) 670 .addAction(NfcAdapter.ACTION_NDEF_DISCOVERED) 671 .build(); 672 getDefaultCloneProfileFilters()673 public static List<DefaultCrossProfileIntentFilter> getDefaultCloneProfileFilters() { 674 return Arrays.asList( 675 PARENT_TO_CLONE_SEND_ACTION, 676 PARENT_TO_CLONE_WEB_VIEW_ACTION, 677 PARENT_TO_CLONE_PICK_INSERT_ACTION, 678 PARENT_TO_CLONE_DIAL_DATA, 679 CLONE_TO_PARENT_MEDIA_CAPTURE, 680 CLONE_TO_PARENT_SEND_ACTION, 681 CLONE_TO_PARENT_WEB_VIEW_ACTION, 682 CLONE_TO_PARENT_VIEW_ACTION, 683 CLONE_TO_PARENT_PICK_INSERT_ACTION, 684 CLONE_TO_PARENT_DIAL_DATA, 685 CLONE_TO_PARENT_SMS_MMS, 686 CLONE_TO_PARENT_PHOTOPICKER_SELECTION, 687 CLONE_TO_PARENT_ACTION_PICK_IMAGES, 688 CLONE_TO_PARENT_ACTION_PICK_IMAGES_WITH_DATA_TYPES, 689 PARENT_TO_CLONE_NFC_TAG_DISCOVERED, 690 PARENT_TO_CLONE_NFC_TECH_DISCOVERED, 691 PARENT_TO_CLONE_NFC_NDEF_DISCOVERED 692 ); 693 } 694 695 /** Call intent should be handled by the main user. */ 696 private static final DefaultCrossProfileIntentFilter CALL_PRIVATE_PROFILE = 697 new DefaultCrossProfileIntentFilter.Builder( 698 DefaultCrossProfileIntentFilter.Direction.TO_PARENT, 699 SKIP_CURRENT_PROFILE, 700 /* letsPersonalDataIntoProfile= */ false) 701 .addAction(Intent.ACTION_CALL) 702 .addCategory(Intent.CATEGORY_DEFAULT) 703 .addDataScheme("tel") 704 .addDataScheme("sip") 705 .addDataScheme("voicemail") 706 .build(); 707 708 /** Pressing the call button should be handled by the main user. */ 709 private static final DefaultCrossProfileIntentFilter CALL_BUTTON_PRIVATE_PROFILE = 710 new DefaultCrossProfileIntentFilter.Builder( 711 DefaultCrossProfileIntentFilter.Direction.TO_PARENT, 712 ONLY_IF_NO_MATCH_FOUND, 713 /* letsPersonalDataIntoProfile= */ false) 714 .addAction(Intent.ACTION_CALL_BUTTON) 715 .addCategory(Intent.CATEGORY_DEFAULT) 716 .build(); 717 718 /** Dial intent with mime type can be handled by either private profile or its parent user. */ 719 private static final DefaultCrossProfileIntentFilter DIAL_MIME_PRIVATE_PROFILE = 720 new DefaultCrossProfileIntentFilter.Builder( 721 DefaultCrossProfileIntentFilter.Direction.TO_PARENT, 722 ONLY_IF_NO_MATCH_FOUND, 723 /* letsPersonalDataIntoProfile= */ false) 724 .addAction(Intent.ACTION_DIAL) 725 .addAction(Intent.ACTION_VIEW) 726 .addCategory(Intent.CATEGORY_DEFAULT) 727 .addCategory(Intent.CATEGORY_BROWSABLE) 728 .addDataType("vnd.android.cursor.item/phone") 729 .addDataType("vnd.android.cursor.item/phone_v2") 730 .addDataType("vnd.android.cursor.item/person") 731 .addDataType("vnd.android.cursor.dir/calls") 732 .addDataType("vnd.android.cursor.item/calls") 733 .build(); 734 735 /** Dial intent with data scheme can be handled by either private profile or its parent user. */ 736 private static final DefaultCrossProfileIntentFilter DIAL_DATA_PRIVATE_PROFILE = 737 new DefaultCrossProfileIntentFilter.Builder( 738 DefaultCrossProfileIntentFilter.Direction.TO_PARENT, 739 ONLY_IF_NO_MATCH_FOUND, 740 /* letsPersonalDataIntoProfile= */ false) 741 .addAction(Intent.ACTION_DIAL) 742 .addAction(Intent.ACTION_VIEW) 743 .addCategory(Intent.CATEGORY_DEFAULT) 744 .addCategory(Intent.CATEGORY_BROWSABLE) 745 .addDataScheme("tel") 746 .addDataScheme("sip") 747 .addDataScheme("voicemail") 748 .build(); 749 750 /** 751 * Dial intent with no data scheme or type can be handled by either private profile or its 752 * parent user. 753 */ 754 private static final DefaultCrossProfileIntentFilter DIAL_RAW_PRIVATE_PROFILE = 755 new DefaultCrossProfileIntentFilter.Builder( 756 DefaultCrossProfileIntentFilter.Direction.TO_PARENT, 757 ONLY_IF_NO_MATCH_FOUND, 758 /* letsPersonalDataIntoProfile= */ false) 759 .addAction(Intent.ACTION_DIAL) 760 .addCategory(Intent.CATEGORY_DEFAULT) 761 .addCategory(Intent.CATEGORY_BROWSABLE) 762 .build(); 763 764 /** SMS and MMS are always handled in the main user. */ 765 private static final DefaultCrossProfileIntentFilter SMS_MMS_PRIVATE_PROFILE = 766 new DefaultCrossProfileIntentFilter.Builder( 767 DefaultCrossProfileIntentFilter.Direction.TO_PARENT, 768 SKIP_CURRENT_PROFILE, 769 /* letsPersonalDataIntoProfile= */ false) 770 .addAction(Intent.ACTION_VIEW) 771 .addAction(Intent.ACTION_SENDTO) 772 .addCategory(Intent.CATEGORY_DEFAULT) 773 .addCategory(Intent.CATEGORY_BROWSABLE) 774 .addDataScheme("sms") 775 .addDataScheme("smsto") 776 .addDataScheme("mms") 777 .addDataScheme("mmsto") 778 .build(); 779 getDefaultPrivateProfileFilters()780 public static List<DefaultCrossProfileIntentFilter> getDefaultPrivateProfileFilters() { 781 return Arrays.asList( 782 DIAL_MIME_PRIVATE_PROFILE, 783 DIAL_DATA_PRIVATE_PROFILE, 784 DIAL_RAW_PRIVATE_PROFILE, 785 CALL_PRIVATE_PROFILE, 786 CALL_BUTTON_PRIVATE_PROFILE, 787 EMERGENCY_CALL_DATA, 788 EMERGENCY_CALL_MIME, 789 SMS_MMS_PRIVATE_PROFILE 790 ); 791 } 792 } 793