blob: 3b73174cf88e237da9f43c706ad732cd9ef5d5f0 [file] [log] [blame]
Jason Monk8f5f7ff2017-10-17 14:12:42 -04001/*
2 * Copyright (C) 2017 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
17package android.app.slice;
18
Jason Monkbf3eedc2018-04-05 20:56:42 -040019import static android.content.pm.PackageManager.PERMISSION_DENIED;
20
Jason Monke2c64512017-12-11 15:14:54 -050021import android.annotation.NonNull;
Jason Monkb9e06a82018-01-16 15:32:53 -050022import android.annotation.Nullable;
Jason Monk5e676a22018-03-08 14:18:55 -050023import android.annotation.SdkConstant;
24import android.annotation.SdkConstant.SdkConstantType;
Jason Monk8f5f7ff2017-10-17 14:12:42 -040025import android.annotation.SystemService;
Jason Monk632def12018-02-01 15:21:16 -050026import android.content.ContentProviderClient;
Jason Monkb9e06a82018-01-16 15:32:53 -050027import android.content.ContentResolver;
Jason Monk8f5f7ff2017-10-17 14:12:42 -040028import android.content.Context;
Jason Monkb9e06a82018-01-16 15:32:53 -050029import android.content.Intent;
Jason Monkf2008872018-02-23 08:59:31 -050030import android.content.pm.PackageManager;
Jason Monk71888552018-03-30 14:14:51 -040031import android.content.pm.PackageManager.PermissionResult;
Jason Monkb9e06a82018-01-16 15:32:53 -050032import android.content.pm.ResolveInfo;
Jason Monk74f5e362017-12-06 08:56:33 -050033import android.net.Uri;
Jason Monk38df2802018-02-22 19:28:12 -050034import android.os.Binder;
Jason Monkb9e06a82018-01-16 15:32:53 -050035import android.os.Bundle;
Jason Monk8f5f7ff2017-10-17 14:12:42 -040036import android.os.Handler;
Jason Monk38df2802018-02-22 19:28:12 -050037import android.os.IBinder;
Jason Monkac112382018-03-23 15:06:35 -040038import android.os.Process;
Jason Monk74f5e362017-12-06 08:56:33 -050039import android.os.RemoteException;
Jason Monk8f5f7ff2017-10-17 14:12:42 -040040import android.os.ServiceManager;
41import android.os.ServiceManager.ServiceNotFoundException;
Jason Monkac112382018-03-23 15:06:35 -040042import android.os.UserHandle;
Jason Monk5f8cc272018-01-16 17:57:20 -050043import android.util.Log;
Jason Monke2c64512017-12-11 15:14:54 -050044
Jason Monkb9e06a82018-01-16 15:32:53 -050045import com.android.internal.util.Preconditions;
46
47import java.util.ArrayList;
Jason Monke2c64512017-12-11 15:14:54 -050048import java.util.Arrays;
Jason Monk5f8cc272018-01-16 17:57:20 -050049import java.util.Collection;
50import java.util.Collections;
Jason Monke2c64512017-12-11 15:14:54 -050051import java.util.List;
Jason Monk8f5f7ff2017-10-17 14:12:42 -040052
53/**
Jason Monke2c64512017-12-11 15:14:54 -050054 * Class to handle interactions with {@link Slice}s.
55 * <p>
56 * The SliceManager manages permissions and pinned state for slices.
Jason Monk8f5f7ff2017-10-17 14:12:42 -040057 */
58@SystemService(Context.SLICE_SERVICE)
59public class SliceManager {
60
Jason Monk5f8cc272018-01-16 17:57:20 -050061 private static final String TAG = "SliceManager";
62
Jason Monke8f8be72018-01-21 10:10:35 -050063 /**
64 * @hide
65 */
66 public static final String ACTION_REQUEST_SLICE_PERMISSION =
67 "android.intent.action.REQUEST_SLICE_PERMISSION";
68
Mady Mellor3267ed82018-02-21 11:42:31 -080069 /**
Jason Monk5e676a22018-03-08 14:18:55 -050070 * Category used to resolve intents that can be rendered as slices.
71 * <p>
72 * This category should be included on intent filters on providers that extend
73 * {@link SliceProvider}.
74 * @see SliceProvider
75 * @see SliceProvider#onMapIntentToUri(Intent)
76 * @see #mapIntentToUri(Intent)
77 */
78 @SdkConstant(SdkConstantType.INTENT_CATEGORY)
79 public static final String CATEGORY_SLICE = "android.app.slice.category.SLICE";
80
81 /**
Mady Mellor3267ed82018-02-21 11:42:31 -080082 * The meta-data key that allows an activity to easily be linked directly to a slice.
83 * <p>
84 * An activity can be statically linked to a slice uri by including a meta-data item
85 * for this key that contains a valid slice uri for the same application declaring
86 * the activity.
Jason Monk39b9fb32018-03-27 10:45:23 -040087 *
88 * <pre class="prettyprint">
89 * {@literal
90 * <activity android:name="com.example.mypkg.MyActivity">
91 * <meta-data android:name="android.metadata.SLICE_URI"
92 * android:value="content://com.example.mypkg/main_slice" />
93 * </activity>}
94 * </pre>
95 *
96 * @see #mapIntentToUri(Intent)
97 * @see SliceProvider#onMapIntentToUri(Intent)
Mady Mellor3267ed82018-02-21 11:42:31 -080098 */
99 public static final String SLICE_METADATA_KEY = "android.metadata.SLICE_URI";
100
Jason Monk8f5f7ff2017-10-17 14:12:42 -0400101 private final ISliceManager mService;
102 private final Context mContext;
Jason Monk38df2802018-02-22 19:28:12 -0500103 private final IBinder mToken = new Binder();
Jason Monk8f5f7ff2017-10-17 14:12:42 -0400104
Jason Monke2c64512017-12-11 15:14:54 -0500105 /**
106 * @hide
107 */
Jason Monk8f5f7ff2017-10-17 14:12:42 -0400108 public SliceManager(Context context, Handler handler) throws ServiceNotFoundException {
109 mContext = context;
110 mService = ISliceManager.Stub.asInterface(
111 ServiceManager.getServiceOrThrow(Context.SLICE_SERVICE));
112 }
Jason Monk74f5e362017-12-06 08:56:33 -0500113
114 /**
Jason Monke2c64512017-12-11 15:14:54 -0500115 * Ensures that a slice is in a pinned state.
116 * <p>
117 * Pinned state is not persisted across reboots, so apps are expected to re-pin any slices
118 * they still care about after a reboot.
Jason Monk632def12018-02-01 15:21:16 -0500119 * <p>
120 * This may only be called by apps that are the default launcher for the device
121 * or the default voice interaction service. Otherwise will throw {@link SecurityException}.
Jason Monke2c64512017-12-11 15:14:54 -0500122 *
123 * @param uri The uri of the slice being pinned.
124 * @param specs The list of supported {@link SliceSpec}s of the callback.
125 * @see SliceProvider#onSlicePinned(Uri)
Jason Monk632def12018-02-01 15:21:16 -0500126 * @see Intent#ACTION_ASSIST
127 * @see Intent#CATEGORY_HOME
Jason Monk74f5e362017-12-06 08:56:33 -0500128 */
Jason Monke2c64512017-12-11 15:14:54 -0500129 public void pinSlice(@NonNull Uri uri, @NonNull List<SliceSpec> specs) {
Jason Monk74f5e362017-12-06 08:56:33 -0500130 try {
Jason Monke2c64512017-12-11 15:14:54 -0500131 mService.pinSlice(mContext.getPackageName(), uri,
Jason Monk38df2802018-02-22 19:28:12 -0500132 specs.toArray(new SliceSpec[specs.size()]), mToken);
Jason Monk74f5e362017-12-06 08:56:33 -0500133 } catch (RemoteException e) {
134 throw e.rethrowFromSystemServer();
135 }
136 }
137
138 /**
Jason Monke2c64512017-12-11 15:14:54 -0500139 * Remove a pin for a slice.
140 * <p>
141 * If the slice has no other pins/callbacks then the slice will be unpinned.
Jason Monk632def12018-02-01 15:21:16 -0500142 * <p>
143 * This may only be called by apps that are the default launcher for the device
144 * or the default voice interaction service. Otherwise will throw {@link SecurityException}.
Jason Monke2c64512017-12-11 15:14:54 -0500145 *
146 * @param uri The uri of the slice being unpinned.
147 * @see #pinSlice
148 * @see SliceProvider#onSliceUnpinned(Uri)
Jason Monk632def12018-02-01 15:21:16 -0500149 * @see Intent#ACTION_ASSIST
150 * @see Intent#CATEGORY_HOME
Jason Monk74f5e362017-12-06 08:56:33 -0500151 */
Jason Monke2c64512017-12-11 15:14:54 -0500152 public void unpinSlice(@NonNull Uri uri) {
Jason Monk74f5e362017-12-06 08:56:33 -0500153 try {
Jason Monk38df2802018-02-22 19:28:12 -0500154 mService.unpinSlice(mContext.getPackageName(), uri, mToken);
Jason Monk74f5e362017-12-06 08:56:33 -0500155 } catch (RemoteException e) {
156 throw e.rethrowFromSystemServer();
157 }
158 }
159
160 /**
Jason Monke2c64512017-12-11 15:14:54 -0500161 * @hide
Jason Monk74f5e362017-12-06 08:56:33 -0500162 */
163 public boolean hasSliceAccess() {
164 try {
165 return mService.hasSliceAccess(mContext.getPackageName());
166 } catch (RemoteException e) {
167 throw e.rethrowFromSystemServer();
168 }
169 }
170
171 /**
Jason Monke2c64512017-12-11 15:14:54 -0500172 * Get the current set of specs for a pinned slice.
173 * <p>
174 * This is the set of specs supported for a specific pinned slice. It will take
175 * into account all clients and returns only specs supported by all.
176 * @see SliceSpec
Jason Monk74f5e362017-12-06 08:56:33 -0500177 */
Jason Monke2c64512017-12-11 15:14:54 -0500178 public @NonNull List<SliceSpec> getPinnedSpecs(Uri uri) {
Jason Monk74f5e362017-12-06 08:56:33 -0500179 try {
Jason Monke2c64512017-12-11 15:14:54 -0500180 return Arrays.asList(mService.getPinnedSpecs(uri, mContext.getPackageName()));
Jason Monk74f5e362017-12-06 08:56:33 -0500181 } catch (RemoteException e) {
182 throw e.rethrowFromSystemServer();
183 }
184 }
185
186 /**
Jason Monkf88d25e2018-03-06 20:13:24 -0500187 * Get the list of currently pinned slices for this app.
188 * @see SliceProvider#onSlicePinned
189 */
190 public @NonNull List<Uri> getPinnedSlices() {
191 try {
192 return Arrays.asList(mService.getPinnedSlices(mContext.getPackageName()));
193 } catch (RemoteException e) {
194 throw e.rethrowFromSystemServer();
195 }
196 }
197
198 /**
Jason Monk5f8cc272018-01-16 17:57:20 -0500199 * Obtains a list of slices that are descendants of the specified Uri.
200 * <p>
201 * Not all slice providers will implement this functionality, in which case,
202 * an empty collection will be returned.
203 *
204 * @param uri The uri to look for descendants under.
205 * @return All slices within the space.
206 * @see SliceProvider#onGetSliceDescendants(Uri)
207 */
208 public @NonNull Collection<Uri> getSliceDescendants(@NonNull Uri uri) {
209 ContentResolver resolver = mContext.getContentResolver();
Jason Monk632def12018-02-01 15:21:16 -0500210 try (ContentProviderClient provider = resolver.acquireContentProviderClient(uri)) {
Jason Monk5f8cc272018-01-16 17:57:20 -0500211 Bundle extras = new Bundle();
212 extras.putParcelable(SliceProvider.EXTRA_BIND_URI, uri);
Jason Monk632def12018-02-01 15:21:16 -0500213 final Bundle res = provider.call(SliceProvider.METHOD_GET_DESCENDANTS, null, extras);
Jason Monk5f8cc272018-01-16 17:57:20 -0500214 return res.getParcelableArrayList(SliceProvider.EXTRA_SLICE_DESCENDANTS);
215 } catch (RemoteException e) {
216 Log.e(TAG, "Unable to get slice descendants", e);
Jason Monk5f8cc272018-01-16 17:57:20 -0500217 }
218 return Collections.emptyList();
219 }
220
221 /**
Jason Monkb9e06a82018-01-16 15:32:53 -0500222 * Turns a slice Uri into slice content.
223 *
224 * @param uri The URI to a slice provider
225 * @param supportedSpecs List of supported specs.
226 * @return The Slice provided by the app or null if none is given.
227 * @see Slice
228 */
229 public @Nullable Slice bindSlice(@NonNull Uri uri, @NonNull List<SliceSpec> supportedSpecs) {
230 Preconditions.checkNotNull(uri, "uri");
231 ContentResolver resolver = mContext.getContentResolver();
Jason Monk632def12018-02-01 15:21:16 -0500232 try (ContentProviderClient provider = resolver.acquireContentProviderClient(uri)) {
233 if (provider == null) {
234 throw new IllegalArgumentException("Unknown URI " + uri);
235 }
Jason Monkb9e06a82018-01-16 15:32:53 -0500236 Bundle extras = new Bundle();
237 extras.putParcelable(SliceProvider.EXTRA_BIND_URI, uri);
238 extras.putParcelableArrayList(SliceProvider.EXTRA_SUPPORTED_SPECS,
239 new ArrayList<>(supportedSpecs));
Jason Monk632def12018-02-01 15:21:16 -0500240 final Bundle res = provider.call(SliceProvider.METHOD_SLICE, null, extras);
Jason Monkb9e06a82018-01-16 15:32:53 -0500241 Bundle.setDefusable(res, true);
242 if (res == null) {
243 return null;
244 }
245 return res.getParcelable(SliceProvider.EXTRA_SLICE);
246 } catch (RemoteException e) {
247 // Arbitrary and not worth documenting, as Activity
248 // Manager will kill this process shortly anyway.
249 return null;
Jason Monkb9e06a82018-01-16 15:32:53 -0500250 }
251 }
252
253 /**
Jason Monkf2008872018-02-23 08:59:31 -0500254 * Turns a slice intent into a slice uri. Expects an explicit intent.
Jason Monk5e676a22018-03-08 14:18:55 -0500255 * <p>
256 * This goes through a several stage resolution process to determine if any slice
257 * can represent this intent.
Jason Monk39b9fb32018-03-27 10:45:23 -0400258 * <ol>
259 * <li> If the intent contains data that {@link ContentResolver#getType} is
260 * {@link SliceProvider#SLICE_TYPE} then the data will be returned.</li>
261 * <li>If the intent with {@link #CATEGORY_SLICE} added resolves to a provider, then
Jason Monk5e676a22018-03-08 14:18:55 -0500262 * the provider will be asked to {@link SliceProvider#onMapIntentToUri} and that result
Jason Monk39b9fb32018-03-27 10:45:23 -0400263 * will be returned.</li>
264 * <li>Lastly, if the intent explicitly points at an activity, and that activity has
Jason Monk5e676a22018-03-08 14:18:55 -0500265 * meta-data for key {@link #SLICE_METADATA_KEY}, then the Uri specified there will be
Jason Monk39b9fb32018-03-27 10:45:23 -0400266 * returned.</li>
267 * <li>If no slice is found, then {@code null} is returned.</li>
268 * </ol>
Jason Monk7b8fef22018-01-30 16:04:14 -0500269 * @param intent The intent associated with a slice.
Jason Monkf2008872018-02-23 08:59:31 -0500270 * @return The Slice Uri provided by the app or null if none exists.
Jason Monk7b8fef22018-01-30 16:04:14 -0500271 * @see Slice
272 * @see SliceProvider#onMapIntentToUri(Intent)
273 * @see Intent
274 */
275 public @Nullable Uri mapIntentToUri(@NonNull Intent intent) {
276 Preconditions.checkNotNull(intent, "intent");
Jason Monk135f4172018-03-15 17:48:47 -0400277 Preconditions.checkArgument(intent.getComponent() != null || intent.getPackage() != null
278 || intent.getData() != null,
Jason Monk7b8fef22018-01-30 16:04:14 -0500279 "Slice intent must be explicit %s", intent);
280 ContentResolver resolver = mContext.getContentResolver();
281
282 // Check if the intent has data for the slice uri on it and use that
283 final Uri intentData = intent.getData();
284 if (intentData != null && SliceProvider.SLICE_TYPE.equals(resolver.getType(intentData))) {
285 return intentData;
286 }
287 // Otherwise ask the app
Jason Monk5e676a22018-03-08 14:18:55 -0500288 Intent queryIntent = new Intent(intent);
289 if (!queryIntent.hasCategory(CATEGORY_SLICE)) {
290 queryIntent.addCategory(CATEGORY_SLICE);
291 }
Jason Monk7b8fef22018-01-30 16:04:14 -0500292 List<ResolveInfo> providers =
Jason Monk5e676a22018-03-08 14:18:55 -0500293 mContext.getPackageManager().queryIntentContentProviders(queryIntent, 0);
Jason Monk7b8fef22018-01-30 16:04:14 -0500294 if (providers == null || providers.isEmpty()) {
Jason Monkf2008872018-02-23 08:59:31 -0500295 // There are no providers, see if this activity has a direct link.
296 ResolveInfo resolve = mContext.getPackageManager().resolveActivity(intent,
297 PackageManager.GET_META_DATA);
298 if (resolve != null && resolve.activityInfo != null
299 && resolve.activityInfo.metaData != null
300 && resolve.activityInfo.metaData.containsKey(SLICE_METADATA_KEY)) {
301 return Uri.parse(
302 resolve.activityInfo.metaData.getString(SLICE_METADATA_KEY));
303 }
304 return null;
Jason Monk7b8fef22018-01-30 16:04:14 -0500305 }
306 String authority = providers.get(0).providerInfo.authority;
307 Uri uri = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
308 .authority(authority).build();
Jason Monk632def12018-02-01 15:21:16 -0500309 try (ContentProviderClient provider = resolver.acquireContentProviderClient(uri)) {
310 if (provider == null) {
311 throw new IllegalArgumentException("Unknown URI " + uri);
312 }
Jason Monk7b8fef22018-01-30 16:04:14 -0500313 Bundle extras = new Bundle();
314 extras.putParcelable(SliceProvider.EXTRA_INTENT, intent);
Jason Monk632def12018-02-01 15:21:16 -0500315 final Bundle res = provider.call(SliceProvider.METHOD_MAP_ONLY_INTENT, null, extras);
Jason Monk7b8fef22018-01-30 16:04:14 -0500316 if (res == null) {
317 return null;
318 }
319 return res.getParcelable(SliceProvider.EXTRA_SLICE);
320 } catch (RemoteException e) {
321 // Arbitrary and not worth documenting, as Activity
322 // Manager will kill this process shortly anyway.
323 return null;
Jason Monk7b8fef22018-01-30 16:04:14 -0500324 }
325 }
326
327 /**
Jason Monkb9e06a82018-01-16 15:32:53 -0500328 * Turns a slice intent into slice content. Expects an explicit intent. If there is no
329 * {@link android.content.ContentProvider} associated with the given intent this will throw
330 * {@link IllegalArgumentException}.
331 *
332 * @param intent The intent associated with a slice.
333 * @param supportedSpecs List of supported specs.
334 * @return The Slice provided by the app or null if none is given.
335 * @see Slice
336 * @see SliceProvider#onMapIntentToUri(Intent)
337 * @see Intent
338 */
339 public @Nullable Slice bindSlice(@NonNull Intent intent,
340 @NonNull List<SliceSpec> supportedSpecs) {
341 Preconditions.checkNotNull(intent, "intent");
Jason Monk135f4172018-03-15 17:48:47 -0400342 Preconditions.checkArgument(intent.getComponent() != null || intent.getPackage() != null
343 || intent.getData() != null,
Jason Monk7b8fef22018-01-30 16:04:14 -0500344 "Slice intent must be explicit %s", intent);
Jason Monkb9e06a82018-01-16 15:32:53 -0500345 ContentResolver resolver = mContext.getContentResolver();
346
347 // Check if the intent has data for the slice uri on it and use that
348 final Uri intentData = intent.getData();
349 if (intentData != null && SliceProvider.SLICE_TYPE.equals(resolver.getType(intentData))) {
350 return bindSlice(intentData, supportedSpecs);
351 }
352 // Otherwise ask the app
353 List<ResolveInfo> providers =
354 mContext.getPackageManager().queryIntentContentProviders(intent, 0);
Jason Monk7b8fef22018-01-30 16:04:14 -0500355 if (providers == null || providers.isEmpty()) {
Jason Monkf2008872018-02-23 08:59:31 -0500356 // There are no providers, see if this activity has a direct link.
357 ResolveInfo resolve = mContext.getPackageManager().resolveActivity(intent,
358 PackageManager.GET_META_DATA);
359 if (resolve != null && resolve.activityInfo != null
360 && resolve.activityInfo.metaData != null
361 && resolve.activityInfo.metaData.containsKey(SLICE_METADATA_KEY)) {
362 return bindSlice(Uri.parse(resolve.activityInfo.metaData
363 .getString(SLICE_METADATA_KEY)), supportedSpecs);
364 }
365 return null;
Jason Monkb9e06a82018-01-16 15:32:53 -0500366 }
367 String authority = providers.get(0).providerInfo.authority;
368 Uri uri = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
369 .authority(authority).build();
Jason Monk632def12018-02-01 15:21:16 -0500370 try (ContentProviderClient provider = resolver.acquireContentProviderClient(uri)) {
371 if (provider == null) {
372 throw new IllegalArgumentException("Unknown URI " + uri);
373 }
Jason Monkb9e06a82018-01-16 15:32:53 -0500374 Bundle extras = new Bundle();
375 extras.putParcelable(SliceProvider.EXTRA_INTENT, intent);
376 extras.putParcelableArrayList(SliceProvider.EXTRA_SUPPORTED_SPECS,
377 new ArrayList<>(supportedSpecs));
Jason Monk632def12018-02-01 15:21:16 -0500378 final Bundle res = provider.call(SliceProvider.METHOD_MAP_INTENT, null, extras);
Jason Monkb9e06a82018-01-16 15:32:53 -0500379 if (res == null) {
380 return null;
381 }
382 return res.getParcelable(SliceProvider.EXTRA_SLICE);
383 } catch (RemoteException e) {
384 // Arbitrary and not worth documenting, as Activity
385 // Manager will kill this process shortly anyway.
386 return null;
Jason Monkb9e06a82018-01-16 15:32:53 -0500387 }
388 }
389
390 /**
Jason Monk71888552018-03-30 14:14:51 -0400391 * Determine whether a particular process and user ID has been granted
392 * permission to access a specific slice URI.
393 *
394 * @param uri The uri that is being checked.
395 * @param pid The process ID being checked against. Must be &gt; 0.
396 * @param uid The user ID being checked against. A uid of 0 is the root
397 * user, which will pass every permission check.
398 *
399 * @return {@link PackageManager#PERMISSION_GRANTED} if the given
400 * pid/uid is allowed to access that uri, or
401 * {@link PackageManager#PERMISSION_DENIED} if it is not.
402 *
403 * @see #grantSlicePermission(String, Uri)
404 */
405 public @PermissionResult int checkSlicePermission(@NonNull Uri uri, int pid, int uid) {
Jason Monkbf3eedc2018-04-05 20:56:42 -0400406 try {
407 return mService.checkSlicePermission(uri, null, pid, uid, null);
408 } catch (RemoteException e) {
409 throw e.rethrowFromSystemServer();
410 }
Jason Monk71888552018-03-30 14:14:51 -0400411 }
412
413 /**
414 * Grant permission to access a specific slice Uri to another package.
415 *
416 * @param toPackage The package you would like to allow to access the Uri.
417 * @param uri The Uri you would like to grant access to.
418 *
419 * @see #revokeSlicePermission
420 */
421 public void grantSlicePermission(@NonNull String toPackage, @NonNull Uri uri) {
Jason Monkbf3eedc2018-04-05 20:56:42 -0400422 try {
423 mService.grantSlicePermission(mContext.getPackageName(), toPackage, uri);
424 } catch (RemoteException e) {
425 throw e.rethrowFromSystemServer();
426 }
Jason Monk71888552018-03-30 14:14:51 -0400427 }
428
429 /**
430 * Remove permissions to access a particular content provider Uri
431 * that were previously added with {@link #grantSlicePermission} for a specific target
432 * package. The given Uri will match all previously granted Uris that are the same or a
433 * sub-path of the given Uri. That is, revoking "content://foo/target" will
434 * revoke both "content://foo/target" and "content://foo/target/sub", but not
435 * "content://foo". It will not remove any prefix grants that exist at a
436 * higher level.
437 *
438 * @param toPackage The package you would like to allow to access the Uri.
439 * @param uri The Uri you would like to revoke access to.
440 *
441 * @see #grantSlicePermission
442 */
443 public void revokeSlicePermission(@NonNull String toPackage, @NonNull Uri uri) {
Jason Monkbf3eedc2018-04-05 20:56:42 -0400444 try {
445 mService.revokeSlicePermission(mContext.getPackageName(), toPackage, uri);
446 } catch (RemoteException e) {
447 throw e.rethrowFromSystemServer();
448 }
Jason Monk71888552018-03-30 14:14:51 -0400449 }
450
451 /**
Jason Monke8f8be72018-01-21 10:10:35 -0500452 * Does the permission check to see if a caller has access to a specific slice.
453 * @hide
454 */
Jason Monk42e03f82018-03-30 11:26:56 -0400455 public void enforceSlicePermission(Uri uri, String pkg, int pid, int uid,
456 String[] autoGrantPermissions) {
Jason Monke8f8be72018-01-21 10:10:35 -0500457 try {
Jason Monkac112382018-03-23 15:06:35 -0400458 if (UserHandle.isSameApp(uid, Process.myUid())) {
459 return;
460 }
Jason Monke8f8be72018-01-21 10:10:35 -0500461 if (pkg == null) {
462 throw new SecurityException("No pkg specified");
463 }
Jason Monk42e03f82018-03-30 11:26:56 -0400464 int result = mService.checkSlicePermission(uri, pkg, pid, uid, autoGrantPermissions);
Jason Monke8f8be72018-01-21 10:10:35 -0500465 if (result == PERMISSION_DENIED) {
466 throw new SecurityException("User " + uid + " does not have slice permission for "
467 + uri + ".");
468 }
Jason Monke8f8be72018-01-21 10:10:35 -0500469 } catch (RemoteException e) {
470 throw e.rethrowFromSystemServer();
471 }
472 }
473
474 /**
475 * Called by SystemUI to grant a slice permission after a dialog is shown.
476 * @hide
477 */
478 public void grantPermissionFromUser(Uri uri, String pkg, boolean allSlices) {
479 try {
480 mService.grantPermissionFromUser(uri, pkg, mContext.getPackageName(), allSlices);
481 } catch (RemoteException e) {
482 throw e.rethrowFromSystemServer();
483 }
484 }
Jason Monk8f5f7ff2017-10-17 14:12:42 -0400485}