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