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