Home | History | Annotate | Download | only in managedprovisioning
      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 (at) example.com")),
    117                 new Intent(Intent.ACTION_VIEW).setData(
    118                         Uri.parse("mailto:user (at) 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 
    146     IntentFiltersTestHelper(Context context) {
    147         mContext = context;
    148 
    149         addIntentsThatDependOnDeviceConfigs();
    150         addIntentsThatDependOnDeviceFeatures();
    151     }
    152 
    153     private void addIntentsThatDependOnDeviceConfigs() {
    154         if (UserManager.supportsMultipleUsers()) {
    155             forwardedIntentsFromManaged.add(
    156                     new Intent("android.settings.USER_SETTINGS"));
    157         }
    158     }
    159 
    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(Intent.ACTION_DIAL).setData(Uri.parse("tel:123")),
    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
    192                     .add(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             forwardedIntentsFromManaged.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 
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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