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