• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2014, 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 package com.android.managedprovisioning.task;
17 
18 import static android.content.pm.PackageManager.ONLY_IF_NO_MATCH_FOUND;
19 import static android.content.pm.PackageManager.SKIP_CURRENT_PROFILE;
20 import static android.speech.RecognizerIntent.ACTION_RECOGNIZE_SPEECH;
21 import static com.android.internal.util.Preconditions.checkNotNull;
22 
23 import android.content.Context;
24 import android.content.Intent;
25 import android.content.pm.PackageManager;
26 import android.content.pm.UserInfo;
27 import android.hardware.usb.UsbManager;
28 import android.os.UserManager;
29 import android.provider.AlarmClock;
30 import android.provider.MediaStore;
31 
32 import com.android.internal.annotations.VisibleForTesting;
33 import com.android.managedprovisioning.common.ProvisionLogger;
34 import com.android.managedprovisioning.task.CrossProfileIntentFilter.Direction;
35 
36 import java.util.Arrays;
37 import java.util.List;
38 
39 /**
40  * Class to set CrossProfileIntentFilters during managed profile creation, and reset them after an
41  * ota.
42  */
43 public class CrossProfileIntentFiltersSetter {
44 
45     // Intents from profile to parent user
46 
47     /** Emergency call intent with mime type is always resolved by primary user. */
48     private static final CrossProfileIntentFilter EMERGENCY_CALL_MIME =
49             new CrossProfileIntentFilter.Builder(Direction.TO_PARENT, SKIP_CURRENT_PROFILE)
50                     .addAction(Intent.ACTION_CALL_EMERGENCY)
51                     .addAction(Intent.ACTION_CALL_PRIVILEGED)
52                     .addCategory(Intent.CATEGORY_DEFAULT)
53                     .addCategory(Intent.CATEGORY_BROWSABLE)
54                     .addDataType("vnd.android.cursor.item/phone")
55                     .addDataType("vnd.android.cursor.item/phone_v2")
56                     .addDataType("vnd.android.cursor.item/person")
57                     .addDataType("vnd.android.cursor.dir/calls")
58                     .addDataType("vnd.android.cursor.item/calls")
59                     .build();
60 
61     /** Emergency call intent with data schemes is always resolved by primary user. */
62     private static final CrossProfileIntentFilter EMERGENCY_CALL_DATA =
63             new CrossProfileIntentFilter.Builder(Direction.TO_PARENT, SKIP_CURRENT_PROFILE)
64                     .addAction(Intent.ACTION_CALL_EMERGENCY)
65                     .addAction(Intent.ACTION_CALL_PRIVILEGED)
66                     .addCategory(Intent.CATEGORY_DEFAULT)
67                     .addCategory(Intent.CATEGORY_BROWSABLE)
68                     .addDataScheme("tel")
69                     .addDataScheme("sip")
70                     .addDataScheme("voicemail")
71                     .build();
72 
73     /** Dial intent with mime type can be handled by either managed profile or its parent user. */
74     private static final CrossProfileIntentFilter DIAL_MIME =
75             new CrossProfileIntentFilter.Builder(Direction.TO_PARENT, ONLY_IF_NO_MATCH_FOUND)
76                     .addAction(Intent.ACTION_DIAL)
77                     .addAction(Intent.ACTION_VIEW)
78                     .addCategory(Intent.CATEGORY_DEFAULT)
79                     .addCategory(Intent.CATEGORY_BROWSABLE)
80                     .addDataType("vnd.android.cursor.item/phone")
81                     .addDataType("vnd.android.cursor.item/phone_v2")
82                     .addDataType("vnd.android.cursor.item/person")
83                     .addDataType("vnd.android.cursor.dir/calls")
84                     .addDataType("vnd.android.cursor.item/calls")
85                     .build();
86 
87     /** Dial intent with data scheme can be handled by either managed profile or its parent user. */
88     private static final CrossProfileIntentFilter DIAL_DATA =
89             new CrossProfileIntentFilter.Builder(Direction.TO_PARENT, ONLY_IF_NO_MATCH_FOUND)
90                     .addAction(Intent.ACTION_DIAL)
91                     .addAction(Intent.ACTION_VIEW)
92                     .addCategory(Intent.CATEGORY_DEFAULT)
93                     .addCategory(Intent.CATEGORY_BROWSABLE)
94                     .addDataScheme("tel")
95                     .addDataScheme("sip")
96                     .addDataScheme("voicemail")
97                     .build();
98 
99     /**
100      * Dial intent with no data scheme or type can be handled by either managed profile or its
101      * parent user.
102      */
103     private static final CrossProfileIntentFilter DIAL_RAW =
104             new CrossProfileIntentFilter.Builder(Direction.TO_PARENT, ONLY_IF_NO_MATCH_FOUND)
105                     .addAction(Intent.ACTION_DIAL)
106                     .addCategory(Intent.CATEGORY_DEFAULT)
107                     .addCategory(Intent.CATEGORY_BROWSABLE)
108                     .build();
109 
110     /** Pressing the call button can be handled by either managed profile or its parent user. */
111     private static final CrossProfileIntentFilter CALL_BUTTON =
112             new CrossProfileIntentFilter.Builder(Direction.TO_PARENT, ONLY_IF_NO_MATCH_FOUND)
113                     .addAction(Intent.ACTION_CALL_BUTTON)
114                     .addCategory(Intent.CATEGORY_DEFAULT)
115                     .build();
116 
117     /** SMS and MMS are exclusively handled by the primary user. */
118     private static final CrossProfileIntentFilter SMS_MMS =
119             new CrossProfileIntentFilter.Builder(Direction.TO_PARENT, SKIP_CURRENT_PROFILE)
120                     .addAction(Intent.ACTION_VIEW)
121                     .addAction(Intent.ACTION_SENDTO)
122                     .addCategory(Intent.CATEGORY_DEFAULT)
123                     .addCategory(Intent.CATEGORY_BROWSABLE)
124                     .addDataScheme("sms")
125                     .addDataScheme("smsto")
126                     .addDataScheme("mms")
127                     .addDataScheme("mmsto")
128                     .build();
129 
130     /** Mobile network settings is always shown in the primary user. */
131     private static final CrossProfileIntentFilter MOBILE_NETWORK_SETTINGS =
132             new CrossProfileIntentFilter.Builder(Direction.TO_PARENT, SKIP_CURRENT_PROFILE)
133                     .addAction(android.provider.Settings.ACTION_DATA_ROAMING_SETTINGS)
134                     .addAction(android.provider.Settings.ACTION_NETWORK_OPERATOR_SETTINGS)
135                     .addCategory(Intent.CATEGORY_DEFAULT)
136                     .build();
137 
138     /** HOME intent is always resolved by the primary user. */
139     @VisibleForTesting
140     static final CrossProfileIntentFilter HOME =
141             new CrossProfileIntentFilter.Builder(Direction.TO_PARENT, SKIP_CURRENT_PROFILE)
142                     .addAction(Intent.ACTION_MAIN)
143                     .addCategory(Intent.CATEGORY_DEFAULT)
144                     .addCategory(Intent.CATEGORY_HOME)
145                     .build();
146 
147     /** Get content can be forwarded to parent user. */
148     private static final CrossProfileIntentFilter GET_CONTENT =
149             new CrossProfileIntentFilter.Builder(Direction.TO_PARENT, 0)
150                     .addAction(Intent.ACTION_GET_CONTENT)
151                     .addCategory(Intent.CATEGORY_DEFAULT)
152                     .addCategory(Intent.CATEGORY_OPENABLE)
153                     .addDataType("*/*")
154                     .build();
155 
156     /** Open document intent can be forwarded to parent user. */
157     private static final CrossProfileIntentFilter OPEN_DOCUMENT =
158             new CrossProfileIntentFilter.Builder(Direction.TO_PARENT, 0)
159                     .addAction(Intent.ACTION_OPEN_DOCUMENT)
160                     .addCategory(Intent.CATEGORY_DEFAULT)
161                     .addCategory(Intent.CATEGORY_OPENABLE)
162                     .addDataType("*/*")
163                     .build();
164 
165     /** Pick for any data type can be forwarded to parent user. */
166     private static final CrossProfileIntentFilter ACTION_PICK_DATA =
167             new CrossProfileIntentFilter.Builder(Direction.TO_PARENT, 0)
168                     .addAction(Intent.ACTION_PICK)
169                     .addCategory(Intent.CATEGORY_DEFAULT)
170                     .addDataType("*/*")
171                     .build();
172 
173     /** Pick without data type can be forwarded to parent user. */
174     private static final CrossProfileIntentFilter ACTION_PICK_RAW =
175             new CrossProfileIntentFilter.Builder(Direction.TO_PARENT, 0)
176                     .addAction(Intent.ACTION_PICK)
177                     .addCategory(Intent.CATEGORY_DEFAULT)
178                     .build();
179 
180     /** Speech recognition can be performed by primary user. */
181     private static final CrossProfileIntentFilter RECOGNIZE_SPEECH =
182             new CrossProfileIntentFilter.Builder(Direction.TO_PARENT, 0)
183                     .addAction(ACTION_RECOGNIZE_SPEECH)
184                     .addCategory(Intent.CATEGORY_DEFAULT)
185                     .build();
186 
187     /** Media capture can be performed by primary user. */
188     private static final CrossProfileIntentFilter MEDIA_CAPTURE =
189             new CrossProfileIntentFilter.Builder(Direction.TO_PARENT, 0)
190                     .addAction(MediaStore.ACTION_IMAGE_CAPTURE)
191                     .addAction(MediaStore.ACTION_IMAGE_CAPTURE_SECURE)
192                     .addAction(MediaStore.ACTION_VIDEO_CAPTURE)
193                     .addAction(MediaStore.Audio.Media.RECORD_SOUND_ACTION)
194                     .addAction(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA)
195                     .addAction(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE)
196                     .addAction(MediaStore.INTENT_ACTION_VIDEO_CAMERA)
197                     .addCategory(Intent.CATEGORY_DEFAULT)
198                     .build();
199 
200     /** Alarm setting can be performed by primary user. */
201     private static final CrossProfileIntentFilter SET_ALARM =
202             new CrossProfileIntentFilter.Builder(Direction.TO_PARENT, 0)
203                     .addAction(AlarmClock.ACTION_SET_ALARM)
204                     .addAction(AlarmClock.ACTION_SHOW_ALARMS)
205                     .addAction(AlarmClock.ACTION_SET_TIMER)
206                     .addCategory(Intent.CATEGORY_DEFAULT)
207                     .build();
208 
209     // Intents from parent to profile user
210 
211     /** ACTION_SEND can be forwarded to the managed profile on user's choice. */
212     @VisibleForTesting
213     static final CrossProfileIntentFilter ACTION_SEND =
214             new CrossProfileIntentFilter.Builder(Direction.TO_PROFILE, 0)
215                     .addAction(Intent.ACTION_SEND)
216                     .addAction(Intent.ACTION_SEND_MULTIPLE)
217                     .addCategory(Intent.CATEGORY_DEFAULT)
218                     .addDataType("*/*")
219                     .build();
220 
221     /** USB devices attached can get forwarded to the profile. */
222     private static final CrossProfileIntentFilter USB_DEVICE_ATTACHED =
223             new CrossProfileIntentFilter.Builder(Direction.TO_PROFILE, 0)
224                     .addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED)
225                     .addAction(UsbManager.ACTION_USB_ACCESSORY_ATTACHED)
226                     .addCategory(Intent.CATEGORY_DEFAULT)
227                     .build();
228 
229     @VisibleForTesting
230     static final List<CrossProfileIntentFilter> FILTERS = Arrays.asList(
231             EMERGENCY_CALL_MIME,
232             EMERGENCY_CALL_DATA,
233             DIAL_MIME,
234             DIAL_DATA,
235             DIAL_RAW,
236             CALL_BUTTON,
237             SMS_MMS,
238             SET_ALARM,
239             MEDIA_CAPTURE,
240             RECOGNIZE_SPEECH,
241             ACTION_PICK_RAW,
242             ACTION_PICK_DATA,
243             OPEN_DOCUMENT,
244             GET_CONTENT,
245             USB_DEVICE_ATTACHED,
246             ACTION_SEND,
247             HOME,
248             MOBILE_NETWORK_SETTINGS);
249 
250     private final PackageManager mPackageManager;
251     private final UserManager mUserManager;
252 
CrossProfileIntentFiltersSetter(Context context)253     public CrossProfileIntentFiltersSetter(Context context) {
254         this(context.getPackageManager(),
255                 (UserManager) context.getSystemService(Context.USER_SERVICE));
256     }
257 
258     @VisibleForTesting
CrossProfileIntentFiltersSetter(PackageManager packageManager, UserManager userManager)259     CrossProfileIntentFiltersSetter(PackageManager packageManager, UserManager userManager) {
260         mPackageManager = checkNotNull(packageManager);
261         mUserManager = checkNotNull(userManager);
262     }
263 
264     /**
265      * Sets all default cross profile intent filters from {@code parentUserId} to
266      * {@code managedProfileUserId}.
267      */
setFilters(int parentUserId, int managedProfileUserId)268     public void setFilters(int parentUserId, int managedProfileUserId) {
269         ProvisionLogger.logd("Setting cross-profile intent filters");
270 
271         for (CrossProfileIntentFilter filter : FILTERS) {
272             if (filter.direction == Direction.TO_PARENT) {
273                 mPackageManager.addCrossProfileIntentFilter(filter.filter, managedProfileUserId,
274                         parentUserId, filter.flags);
275             } else {
276                 mPackageManager.addCrossProfileIntentFilter(filter.filter, parentUserId,
277                         managedProfileUserId, filter.flags);
278             }
279         }
280     }
281 
282     /**
283      * Reset the cross profile intent filters between {@code userId} and all of its managed profiles
284      * if any.
285      */
resetFilters(int userId)286     public void resetFilters(int userId) {
287         List<UserInfo> profiles = mUserManager.getProfiles(userId);
288         if (profiles.size() <= 1) {
289             return;
290         }
291 
292         // Removes cross profile intent filters from the parent to all the managed profiles.
293         mPackageManager.clearCrossProfileIntentFilters(userId);
294 
295         // For each managed profile reset cross profile intent filters
296         for (UserInfo profile : profiles) {
297             if (!profile.isManagedProfile()) {
298                 continue;
299             }
300             mPackageManager.clearCrossProfileIntentFilters(profile.id);
301             setFilters(userId, profile.id);
302         }
303     }
304 
305 }
306