1 /* 2 * Copyright (C) 2015 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.cts.verifier.managedprovisioning; 18 19 import android.app.DownloadManager; 20 import android.app.admin.DevicePolicyManager; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.content.pm.ActivityInfo; 24 import android.content.pm.PackageManager; 25 import android.content.pm.ResolveInfo; 26 import android.media.audiofx.AudioEffect; 27 import android.net.Uri; 28 import android.nfc.cardemulation.CardEmulation; 29 import android.os.Build; 30 import android.os.Environment; 31 import android.os.UserManager; 32 import android.provider.AlarmClock; 33 import android.provider.CalendarContract.Events; 34 import android.provider.MediaStore; 35 import android.provider.Settings; 36 import android.util.Log; 37 38 import java.util.ArrayList; 39 import java.util.Arrays; 40 import java.util.List; 41 42 /** 43 * Helper class for testing if the required cross profile intent filters are set during the 44 * managed provisioning. 45 */ 46 public class IntentFiltersTestHelper { 47 48 private static final String TAG = "IntentFiltersTestHelper"; 49 50 // These are the intents which can be forwarded to the managed profile. 51 private static final ArrayList<Intent> forwardedIntentsFromPrimary = 52 new ArrayList<>(Arrays.asList( 53 new Intent(Intent.ACTION_SEND).setType("*/*"), 54 new Intent(Intent.ACTION_SEND_MULTIPLE).setType("*/*") 55 )); 56 57 // These are the intents which can be forwarded to the primary profile. 58 private static final ArrayList<Intent> forwardedIntentsFromManaged = 59 new ArrayList<>(Arrays.asList( 60 new Intent(AlarmClock.ACTION_SET_ALARM), 61 new Intent(AlarmClock.ACTION_SET_TIMER), 62 new Intent(AlarmClock.ACTION_SHOW_ALARMS), 63 new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS), 64 new Intent(Settings.ACTION_CAPTIONING_SETTINGS), 65 new Intent(Settings.ACTION_DATE_SETTINGS), 66 new Intent(Settings.ACTION_DEVICE_INFO_SETTINGS), 67 new Intent(Settings.ACTION_DISPLAY_SETTINGS), 68 new Intent(Settings.ACTION_LOCALE_SETTINGS), 69 new Intent(Settings.ACTION_PRIVACY_SETTINGS), 70 new Intent(Settings.ACTION_SETTINGS), 71 new Intent(Settings.ACTION_WIRELESS_SETTINGS), 72 new Intent("android.net.vpn.SETTINGS"), 73 new Intent(Settings.ACTION_VPN_SETTINGS), 74 new Intent(Settings.ACTION_BATTERY_SAVER_SETTINGS), 75 new Intent("android.settings.LICENSE"), 76 new Intent("android.settings.NOTIFICATION_SETTINGS"), 77 new Intent("android.settings.ZEN_MODE_SETTINGS"), 78 new Intent("com.android.settings.ACCESSIBILITY_COLOR_SPACE_SETTINGS"), 79 new Intent("com.android.settings.TTS_SETTINGS"), 80 new Intent(Settings.ACTION_INTERNAL_STORAGE_SETTINGS), 81 new Intent(Intent.ACTION_GET_CONTENT).setType("*/*").addCategory( 82 Intent.CATEGORY_OPENABLE), 83 new Intent(Intent.ACTION_OPEN_DOCUMENT).setType("*/*").addCategory( 84 Intent.CATEGORY_OPENABLE) 85 )); 86 87 // These are the intents which can either be handled directly in the managed profile, 88 // or be forwarded to the primary profile. 89 private static final ArrayList<Intent> forwardingOptionalIntentsFromManaged = 90 new ArrayList<>(Arrays.asList( 91 new Intent(Settings.ACTION_SYNC_SETTINGS), 92 new Intent(Settings.ACTION_ADD_ACCOUNT), 93 new Intent(Settings.ACTION_MANAGE_APPLICATIONS_SETTINGS), 94 new Intent(Settings.ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS), 95 new Intent(Settings.ACTION_APPLICATION_SETTINGS), 96 new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD), 97 new Intent("android.settings.ACCOUNT_SYNC_SETTINGS") 98 )); 99 100 // These are the intents which cannot be forwarded to the primary profile. 101 private static final ArrayList<Intent> notForwardedIntentsFromManaged = 102 new ArrayList<>(Arrays.asList( 103 new Intent(Intent.ACTION_INSERT).setData( 104 Uri.parse("content://browser/bookmarks")), 105 new Intent(Intent.ACTION_VIEW).setData( 106 Uri.parse("http://www.example.com")).addCategory( 107 Intent.CATEGORY_BROWSABLE), 108 new Intent(Intent.ACTION_SENDTO).setData( 109 Uri.parse("mailto:user@example.com")), 110 new Intent(Intent.ACTION_VIEW).setData( 111 Uri.parse("mailto:user@example.com")).addCategory( 112 Intent.CATEGORY_BROWSABLE), 113 new Intent(Intent.ACTION_VIEW).setData( 114 Uri.parse("geo:0,0?q=BuckinghamPalace")), 115 new Intent(Intent.ACTION_VIEW).setData( 116 Uri.parse("http://example.com/oceans.mp4")).setType("video/mp4"), 117 new Intent(Intent.ACTION_VIEW).setData( 118 Uri.parse("http://www.example.com/horse.mp3")).setType("audio/*"), 119 new Intent(MediaStore.INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH), 120 new Intent(Intent.ACTION_VIEW).setData( 121 Uri.parse("market://details?id=com.android.chrome")).addCategory( 122 Intent.CATEGORY_BROWSABLE), 123 new Intent(Intent.ACTION_WEB_SEARCH), 124 new Intent(Settings.ACTION_SEARCH_SETTINGS), 125 new Intent(Intent.ACTION_MANAGE_NETWORK_USAGE), 126 new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).setData( 127 Uri.parse("package:com.android.chrome")), 128 new Intent(Intent.ACTION_INSERT).setData(Events.CONTENT_URI), 129 new Intent(DownloadManager.ACTION_VIEW_DOWNLOADS) 130 )); 131 132 // This flag specifies we are dealing with intents fired from the primary profile. 133 public static final int FLAG_INTENTS_FROM_PRIMARY = 1; 134 // This flag specifies we are dealing with intents fired from the managed profile. 135 public static final int FLAG_INTENTS_FROM_MANAGED = 2; 136 137 private Context mContext; 138 IntentFiltersTestHelper(Context context)139 IntentFiltersTestHelper(Context context) { 140 mContext = context; 141 142 addIntentsThatDependOnDeviceConfigs(); 143 addIntentsThatDependOnDeviceFeatures(); 144 } 145 146 // Return whether the intent can be resolved in the current profile canResolveIntent(PackageManager pm, Intent intent)147 private boolean canResolveIntent(PackageManager pm, Intent intent) { 148 return intent.resolveActivity(pm) != null; 149 } 150 addIntentsThatDependOnDeviceConfigs()151 private void addIntentsThatDependOnDeviceConfigs() { 152 if (UserManager.supportsMultipleUsers()) { 153 forwardedIntentsFromManaged.add( 154 new Intent("android.settings.USER_SETTINGS")); 155 } 156 } 157 addIntentsThatDependOnDeviceFeatures()158 private void addIntentsThatDependOnDeviceFeatures() { 159 PackageManager pm = mContext.getPackageManager(); 160 161 if (pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY) 162 && pm.hasSystemFeature(PackageManager.FEATURE_TELECOM)) { 163 forwardedIntentsFromManaged.addAll(Arrays.asList( 164 new Intent("android.intent.action.CALL_EMERGENCY").setData( 165 Uri.parse("tel:123")), 166 new Intent("android.intent.action.CALL_PRIVILEGED").setData( 167 Uri.parse("tel:123")), 168 new Intent(Intent.ACTION_VIEW).setData(Uri.parse("tel:123")).addCategory( 169 Intent.CATEGORY_BROWSABLE), 170 new Intent(Settings.ACTION_NETWORK_OPERATOR_SETTINGS), 171 new Intent(Settings.ACTION_DATA_ROAMING_SETTINGS), 172 new Intent(Intent.ACTION_SENDTO).setData(Uri.parse("sms:07700900100")), 173 new Intent(Intent.ACTION_SENDTO).setData(Uri.parse("smsto:07700900100")), 174 new Intent(Intent.ACTION_SENDTO).setData(Uri.parse("mms:07700900100")), 175 new Intent(Intent.ACTION_SENDTO).setData(Uri.parse("mmsto:07700900100")), 176 new Intent(Intent.ACTION_VIEW).setData( 177 Uri.parse("sms:07700900100?body=Hello%20world")).addCategory( 178 Intent.CATEGORY_BROWSABLE), 179 new Intent(Intent.ACTION_VIEW).setData( 180 Uri.parse("smsto:07700900100?body=Hello%20world")).addCategory( 181 Intent.CATEGORY_BROWSABLE), 182 new Intent(Intent.ACTION_VIEW).setData( 183 Uri.parse("mms:07700900100?body=Hello%20world")).addCategory( 184 Intent.CATEGORY_BROWSABLE), 185 new Intent(Intent.ACTION_VIEW).setData( 186 Uri.parse("mmsto:07700900100?body=Hello%20world")).addCategory( 187 Intent.CATEGORY_BROWSABLE), 188 new Intent(Settings.ACTION_APN_SETTINGS))); 189 notForwardedIntentsFromManaged.addAll(Arrays.asList( 190 new Intent(Intent.ACTION_DIAL).setData(Uri.parse("tel:123")), 191 new Intent(Intent.ACTION_CALL).setData(Uri.parse("tel:123")))); 192 } 193 194 if (pm.hasSystemFeature(PackageManager.FEATURE_NFC)) { 195 forwardedIntentsFromManaged.add(new Intent(Settings.ACTION_NFC_SETTINGS)); 196 } 197 198 if (pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION)) { 199 forwardedIntentsFromManaged.addAll(Arrays.asList( 200 new Intent(CardEmulation.ACTION_CHANGE_DEFAULT), 201 new Intent(Settings.ACTION_NFC_PAYMENT_SETTINGS))); 202 } 203 204 if (pm.hasSystemFeature(PackageManager.FEATURE_CAMERA)) { 205 forwardingOptionalIntentsFromManaged.addAll(Arrays.asList( 206 new Intent(MediaStore.ACTION_IMAGE_CAPTURE), 207 new Intent(MediaStore.ACTION_VIDEO_CAPTURE), 208 new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA), 209 new Intent(MediaStore.INTENT_ACTION_VIDEO_CAMERA), 210 new Intent(MediaStore.ACTION_IMAGE_CAPTURE_SECURE), 211 new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE))); 212 213 if (com.android.providers.media.flags.Flags.motionPhotoIntent()) { 214 Intent motionPhotoIntent = new Intent(MediaStore.ACTION_MOTION_PHOTO_CAPTURE); 215 if (canResolveIntent(pm, motionPhotoIntent)) { 216 forwardingOptionalIntentsFromManaged.add(motionPhotoIntent); 217 } 218 219 Intent motionPhotoSecureIntent = 220 new Intent(MediaStore.ACTION_MOTION_PHOTO_CAPTURE_SECURE); 221 if (canResolveIntent(pm, motionPhotoSecureIntent)) { 222 forwardingOptionalIntentsFromManaged.add(motionPhotoSecureIntent); 223 } 224 } 225 } 226 227 final String state = Environment.getExternalStorageState(); 228 if (Environment.MEDIA_MOUNTED.equals(state)) { 229 forwardedIntentsFromManaged.add( 230 new Intent(Settings.ACTION_MEMORY_CARD_SETTINGS)); 231 } 232 233 if (pm.hasSystemFeature(PackageManager.FEATURE_WIFI)) { 234 forwardedIntentsFromManaged.addAll(Arrays.asList( 235 new Intent(Settings.ACTION_WIFI_IP_SETTINGS), 236 new Intent(Settings.ACTION_WIFI_SETTINGS))); 237 } 238 239 if (pm.hasSystemFeature(PackageManager.FEATURE_MICROPHONE)) { 240 forwardingOptionalIntentsFromManaged.add( 241 new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION)); 242 } 243 244 if (pm.hasSystemFeature(PackageManager.FEATURE_LOCATION)) { 245 forwardingOptionalIntentsFromManaged.add( 246 new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)); 247 } 248 249 if (pm.hasSystemFeature(PackageManager.FEATURE_AUDIO_OUTPUT)) { 250 forwardedIntentsFromManaged.addAll(Arrays.asList( 251 new Intent(Settings.ACTION_SOUND_SETTINGS), 252 new Intent("android.settings.ACTION_OTHER_SOUND_SETTINGS"))); 253 notForwardedIntentsFromManaged.add( 254 new Intent(AudioEffect.ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL)); 255 } 256 257 if (pm.hasSystemFeature(PackageManager.FEATURE_HOME_SCREEN)) { 258 forwardingOptionalIntentsFromManaged.add( 259 new Intent(Settings.ACTION_HOME_SETTINGS)); 260 } 261 262 if (pm.hasSystemFeature(PackageManager.FEATURE_INPUT_METHODS)) { 263 notForwardedIntentsFromManaged.addAll(Arrays.asList( 264 new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS), 265 new Intent(Settings.ACTION_INPUT_METHOD_SUBTYPE_SETTINGS))); 266 } 267 268 if (!pm.hasSystemFeature(PackageManager.FEATURE_WATCH)) { 269 forwardedIntentsFromManaged.add( 270 new Intent(Settings.ACTION_DREAM_SETTINGS)); 271 } 272 273 if (!pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK)) { 274 forwardedIntentsFromManaged.add( 275 new Intent(Settings.ACTION_AIRPLANE_MODE_SETTINGS)); 276 } 277 278 if (pm.hasSystemFeature(PackageManager.FEATURE_PRINTING)) { 279 notForwardedIntentsFromManaged.add( 280 new Intent(Settings.ACTION_PRINT_SETTINGS)); 281 } 282 283 if (Build.TYPE.equals("user")) { 284 forwardedIntentsFromManaged.add( 285 new Intent(Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS)); 286 } 287 } 288 checkCrossProfileIntentFilters(int flag)289 public boolean checkCrossProfileIntentFilters(int flag) { 290 boolean crossProfileIntentFiltersSet; 291 if (flag == FLAG_INTENTS_FROM_PRIMARY) { 292 crossProfileIntentFiltersSet = checkIntentForwardingFromPrimary(); 293 } else { 294 crossProfileIntentFiltersSet = 295 checkIntentForwardingFromManaged() && 296 checkIntentsWithOptionalForwardingFromManagedAreHandled(); 297 } 298 return crossProfileIntentFiltersSet; 299 } 300 301 /** 302 * Checks if required cross profile intent filters are set for the intents fired from the 303 * primary profile. 304 */ checkIntentForwardingFromPrimary()305 private boolean checkIntentForwardingFromPrimary() { 306 // Get the class name of the intentForwarderActivity in the primary profile by firing an 307 // intent which we know will be forwarded from primary profile to managed profile. 308 ActivityInfo forwarderActivityInfo = 309 getForwarderActivityInfo(ByodHelperActivity.ACTION_QUERY_PROFILE_OWNER); 310 if (forwarderActivityInfo == null) { 311 return false; 312 } 313 314 // Check for intents which can be forwarded to the managed profile. 315 return checkIntentForwarding(forwardedIntentsFromPrimary, 316 forwarderActivityInfo, "from primary profile should be forwarded to the " + 317 "managed profile but is not.", true); 318 } 319 320 /** 321 * Checks that the required intents either have cross profile intent filters set up, or are 322 * handled directly in the managed profile. 323 */ checkIntentsWithOptionalForwardingFromManagedAreHandled()324 private boolean checkIntentsWithOptionalForwardingFromManagedAreHandled() { 325 for (Intent intent : forwardingOptionalIntentsFromManaged) { 326 List<ResolveInfo> resolveInfoList = 327 mContext.getPackageManager().queryIntentActivities(intent, 328 PackageManager.MATCH_DEFAULT_ONLY); 329 330 if (resolveInfoList.isEmpty()) { 331 Log.e(TAG, intent + " should be handled in or forwarded from the managed " + 332 "profile, but it is not."); 333 return false; 334 } 335 } 336 337 return true; 338 } 339 340 /** 341 * Checks if required cross profile intent filters are set for the intents fired from the 342 * managed profile. 343 */ checkIntentForwardingFromManaged()344 private boolean checkIntentForwardingFromManaged() { 345 // Get the class name of the intentForwarderActivity in the managed profile by firing an 346 // intent which we know will be forwarded from managed profile to primary profile. 347 ActivityInfo forwarderActivityInfo = 348 getForwarderActivityInfo(ByodHelperActivity.ACTION_PROFILE_OWNER_STATUS); 349 if (forwarderActivityInfo == null) { 350 return false; 351 } 352 353 boolean success = true; 354 // Check for intents which can be forwarded to the primary profile. 355 success &= checkIntentForwarding(forwardedIntentsFromManaged, 356 forwarderActivityInfo, " from managed profile should be forwarded to the " + 357 "primary profile but is not.", true); 358 359 // Check for intents which cannot be forwarded to the primary profile. 360 success &= checkIntentForwarding(notForwardedIntentsFromManaged, 361 forwarderActivityInfo, "from managed profile should not be forwarded to the " + 362 "primary profile but it is.", false); 363 return success; 364 } 365 366 /** 367 * Checks if the intentForwarderActivity can handle the intent passed. 368 */ canForwarderActivityHandleIntent(Intent intent, ActivityInfo forwarderActivityInfo)369 private boolean canForwarderActivityHandleIntent(Intent intent, 370 ActivityInfo forwarderActivityInfo) { 371 // Get all the activities which can handle the intent. 372 List<ResolveInfo> resolveInfoList = 373 mContext.getPackageManager().queryIntentActivities(intent, 374 PackageManager.MATCH_DEFAULT_ONLY); 375 // Check if intentForwarderActivity is part of the list. 376 for (ResolveInfo resolveInfo : resolveInfoList) { 377 if (forwarderActivityInfo.packageName.equals(resolveInfo.activityInfo.packageName) 378 && forwarderActivityInfo.name.equals(resolveInfo.activityInfo.name)) { 379 return true; 380 } 381 } 382 return false; 383 } 384 385 /** 386 * Returns the class name of the intentForwarderActivity. 387 */ getForwarderActivityInfo(String action)388 private ActivityInfo getForwarderActivityInfo(String action) { 389 Intent intent = new Intent(action); 390 List<ResolveInfo> resolveInfoList = 391 mContext.getPackageManager().queryIntentActivities(intent, 392 PackageManager.MATCH_DEFAULT_ONLY); 393 if (resolveInfoList.isEmpty() || resolveInfoList.size() > 1) { 394 Log.d(TAG, "There should be exactly one activity IntentForwarder which " + 395 "handles the intent " + intent); 396 return null; 397 } 398 return resolveInfoList.get(0).activityInfo; 399 } 400 401 /** 402 * Checks if the intents passed are correctly handled. 403 * @return {@code false} if at least one intent is not handled correctly. 404 */ checkIntentForwarding(ArrayList<Intent> intentList, ActivityInfo expectedForwarderActivityInfo, String errorMessage, boolean canResolve)405 private boolean checkIntentForwarding(ArrayList<Intent> intentList, 406 ActivityInfo expectedForwarderActivityInfo, String errorMessage, boolean canResolve) { 407 boolean success = true; 408 for (Intent intent : intentList) { 409 if (canForwarderActivityHandleIntent(intent, 410 expectedForwarderActivityInfo) != canResolve) { 411 Log.e(TAG, intent + " " + errorMessage); 412 success = false; 413 } 414 } 415 return success; 416 } 417 } 418