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