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(DevicePolicyManager.ACTION_SET_NEW_PASSWORD),
80                 new Intent("android.net.vpn.SETTINGS"),
81                 new Intent(Settings.ACTION_VPN_SETTINGS),
82                 new Intent("android.settings.ACCOUNT_SYNC_SETTINGS"),
83                 new Intent(Settings.ACTION_BATTERY_SAVER_SETTINGS),
84                 new Intent("android.settings.LICENSE"),
85                 new Intent("android.settings.NOTIFICATION_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         addIntentsThatDependOnDeviceConfigs();
144         addIntentsThatDependOnDeviceFeatures();
145     }
146 
addIntentsThatDependOnDeviceConfigs()147     private void addIntentsThatDependOnDeviceConfigs() {
148         if (UserManager.supportsMultipleUsers()) {
149             forwardedIntentsFromManaged.add(
150                     new Intent("android.settings.USER_SETTINGS"));
151         }
152     }
153 
addIntentsThatDependOnDeviceFeatures()154     private void addIntentsThatDependOnDeviceFeatures() {
155         PackageManager pm = mContext.getPackageManager();
156 
157         if (pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
158             forwardedIntentsFromManaged.addAll(Arrays.asList(
159                     new Intent(Intent.ACTION_DIAL).setData(Uri.parse("tel:123")),
160                     new Intent("android.intent.action.CALL_EMERGENCY").setData(
161                             Uri.parse("tel:123")),
162                     new Intent("android.intent.action.CALL_PRIVILEGED").setData(
163                             Uri.parse("tel:123")),
164                     new Intent(Intent.ACTION_VIEW).setData(Uri.parse("tel:123")).addCategory(
165                             Intent.CATEGORY_BROWSABLE),
166                     new Intent(Settings.ACTION_NETWORK_OPERATOR_SETTINGS),
167                     new Intent(Settings.ACTION_DATA_ROAMING_SETTINGS),
168                     new Intent(Intent.ACTION_SENDTO).setData(Uri.parse("sms:07700900100")),
169                     new Intent(Intent.ACTION_SENDTO).setData(Uri.parse("smsto:07700900100")),
170                     new Intent(Intent.ACTION_SENDTO).setData(Uri.parse("mms:07700900100")),
171                     new Intent(Intent.ACTION_SENDTO).setData(Uri.parse("mmsto:07700900100")),
172                     new Intent(Intent.ACTION_VIEW).setData(
173                             Uri.parse("sms:07700900100?body=Hello%20world")).addCategory(
174                             Intent.CATEGORY_BROWSABLE),
175                     new Intent(Intent.ACTION_VIEW).setData(
176                             Uri.parse("smsto:07700900100?body=Hello%20world")).addCategory(
177                             Intent.CATEGORY_BROWSABLE),
178                     new Intent(Intent.ACTION_VIEW).setData(
179                             Uri.parse("mms:07700900100?body=Hello%20world")).addCategory(
180                             Intent.CATEGORY_BROWSABLE),
181                     new Intent(Intent.ACTION_VIEW).setData(
182                             Uri.parse("mmsto:07700900100?body=Hello%20world")).addCategory(
183                             Intent.CATEGORY_BROWSABLE),
184                     new Intent(Settings.ACTION_APN_SETTINGS)));
185             notForwardedIntentsFromManaged
186                     .add(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             forwardedIntentsFromManaged.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             forwardedIntentsFromManaged.addAll(Arrays.asList(
225                     new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION),
226                     new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH)));
227         }
228 
229         if (pm.hasSystemFeature(PackageManager.FEATURE_LOCATION)) {
230             forwardedIntentsFromManaged.add(
231                     new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS));
232         }
233 
234         if (pm.hasSystemFeature(PackageManager.FEATURE_AUDIO_OUTPUT)) {
235             forwardedIntentsFromManaged.addAll(Arrays.asList(
236                     new Intent(Settings.ACTION_SOUND_SETTINGS),
237                     new Intent("android.settings.ACTION_OTHER_SOUND_SETTINGS")));
238             notForwardedIntentsFromManaged.add(
239                     new Intent(AudioEffect.ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL));
240         }
241 
242         if (pm.hasSystemFeature(PackageManager.FEATURE_HOME_SCREEN)) {
243             forwardedIntentsFromManaged.add(
244                     new Intent(Settings.ACTION_HOME_SETTINGS));
245         }
246 
247         if (pm.hasSystemFeature(PackageManager.FEATURE_INPUT_METHODS)) {
248             forwardedIntentsFromManaged.addAll(Arrays.asList(
249                     new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS),
250                     new Intent(Settings.ACTION_INPUT_METHOD_SUBTYPE_SETTINGS)));
251             notForwardedIntentsFromManaged.add(
252                     new Intent("android.settings.SHOW_INPUT_METHOD_PICKER"));
253         }
254 
255         if (!pm.hasSystemFeature(PackageManager.FEATURE_WATCH)) {
256             forwardedIntentsFromManaged.add(
257                     new Intent(Settings.ACTION_DREAM_SETTINGS));
258         }
259 
260         if (!pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
261             forwardedIntentsFromManaged.add(
262                     new Intent(Settings.ACTION_AIRPLANE_MODE_SETTINGS));
263         }
264 
265         if (pm.hasSystemFeature(PackageManager.FEATURE_PRINTING)) {
266             notForwardedIntentsFromManaged.add(
267                     new Intent(Settings.ACTION_PRINT_SETTINGS));
268         }
269 
270         if (Build.TYPE.equals("user")) {
271             forwardedIntentsFromManaged.add(
272                     new Intent(Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS));
273         }
274     }
275 
checkCrossProfileIntentFilters(int flag)276     public boolean checkCrossProfileIntentFilters(int flag) {
277         boolean crossProfileIntentFiltersSet;
278         if (flag == FLAG_INTENTS_FROM_PRIMARY) {
279             crossProfileIntentFiltersSet = checkForIntentsFromPrimary();
280         } else {
281             crossProfileIntentFiltersSet = checkForIntentsFromManaged();
282         }
283         return crossProfileIntentFiltersSet;
284     }
285 
286     /**
287      * Checks if required cross profile intent filters are set for the intents fired from the
288      * primary profile.
289      */
checkForIntentsFromPrimary()290     private boolean checkForIntentsFromPrimary() {
291         // Get the class name of the intentForwarderActivity in the primary profile by firing an
292         // intent which we know will be forwarded from primary profile to managed profile.
293         ActivityInfo forwarderActivityInfo =
294                 getForwarderActivityInfo(ByodHelperActivity.ACTION_QUERY_PROFILE_OWNER);
295         if (forwarderActivityInfo == null) {
296             return false;
297         }
298 
299         // Check for intents which can be forwarded to the managed profile.
300         return checkForIntentsNotHandled(forwardedIntentsFromPrimary,
301                 forwarderActivityInfo, "from primary profile should be forwarded to the " +
302                 "managed profile but is not.", true);
303     }
304 
305     /**
306      * Checks if required cross profile intent filters are set for the intents fired from the
307      * managed profile.
308      */
checkForIntentsFromManaged()309     private boolean checkForIntentsFromManaged() {
310         // Get the class name of the intentForwarderActivity in the managed profile by firing an
311         // intent which we know will be forwarded from managed profile to primary profile.
312         ActivityInfo forwarderActivityInfo =
313                 getForwarderActivityInfo(ByodHelperActivity.ACTION_PROFILE_OWNER_STATUS);
314         if (forwarderActivityInfo == null) {
315             return false;
316         }
317 
318         boolean success = true;
319         // Check for intents which can be forwarded to the primary profile.
320         success &= checkForIntentsNotHandled(forwardedIntentsFromManaged,
321                 forwarderActivityInfo, " from managed profile should be forwarded to the " +
322                 "primary profile but is not.", true);
323 
324         // Check for intents which cannot be forwarded to the primary profile.
325         success &= checkForIntentsNotHandled(notForwardedIntentsFromManaged,
326                 forwarderActivityInfo, "from managed profile should not be forwarded to the " +
327                 "primary profile but it is.", false);
328         return success;
329     }
330 
331     /**
332      * Checks if the intentForwarderActivity can handle the intent passed.
333      */
canForwarderActivityHandleIntent(Intent intent, ActivityInfo forwarderActivityInfo)334     private boolean canForwarderActivityHandleIntent(Intent intent,
335             ActivityInfo forwarderActivityInfo) {
336         // Get all the activities which can handle the intent.
337         List<ResolveInfo> resolveInfoList =
338                 mContext.getPackageManager().queryIntentActivities(intent,
339                         PackageManager.MATCH_DEFAULT_ONLY);
340         // Check if intentForwarderActivity is part of the list.
341         for (ResolveInfo resolveInfo : resolveInfoList) {
342             if (forwarderActivityInfo.packageName.equals(resolveInfo.activityInfo.packageName)
343                     && forwarderActivityInfo.name.equals(resolveInfo.activityInfo.name)) {
344                 return true;
345             }
346         }
347         return false;
348     }
349 
350     /**
351      * Returns the class name of the intentForwarderActivity.
352      */
getForwarderActivityInfo(String action)353     private ActivityInfo getForwarderActivityInfo(String action) {
354         Intent intent = new Intent(action);
355         List<ResolveInfo> resolveInfoList =
356                 mContext.getPackageManager().queryIntentActivities(intent,
357                         PackageManager.MATCH_DEFAULT_ONLY);
358         if (resolveInfoList.isEmpty() || resolveInfoList.size() > 1) {
359             Log.d(TAG, "There should be exactly one activity IntentForwarder which " +
360                     "handles the intent " + intent);
361             return null;
362         }
363         return resolveInfoList.get(0).activityInfo;
364     }
365 
366     /**
367      * Checks if the intents passed are correctly handled.
368      * @return {@code false} if at least one intent is not handled correctly.
369      */
checkForIntentsNotHandled(ArrayList<Intent> intentList, ActivityInfo expectedForwarderActivityInfo, String errorMessage, boolean canResolve)370     private boolean checkForIntentsNotHandled(ArrayList<Intent> intentList,
371             ActivityInfo expectedForwarderActivityInfo, String errorMessage, boolean canResolve) {
372         boolean success = true;
373         for (Intent intent : intentList) {
374             if (canForwarderActivityHandleIntent(intent,
375                     expectedForwarderActivityInfo) != canResolve) {
376                 Log.e(TAG, intent + " " + errorMessage);
377                 success = false;
378             }
379         }
380         return success;
381     }
382 }
383