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.addAll(Arrays.asList( 232 new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION), 233 new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH))); 234 } 235 236 if (pm.hasSystemFeature(PackageManager.FEATURE_LOCATION)) { 237 forwardingOptionalIntentsFromManaged.add( 238 new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)); 239 } 240 241 if (pm.hasSystemFeature(PackageManager.FEATURE_AUDIO_OUTPUT)) { 242 forwardedIntentsFromManaged.addAll(Arrays.asList( 243 new Intent(Settings.ACTION_SOUND_SETTINGS), 244 new Intent("android.settings.ACTION_OTHER_SOUND_SETTINGS"))); 245 notForwardedIntentsFromManaged.add( 246 new Intent(AudioEffect.ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL)); 247 } 248 249 if (pm.hasSystemFeature(PackageManager.FEATURE_HOME_SCREEN)) { 250 forwardingOptionalIntentsFromManaged.add( 251 new Intent(Settings.ACTION_HOME_SETTINGS)); 252 } 253 254 if (pm.hasSystemFeature(PackageManager.FEATURE_INPUT_METHODS)) { 255 notForwardedIntentsFromManaged.addAll(Arrays.asList( 256 new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS), 257 new Intent(Settings.ACTION_INPUT_METHOD_SUBTYPE_SETTINGS))); 258 } 259 260 if (!pm.hasSystemFeature(PackageManager.FEATURE_WATCH)) { 261 forwardedIntentsFromManaged.add( 262 new Intent(Settings.ACTION_DREAM_SETTINGS)); 263 } 264 265 if (!pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK)) { 266 forwardedIntentsFromManaged.add( 267 new Intent(Settings.ACTION_AIRPLANE_MODE_SETTINGS)); 268 } 269 270 if (pm.hasSystemFeature(PackageManager.FEATURE_PRINTING)) { 271 notForwardedIntentsFromManaged.add( 272 new Intent(Settings.ACTION_PRINT_SETTINGS)); 273 } 274 275 if (Build.TYPE.equals("user")) { 276 forwardedIntentsFromManaged.add( 277 new Intent(Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS)); 278 } 279 } 280 checkCrossProfileIntentFilters(int flag)281 public boolean checkCrossProfileIntentFilters(int flag) { 282 boolean crossProfileIntentFiltersSet; 283 if (flag == FLAG_INTENTS_FROM_PRIMARY) { 284 crossProfileIntentFiltersSet = checkIntentForwardingFromPrimary(); 285 } else { 286 crossProfileIntentFiltersSet = 287 checkIntentForwardingFromManaged() && 288 checkIntentsWithOptionalForwardingFromManagedAreHandled(); 289 } 290 return crossProfileIntentFiltersSet; 291 } 292 293 /** 294 * Checks if required cross profile intent filters are set for the intents fired from the 295 * primary profile. 296 */ checkIntentForwardingFromPrimary()297 private boolean checkIntentForwardingFromPrimary() { 298 // Get the class name of the intentForwarderActivity in the primary profile by firing an 299 // intent which we know will be forwarded from primary profile to managed profile. 300 ActivityInfo forwarderActivityInfo = 301 getForwarderActivityInfo(ByodHelperActivity.ACTION_QUERY_PROFILE_OWNER); 302 if (forwarderActivityInfo == null) { 303 return false; 304 } 305 306 // Check for intents which can be forwarded to the managed profile. 307 return checkIntentForwarding(forwardedIntentsFromPrimary, 308 forwarderActivityInfo, "from primary profile should be forwarded to the " + 309 "managed profile but is not.", true); 310 } 311 312 /** 313 * Checks that the required intents either have cross profile intent filters set up, or are 314 * handled directly in the managed profile. 315 */ checkIntentsWithOptionalForwardingFromManagedAreHandled()316 private boolean checkIntentsWithOptionalForwardingFromManagedAreHandled() { 317 for (Intent intent : forwardingOptionalIntentsFromManaged) { 318 List<ResolveInfo> resolveInfoList = 319 mContext.getPackageManager().queryIntentActivities(intent, 320 PackageManager.MATCH_DEFAULT_ONLY); 321 322 if (resolveInfoList.isEmpty()) { 323 Log.e(TAG, intent + " should be handled in or forwarded from the managed " + 324 "profile, but it is not."); 325 return false; 326 } 327 } 328 329 return true; 330 } 331 332 /** 333 * Checks if required cross profile intent filters are set for the intents fired from the 334 * managed profile. 335 */ checkIntentForwardingFromManaged()336 private boolean checkIntentForwardingFromManaged() { 337 // Get the class name of the intentForwarderActivity in the managed profile by firing an 338 // intent which we know will be forwarded from managed profile to primary profile. 339 ActivityInfo forwarderActivityInfo = 340 getForwarderActivityInfo(ByodHelperActivity.ACTION_PROFILE_OWNER_STATUS); 341 if (forwarderActivityInfo == null) { 342 return false; 343 } 344 345 boolean success = true; 346 // Check for intents which can be forwarded to the primary profile. 347 success &= checkIntentForwarding(forwardedIntentsFromManaged, 348 forwarderActivityInfo, " from managed profile should be forwarded to the " + 349 "primary profile but is not.", true); 350 351 // Check for intents which cannot be forwarded to the primary profile. 352 success &= checkIntentForwarding(notForwardedIntentsFromManaged, 353 forwarderActivityInfo, "from managed profile should not be forwarded to the " + 354 "primary profile but it is.", false); 355 return success; 356 } 357 358 /** 359 * Checks if the intentForwarderActivity can handle the intent passed. 360 */ canForwarderActivityHandleIntent(Intent intent, ActivityInfo forwarderActivityInfo)361 private boolean canForwarderActivityHandleIntent(Intent intent, 362 ActivityInfo forwarderActivityInfo) { 363 // Get all the activities which can handle the intent. 364 List<ResolveInfo> resolveInfoList = 365 mContext.getPackageManager().queryIntentActivities(intent, 366 PackageManager.MATCH_DEFAULT_ONLY); 367 // Check if intentForwarderActivity is part of the list. 368 for (ResolveInfo resolveInfo : resolveInfoList) { 369 if (forwarderActivityInfo.packageName.equals(resolveInfo.activityInfo.packageName) 370 && forwarderActivityInfo.name.equals(resolveInfo.activityInfo.name)) { 371 return true; 372 } 373 } 374 return false; 375 } 376 377 /** 378 * Returns the class name of the intentForwarderActivity. 379 */ getForwarderActivityInfo(String action)380 private ActivityInfo getForwarderActivityInfo(String action) { 381 Intent intent = new Intent(action); 382 List<ResolveInfo> resolveInfoList = 383 mContext.getPackageManager().queryIntentActivities(intent, 384 PackageManager.MATCH_DEFAULT_ONLY); 385 if (resolveInfoList.isEmpty() || resolveInfoList.size() > 1) { 386 Log.d(TAG, "There should be exactly one activity IntentForwarder which " + 387 "handles the intent " + intent); 388 return null; 389 } 390 return resolveInfoList.get(0).activityInfo; 391 } 392 393 /** 394 * Checks if the intents passed are correctly handled. 395 * @return {@code false} if at least one intent is not handled correctly. 396 */ checkIntentForwarding(ArrayList<Intent> intentList, ActivityInfo expectedForwarderActivityInfo, String errorMessage, boolean canResolve)397 private boolean checkIntentForwarding(ArrayList<Intent> intentList, 398 ActivityInfo expectedForwarderActivityInfo, String errorMessage, boolean canResolve) { 399 boolean success = true; 400 for (Intent intent : intentList) { 401 if (canForwarderActivityHandleIntent(intent, 402 expectedForwarderActivityInfo) != canResolve) { 403 Log.e(TAG, intent + " " + errorMessage); 404 success = false; 405 } 406 } 407 return success; 408 } 409 } 410