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