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 forwardedIntentsFromManaged.addAll(Arrays.asList( 165 new Intent("android.intent.action.CALL_EMERGENCY").setData( 166 Uri.parse("tel:123")), 167 new Intent("android.intent.action.CALL_PRIVILEGED").setData( 168 Uri.parse("tel:123")), 169 new Intent(Intent.ACTION_VIEW).setData(Uri.parse("tel:123")).addCategory( 170 Intent.CATEGORY_BROWSABLE), 171 new Intent(Settings.ACTION_NETWORK_OPERATOR_SETTINGS), 172 new Intent(Settings.ACTION_DATA_ROAMING_SETTINGS), 173 new Intent(Intent.ACTION_SENDTO).setData(Uri.parse("sms:07700900100")), 174 new Intent(Intent.ACTION_SENDTO).setData(Uri.parse("smsto:07700900100")), 175 new Intent(Intent.ACTION_SENDTO).setData(Uri.parse("mms:07700900100")), 176 new Intent(Intent.ACTION_SENDTO).setData(Uri.parse("mmsto:07700900100")), 177 new Intent(Intent.ACTION_VIEW).setData( 178 Uri.parse("sms:07700900100?body=Hello%20world")).addCategory( 179 Intent.CATEGORY_BROWSABLE), 180 new Intent(Intent.ACTION_VIEW).setData( 181 Uri.parse("smsto:07700900100?body=Hello%20world")).addCategory( 182 Intent.CATEGORY_BROWSABLE), 183 new Intent(Intent.ACTION_VIEW).setData( 184 Uri.parse("mms:07700900100?body=Hello%20world")).addCategory( 185 Intent.CATEGORY_BROWSABLE), 186 new Intent(Intent.ACTION_VIEW).setData( 187 Uri.parse("mmsto:07700900100?body=Hello%20world")).addCategory( 188 Intent.CATEGORY_BROWSABLE), 189 new Intent(Settings.ACTION_APN_SETTINGS))); 190 notForwardedIntentsFromManaged.addAll(Arrays.asList( 191 new Intent(Intent.ACTION_DIAL).setData(Uri.parse("tel:123")), 192 new Intent(Intent.ACTION_CALL).setData(Uri.parse("tel:123")))); 193 } 194 195 if (pm.hasSystemFeature(PackageManager.FEATURE_NFC)) { 196 forwardedIntentsFromManaged.addAll(Arrays.asList( 197 new Intent(Settings.ACTION_NFC_SETTINGS), 198 new Intent(Settings.ACTION_NFCSHARING_SETTINGS))); 199 } 200 201 if (pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION)) { 202 forwardedIntentsFromManaged.addAll(Arrays.asList( 203 new Intent(CardEmulation.ACTION_CHANGE_DEFAULT), 204 new Intent(Settings.ACTION_NFC_PAYMENT_SETTINGS))); 205 } 206 207 if (pm.hasSystemFeature(PackageManager.FEATURE_CAMERA)) { 208 forwardedIntentsFromManaged.addAll(Arrays.asList( 209 new Intent(MediaStore.ACTION_IMAGE_CAPTURE), 210 new Intent(MediaStore.ACTION_VIDEO_CAPTURE), 211 new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA), 212 new Intent(MediaStore.INTENT_ACTION_VIDEO_CAMERA), 213 new Intent(MediaStore.ACTION_IMAGE_CAPTURE_SECURE), 214 new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE))); 215 } 216 217 final String state = Environment.getExternalStorageState(); 218 if (Environment.MEDIA_MOUNTED.equals(state)) { 219 forwardedIntentsFromManaged.add( 220 new Intent(Settings.ACTION_MEMORY_CARD_SETTINGS)); 221 } 222 223 if (pm.hasSystemFeature(PackageManager.FEATURE_WIFI)) { 224 forwardedIntentsFromManaged.addAll(Arrays.asList( 225 new Intent(Settings.ACTION_WIFI_IP_SETTINGS), 226 new Intent(Settings.ACTION_WIFI_SETTINGS))); 227 } 228 229 if (pm.hasSystemFeature(PackageManager.FEATURE_MICROPHONE)) { 230 forwardedIntentsFromManaged.addAll(Arrays.asList( 231 new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION), 232 new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH))); 233 } 234 235 if (pm.hasSystemFeature(PackageManager.FEATURE_LOCATION)) { 236 forwardingOptionalIntentsFromManaged.add( 237 new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)); 238 } 239 240 if (pm.hasSystemFeature(PackageManager.FEATURE_AUDIO_OUTPUT)) { 241 forwardedIntentsFromManaged.addAll(Arrays.asList( 242 new Intent(Settings.ACTION_SOUND_SETTINGS), 243 new Intent("android.settings.ACTION_OTHER_SOUND_SETTINGS"))); 244 notForwardedIntentsFromManaged.add( 245 new Intent(AudioEffect.ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL)); 246 } 247 248 if (pm.hasSystemFeature(PackageManager.FEATURE_HOME_SCREEN)) { 249 forwardingOptionalIntentsFromManaged.add( 250 new Intent(Settings.ACTION_HOME_SETTINGS)); 251 } 252 253 if (pm.hasSystemFeature(PackageManager.FEATURE_INPUT_METHODS)) { 254 notForwardedIntentsFromManaged.addAll(Arrays.asList( 255 new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS), 256 new Intent(Settings.ACTION_INPUT_METHOD_SUBTYPE_SETTINGS))); 257 } 258 259 if (!pm.hasSystemFeature(PackageManager.FEATURE_WATCH)) { 260 forwardedIntentsFromManaged.add( 261 new Intent(Settings.ACTION_DREAM_SETTINGS)); 262 } 263 264 if (!pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK)) { 265 forwardedIntentsFromManaged.add( 266 new Intent(Settings.ACTION_AIRPLANE_MODE_SETTINGS)); 267 } 268 269 if (pm.hasSystemFeature(PackageManager.FEATURE_PRINTING)) { 270 notForwardedIntentsFromManaged.add( 271 new Intent(Settings.ACTION_PRINT_SETTINGS)); 272 } 273 274 if (Build.TYPE.equals("user")) { 275 forwardedIntentsFromManaged.add( 276 new Intent(Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS)); 277 } 278 } 279 checkCrossProfileIntentFilters(int flag)280 public boolean checkCrossProfileIntentFilters(int flag) { 281 boolean crossProfileIntentFiltersSet; 282 if (flag == FLAG_INTENTS_FROM_PRIMARY) { 283 crossProfileIntentFiltersSet = checkIntentForwardingFromPrimary(); 284 } else { 285 crossProfileIntentFiltersSet = 286 checkIntentForwardingFromManaged() && 287 checkIntentsWithOptionalForwardingFromManagedAreHandled(); 288 } 289 return crossProfileIntentFiltersSet; 290 } 291 292 /** 293 * Checks if required cross profile intent filters are set for the intents fired from the 294 * primary profile. 295 */ checkIntentForwardingFromPrimary()296 private boolean checkIntentForwardingFromPrimary() { 297 // Get the class name of the intentForwarderActivity in the primary profile by firing an 298 // intent which we know will be forwarded from primary profile to managed profile. 299 ActivityInfo forwarderActivityInfo = 300 getForwarderActivityInfo(ByodHelperActivity.ACTION_QUERY_PROFILE_OWNER); 301 if (forwarderActivityInfo == null) { 302 return false; 303 } 304 305 // Check for intents which can be forwarded to the managed profile. 306 return checkIntentForwarding(forwardedIntentsFromPrimary, 307 forwarderActivityInfo, "from primary profile should be forwarded to the " + 308 "managed profile but is not.", true); 309 } 310 311 /** 312 * Checks that the required intents either have cross profile intent filters set up, or are 313 * handled directly in the managed profile. 314 */ checkIntentsWithOptionalForwardingFromManagedAreHandled()315 private boolean checkIntentsWithOptionalForwardingFromManagedAreHandled() { 316 for (Intent intent : forwardingOptionalIntentsFromManaged) { 317 List<ResolveInfo> resolveInfoList = 318 mContext.getPackageManager().queryIntentActivities(intent, 319 PackageManager.MATCH_DEFAULT_ONLY); 320 321 if (resolveInfoList.isEmpty()) { 322 Log.e(TAG, intent + " should be handled in or forwarded from the managed " + 323 "profile, but it is not."); 324 return false; 325 } 326 } 327 328 return true; 329 } 330 331 /** 332 * Checks if required cross profile intent filters are set for the intents fired from the 333 * managed profile. 334 */ checkIntentForwardingFromManaged()335 private boolean checkIntentForwardingFromManaged() { 336 // Get the class name of the intentForwarderActivity in the managed profile by firing an 337 // intent which we know will be forwarded from managed profile to primary profile. 338 ActivityInfo forwarderActivityInfo = 339 getForwarderActivityInfo(ByodHelperActivity.ACTION_PROFILE_OWNER_STATUS); 340 if (forwarderActivityInfo == null) { 341 return false; 342 } 343 344 boolean success = true; 345 // Check for intents which can be forwarded to the primary profile. 346 success &= checkIntentForwarding(forwardedIntentsFromManaged, 347 forwarderActivityInfo, " from managed profile should be forwarded to the " + 348 "primary profile but is not.", true); 349 350 // Check for intents which cannot be forwarded to the primary profile. 351 success &= checkIntentForwarding(notForwardedIntentsFromManaged, 352 forwarderActivityInfo, "from managed profile should not be forwarded to the " + 353 "primary profile but it is.", false); 354 return success; 355 } 356 357 /** 358 * Checks if the intentForwarderActivity can handle the intent passed. 359 */ canForwarderActivityHandleIntent(Intent intent, ActivityInfo forwarderActivityInfo)360 private boolean canForwarderActivityHandleIntent(Intent intent, 361 ActivityInfo forwarderActivityInfo) { 362 // Get all the activities which can handle the intent. 363 List<ResolveInfo> resolveInfoList = 364 mContext.getPackageManager().queryIntentActivities(intent, 365 PackageManager.MATCH_DEFAULT_ONLY); 366 // Check if intentForwarderActivity is part of the list. 367 for (ResolveInfo resolveInfo : resolveInfoList) { 368 if (forwarderActivityInfo.packageName.equals(resolveInfo.activityInfo.packageName) 369 && forwarderActivityInfo.name.equals(resolveInfo.activityInfo.name)) { 370 return true; 371 } 372 } 373 return false; 374 } 375 376 /** 377 * Returns the class name of the intentForwarderActivity. 378 */ getForwarderActivityInfo(String action)379 private ActivityInfo getForwarderActivityInfo(String action) { 380 Intent intent = new Intent(action); 381 List<ResolveInfo> resolveInfoList = 382 mContext.getPackageManager().queryIntentActivities(intent, 383 PackageManager.MATCH_DEFAULT_ONLY); 384 if (resolveInfoList.isEmpty() || resolveInfoList.size() > 1) { 385 Log.d(TAG, "There should be exactly one activity IntentForwarder which " + 386 "handles the intent " + intent); 387 return null; 388 } 389 return resolveInfoList.get(0).activityInfo; 390 } 391 392 /** 393 * Checks if the intents passed are correctly handled. 394 * @return {@code false} if at least one intent is not handled correctly. 395 */ checkIntentForwarding(ArrayList<Intent> intentList, ActivityInfo expectedForwarderActivityInfo, String errorMessage, boolean canResolve)396 private boolean checkIntentForwarding(ArrayList<Intent> intentList, 397 ActivityInfo expectedForwarderActivityInfo, String errorMessage, boolean canResolve) { 398 boolean success = true; 399 for (Intent intent : intentList) { 400 if (canForwarderActivityHandleIntent(intent, 401 expectedForwarderActivityInfo) != canResolve) { 402 Log.e(TAG, intent + " " + errorMessage); 403 success = false; 404 } 405 } 406 return success; 407 } 408 } 409