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