• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.DownloadManager;
20 import android.app.admin.DevicePolicyManager;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.content.pm.ActivityInfo;
24 import android.content.pm.PackageManager;
25 import android.content.pm.ResolveInfo;
26 import android.media.audiofx.AudioEffect;
27 import android.net.Uri;
28 import android.nfc.cardemulation.CardEmulation;
29 import android.os.Build;
30 import android.os.Environment;
31 import android.os.UserManager;
32 import android.provider.AlarmClock;
33 import android.provider.CalendarContract.Events;
34 import android.provider.MediaStore;
35 import android.provider.Settings;
36 import android.util.Log;
37 
38 import java.util.ArrayList;
39 import java.util.Arrays;
40 import java.util.List;
41 
42 /**
43  * Helper class for testing if the required cross profile intent filters are set during the
44  * managed provisioning.
45  */
46 public class IntentFiltersTestHelper {
47 
48     private static final String TAG = "IntentFiltersTestHelper";
49 
50     // These are the intents which can be forwarded to the managed profile.
51     private static final ArrayList<Intent> forwardedIntentsFromPrimary =
52             new ArrayList<>(Arrays.asList(
53                 new Intent(Intent.ACTION_SEND).setType("*/*"),
54                 new Intent(Intent.ACTION_SEND_MULTIPLE).setType("*/*")
55             ));
56 
57     // These are the intents which can be forwarded to the primary profile.
58     private static final ArrayList<Intent> forwardedIntentsFromManaged =
59             new ArrayList<>(Arrays.asList(
60                 new Intent(AlarmClock.ACTION_SET_ALARM),
61                 new Intent(AlarmClock.ACTION_SET_TIMER),
62                 new Intent(AlarmClock.ACTION_SHOW_ALARMS),
63                 new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS),
64                 new Intent(Settings.ACTION_CAPTIONING_SETTINGS),
65                 new Intent(Settings.ACTION_DATE_SETTINGS),
66                 new Intent(Settings.ACTION_DEVICE_INFO_SETTINGS),
67                 new Intent(Settings.ACTION_DISPLAY_SETTINGS),
68                 new Intent(Settings.ACTION_LOCALE_SETTINGS),
69                 new Intent(Settings.ACTION_PRIVACY_SETTINGS),
70                 new Intent(Settings.ACTION_SETTINGS),
71                 new Intent(Settings.ACTION_WIRELESS_SETTINGS),
72                 new Intent("android.net.vpn.SETTINGS"),
73                 new Intent(Settings.ACTION_VPN_SETTINGS),
74                 new Intent(Settings.ACTION_BATTERY_SAVER_SETTINGS),
75                 new Intent("android.settings.LICENSE"),
76                 new Intent("android.settings.NOTIFICATION_SETTINGS"),
77                 new Intent("android.settings.ZEN_MODE_SETTINGS"),
78                 new Intent("com.android.settings.ACCESSIBILITY_COLOR_SPACE_SETTINGS"),
79                 new Intent("com.android.settings.TTS_SETTINGS"),
80                 new Intent(Settings.ACTION_INTERNAL_STORAGE_SETTINGS),
81                 new Intent(Intent.ACTION_GET_CONTENT).setType("*/*").addCategory(
82                         Intent.CATEGORY_OPENABLE),
83                 new Intent(Intent.ACTION_OPEN_DOCUMENT).setType("*/*").addCategory(
84                         Intent.CATEGORY_OPENABLE)
85             ));
86 
87     // These are the intents which can either be handled directly in the managed profile,
88     // or be forwarded to the primary profile.
89     private static final ArrayList<Intent> forwardingOptionalIntentsFromManaged =
90             new ArrayList<>(Arrays.asList(
91                 new Intent(Settings.ACTION_SYNC_SETTINGS),
92                 new Intent(Settings.ACTION_ADD_ACCOUNT),
93                 new Intent(Settings.ACTION_MANAGE_APPLICATIONS_SETTINGS),
94                 new Intent(Settings.ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS),
95                 new Intent(Settings.ACTION_APPLICATION_SETTINGS),
96                 new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD),
97                 new Intent("android.settings.ACCOUNT_SYNC_SETTINGS")
98             ));
99 
100     // These are the intents which cannot be forwarded to the primary profile.
101     private static final ArrayList<Intent> notForwardedIntentsFromManaged =
102             new ArrayList<>(Arrays.asList(
103                 new Intent(Intent.ACTION_INSERT).setData(
104                         Uri.parse("content://browser/bookmarks")),
105                 new Intent(Intent.ACTION_VIEW).setData(
106                         Uri.parse("http://www.example.com")).addCategory(
107                         Intent.CATEGORY_BROWSABLE),
108                 new Intent(Intent.ACTION_SENDTO).setData(
109                         Uri.parse("mailto:user@example.com")),
110                 new Intent(Intent.ACTION_VIEW).setData(
111                         Uri.parse("mailto:user@example.com")).addCategory(
112                         Intent.CATEGORY_BROWSABLE),
113                 new Intent(Intent.ACTION_VIEW).setData(
114                         Uri.parse("geo:0,0?q=BuckinghamPalace")),
115                 new Intent(Intent.ACTION_VIEW).setData(
116                         Uri.parse("http://example.com/oceans.mp4")).setType("video/mp4"),
117                 new Intent(Intent.ACTION_VIEW).setData(
118                         Uri.parse("http://www.example.com/horse.mp3")).setType("audio/*"),
119                 new Intent(MediaStore.INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH),
120                 new Intent(Intent.ACTION_VIEW).setData(
121                         Uri.parse("market://details?id=com.android.chrome")).addCategory(
122                         Intent.CATEGORY_BROWSABLE),
123                 new Intent(Intent.ACTION_WEB_SEARCH),
124                 new Intent(Settings.ACTION_SEARCH_SETTINGS),
125                 new Intent(Intent.ACTION_MANAGE_NETWORK_USAGE),
126                 new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).setData(
127                         Uri.parse("package:com.android.chrome")),
128                 new Intent(Intent.ACTION_INSERT).setData(Events.CONTENT_URI),
129                 new Intent(DownloadManager.ACTION_VIEW_DOWNLOADS)
130             ));
131 
132     // This flag specifies we are dealing with intents fired from the primary profile.
133     public static final int FLAG_INTENTS_FROM_PRIMARY = 1;
134     // This flag specifies we are dealing with intents fired from the managed profile.
135     public static final int FLAG_INTENTS_FROM_MANAGED = 2;
136 
137     private Context mContext;
138 
IntentFiltersTestHelper(Context context)139     IntentFiltersTestHelper(Context context) {
140         mContext = context;
141 
142         addIntentsThatDependOnDeviceConfigs();
143         addIntentsThatDependOnDeviceFeatures();
144     }
145 
146     // Return whether the intent can be resolved in the current profile
canResolveIntent(PackageManager pm, Intent intent)147     private boolean canResolveIntent(PackageManager pm, Intent intent) {
148         return intent.resolveActivity(pm) != null;
149     }
150 
addIntentsThatDependOnDeviceConfigs()151     private void addIntentsThatDependOnDeviceConfigs() {
152         if (UserManager.supportsMultipleUsers()) {
153             forwardedIntentsFromManaged.add(
154                     new Intent("android.settings.USER_SETTINGS"));
155         }
156     }
157 
addIntentsThatDependOnDeviceFeatures()158     private void addIntentsThatDependOnDeviceFeatures() {
159         PackageManager pm = mContext.getPackageManager();
160 
161         if (pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)
162                 && pm.hasSystemFeature(PackageManager.FEATURE_TELECOM)) {
163             forwardedIntentsFromManaged.addAll(Arrays.asList(
164                     new Intent("android.intent.action.CALL_EMERGENCY").setData(
165                             Uri.parse("tel:123")),
166                     new Intent("android.intent.action.CALL_PRIVILEGED").setData(
167                             Uri.parse("tel:123")),
168                     new Intent(Intent.ACTION_VIEW).setData(Uri.parse("tel:123")).addCategory(
169                             Intent.CATEGORY_BROWSABLE),
170                     new Intent(Settings.ACTION_NETWORK_OPERATOR_SETTINGS),
171                     new Intent(Settings.ACTION_DATA_ROAMING_SETTINGS),
172                     new Intent(Intent.ACTION_SENDTO).setData(Uri.parse("sms:07700900100")),
173                     new Intent(Intent.ACTION_SENDTO).setData(Uri.parse("smsto:07700900100")),
174                     new Intent(Intent.ACTION_SENDTO).setData(Uri.parse("mms:07700900100")),
175                     new Intent(Intent.ACTION_SENDTO).setData(Uri.parse("mmsto:07700900100")),
176                     new Intent(Intent.ACTION_VIEW).setData(
177                             Uri.parse("sms:07700900100?body=Hello%20world")).addCategory(
178                             Intent.CATEGORY_BROWSABLE),
179                     new Intent(Intent.ACTION_VIEW).setData(
180                             Uri.parse("smsto:07700900100?body=Hello%20world")).addCategory(
181                             Intent.CATEGORY_BROWSABLE),
182                     new Intent(Intent.ACTION_VIEW).setData(
183                             Uri.parse("mms:07700900100?body=Hello%20world")).addCategory(
184                             Intent.CATEGORY_BROWSABLE),
185                     new Intent(Intent.ACTION_VIEW).setData(
186                             Uri.parse("mmsto:07700900100?body=Hello%20world")).addCategory(
187                             Intent.CATEGORY_BROWSABLE),
188                     new Intent(Settings.ACTION_APN_SETTINGS)));
189             notForwardedIntentsFromManaged.addAll(Arrays.asList(
190                     new Intent(Intent.ACTION_DIAL).setData(Uri.parse("tel:123")),
191                     new Intent(Intent.ACTION_CALL).setData(Uri.parse("tel:123"))));
192         }
193 
194         if (pm.hasSystemFeature(PackageManager.FEATURE_NFC)) {
195             forwardedIntentsFromManaged.add(new Intent(Settings.ACTION_NFC_SETTINGS));
196         }
197 
198         if (pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION)) {
199             forwardedIntentsFromManaged.addAll(Arrays.asList(
200                     new Intent(CardEmulation.ACTION_CHANGE_DEFAULT),
201                     new Intent(Settings.ACTION_NFC_PAYMENT_SETTINGS)));
202         }
203 
204         if (pm.hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
205             forwardingOptionalIntentsFromManaged.addAll(Arrays.asList(
206                     new Intent(MediaStore.ACTION_IMAGE_CAPTURE),
207                     new Intent(MediaStore.ACTION_VIDEO_CAPTURE),
208                     new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA),
209                     new Intent(MediaStore.INTENT_ACTION_VIDEO_CAMERA),
210                     new Intent(MediaStore.ACTION_IMAGE_CAPTURE_SECURE),
211                     new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE)));
212 
213             if (com.android.providers.media.flags.Flags.motionPhotoIntent()) {
214                 Intent motionPhotoIntent = new Intent(MediaStore.ACTION_MOTION_PHOTO_CAPTURE);
215                 if (canResolveIntent(pm, motionPhotoIntent)) {
216                     forwardingOptionalIntentsFromManaged.add(motionPhotoIntent);
217                 }
218 
219                 Intent motionPhotoSecureIntent =
220                         new Intent(MediaStore.ACTION_MOTION_PHOTO_CAPTURE_SECURE);
221                 if (canResolveIntent(pm, motionPhotoSecureIntent)) {
222                     forwardingOptionalIntentsFromManaged.add(motionPhotoSecureIntent);
223                 }
224             }
225         }
226 
227         final String state = Environment.getExternalStorageState();
228         if (Environment.MEDIA_MOUNTED.equals(state)) {
229             forwardedIntentsFromManaged.add(
230                     new Intent(Settings.ACTION_MEMORY_CARD_SETTINGS));
231         }
232 
233         if (pm.hasSystemFeature(PackageManager.FEATURE_WIFI)) {
234             forwardedIntentsFromManaged.addAll(Arrays.asList(
235                     new Intent(Settings.ACTION_WIFI_IP_SETTINGS),
236                     new Intent(Settings.ACTION_WIFI_SETTINGS)));
237         }
238 
239         if (pm.hasSystemFeature(PackageManager.FEATURE_MICROPHONE)) {
240             forwardingOptionalIntentsFromManaged.add(
241                     new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION));
242         }
243 
244         if (pm.hasSystemFeature(PackageManager.FEATURE_LOCATION)) {
245             forwardingOptionalIntentsFromManaged.add(
246                     new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS));
247         }
248 
249         if (pm.hasSystemFeature(PackageManager.FEATURE_AUDIO_OUTPUT)) {
250             forwardedIntentsFromManaged.addAll(Arrays.asList(
251                     new Intent(Settings.ACTION_SOUND_SETTINGS),
252                     new Intent("android.settings.ACTION_OTHER_SOUND_SETTINGS")));
253             notForwardedIntentsFromManaged.add(
254                     new Intent(AudioEffect.ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL));
255         }
256 
257         if (pm.hasSystemFeature(PackageManager.FEATURE_HOME_SCREEN)) {
258             forwardingOptionalIntentsFromManaged.add(
259                     new Intent(Settings.ACTION_HOME_SETTINGS));
260         }
261 
262         if (pm.hasSystemFeature(PackageManager.FEATURE_INPUT_METHODS)) {
263             notForwardedIntentsFromManaged.addAll(Arrays.asList(
264                     new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS),
265                     new Intent(Settings.ACTION_INPUT_METHOD_SUBTYPE_SETTINGS)));
266         }
267 
268         if (!pm.hasSystemFeature(PackageManager.FEATURE_WATCH)) {
269             forwardedIntentsFromManaged.add(
270                     new Intent(Settings.ACTION_DREAM_SETTINGS));
271         }
272 
273         if (!pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
274             forwardedIntentsFromManaged.add(
275                     new Intent(Settings.ACTION_AIRPLANE_MODE_SETTINGS));
276         }
277 
278         if (pm.hasSystemFeature(PackageManager.FEATURE_PRINTING)) {
279             notForwardedIntentsFromManaged.add(
280                     new Intent(Settings.ACTION_PRINT_SETTINGS));
281         }
282 
283         if (Build.TYPE.equals("user")) {
284             forwardedIntentsFromManaged.add(
285                     new Intent(Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS));
286         }
287     }
288 
checkCrossProfileIntentFilters(int flag)289     public boolean checkCrossProfileIntentFilters(int flag) {
290         boolean crossProfileIntentFiltersSet;
291         if (flag == FLAG_INTENTS_FROM_PRIMARY) {
292             crossProfileIntentFiltersSet = checkIntentForwardingFromPrimary();
293         } else {
294             crossProfileIntentFiltersSet =
295                     checkIntentForwardingFromManaged() &&
296                             checkIntentsWithOptionalForwardingFromManagedAreHandled();
297         }
298         return crossProfileIntentFiltersSet;
299     }
300 
301     /**
302      * Checks if required cross profile intent filters are set for the intents fired from the
303      * primary profile.
304      */
checkIntentForwardingFromPrimary()305     private boolean checkIntentForwardingFromPrimary() {
306         // Get the class name of the intentForwarderActivity in the primary profile by firing an
307         // intent which we know will be forwarded from primary profile to managed profile.
308         ActivityInfo forwarderActivityInfo =
309                 getForwarderActivityInfo(ByodHelperActivity.ACTION_QUERY_PROFILE_OWNER);
310         if (forwarderActivityInfo == null) {
311             return false;
312         }
313 
314         // Check for intents which can be forwarded to the managed profile.
315         return checkIntentForwarding(forwardedIntentsFromPrimary,
316                 forwarderActivityInfo, "from primary profile should be forwarded to the " +
317                 "managed profile but is not.", true);
318     }
319 
320     /**
321      * Checks that the required intents either have cross profile intent filters set up, or are
322      * handled directly in the managed profile.
323      */
checkIntentsWithOptionalForwardingFromManagedAreHandled()324     private boolean checkIntentsWithOptionalForwardingFromManagedAreHandled() {
325         for (Intent intent : forwardingOptionalIntentsFromManaged) {
326             List<ResolveInfo> resolveInfoList =
327                     mContext.getPackageManager().queryIntentActivities(intent,
328                             PackageManager.MATCH_DEFAULT_ONLY);
329 
330             if (resolveInfoList.isEmpty()) {
331                 Log.e(TAG, intent + " should be handled in or forwarded from the managed " +
332                         "profile, but it is not.");
333                 return false;
334             }
335         }
336 
337         return true;
338     }
339 
340     /**
341      * Checks if required cross profile intent filters are set for the intents fired from the
342      * managed profile.
343      */
checkIntentForwardingFromManaged()344     private boolean checkIntentForwardingFromManaged() {
345         // Get the class name of the intentForwarderActivity in the managed profile by firing an
346         // intent which we know will be forwarded from managed profile to primary profile.
347         ActivityInfo forwarderActivityInfo =
348                 getForwarderActivityInfo(ByodHelperActivity.ACTION_PROFILE_OWNER_STATUS);
349         if (forwarderActivityInfo == null) {
350             return false;
351         }
352 
353         boolean success = true;
354         // Check for intents which can be forwarded to the primary profile.
355         success &= checkIntentForwarding(forwardedIntentsFromManaged,
356                 forwarderActivityInfo, " from managed profile should be forwarded to the " +
357                 "primary profile but is not.", true);
358 
359         // Check for intents which cannot be forwarded to the primary profile.
360         success &= checkIntentForwarding(notForwardedIntentsFromManaged,
361                 forwarderActivityInfo, "from managed profile should not be forwarded to the " +
362                 "primary profile but it is.", false);
363         return success;
364     }
365 
366     /**
367      * Checks if the intentForwarderActivity can handle the intent passed.
368      */
canForwarderActivityHandleIntent(Intent intent, ActivityInfo forwarderActivityInfo)369     private boolean canForwarderActivityHandleIntent(Intent intent,
370             ActivityInfo forwarderActivityInfo) {
371         // Get all the activities which can handle the intent.
372         List<ResolveInfo> resolveInfoList =
373                 mContext.getPackageManager().queryIntentActivities(intent,
374                         PackageManager.MATCH_DEFAULT_ONLY);
375         // Check if intentForwarderActivity is part of the list.
376         for (ResolveInfo resolveInfo : resolveInfoList) {
377             if (forwarderActivityInfo.packageName.equals(resolveInfo.activityInfo.packageName)
378                     && forwarderActivityInfo.name.equals(resolveInfo.activityInfo.name)) {
379                 return true;
380             }
381         }
382         return false;
383     }
384 
385     /**
386      * Returns the class name of the intentForwarderActivity.
387      */
getForwarderActivityInfo(String action)388     private ActivityInfo getForwarderActivityInfo(String action) {
389         Intent intent = new Intent(action);
390         List<ResolveInfo> resolveInfoList =
391                 mContext.getPackageManager().queryIntentActivities(intent,
392                         PackageManager.MATCH_DEFAULT_ONLY);
393         if (resolveInfoList.isEmpty() || resolveInfoList.size() > 1) {
394             Log.d(TAG, "There should be exactly one activity IntentForwarder which " +
395                     "handles the intent " + intent);
396             return null;
397         }
398         return resolveInfoList.get(0).activityInfo;
399     }
400 
401     /**
402      * Checks if the intents passed are correctly handled.
403      * @return {@code false} if at least one intent is not handled correctly.
404      */
checkIntentForwarding(ArrayList<Intent> intentList, ActivityInfo expectedForwarderActivityInfo, String errorMessage, boolean canResolve)405     private boolean checkIntentForwarding(ArrayList<Intent> intentList,
406             ActivityInfo expectedForwarderActivityInfo, String errorMessage, boolean canResolve) {
407         boolean success = true;
408         for (Intent intent : intentList) {
409             if (canForwarderActivityHandleIntent(intent,
410                     expectedForwarderActivityInfo) != canResolve) {
411                 Log.e(TAG, intent + " " + errorMessage);
412                 success = false;
413             }
414         }
415         return success;
416     }
417 }
418