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