blob: 22df6c03aee25aa097090837b2c5f2d5270bb276 [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 Monk2d3932e2018-03-08 11:31:26 -050043import android.util.ArraySet;
Jason Monk5f8cc272018-01-16 17:57:20 -050044import android.util.Log;
Jason Monke2c64512017-12-11 15:14:54 -050045
Jason Monkb9e06a82018-01-16 15:32:53 -050046import com.android.internal.util.Preconditions;
47
48import java.util.ArrayList;
Jason Monke2c64512017-12-11 15:14:54 -050049import java.util.Arrays;
Jason Monk5f8cc272018-01-16 17:57:20 -050050import java.util.Collection;
51import java.util.Collections;
Jason Monke2c64512017-12-11 15:14:54 -050052import java.util.List;
Jason Monk2d3932e2018-03-08 11:31:26 -050053import java.util.Set;
Jason Monk8f5f7ff2017-10-17 14:12:42 -040054
55/**
Jason Monke2c64512017-12-11 15:14:54 -050056 * Class to handle interactions with {@link Slice}s.
57 * <p>
58 * The SliceManager manages permissions and pinned state for slices.
Jason Monk8f5f7ff2017-10-17 14:12:42 -040059 */
60@SystemService(Context.SLICE_SERVICE)
61public class SliceManager {
62
Jason Monk5f8cc272018-01-16 17:57:20 -050063 private static final String TAG = "SliceManager";
64
Jason Monke8f8be72018-01-21 10:10:35 -050065 /**
66 * @hide
67 */
68 public static final String ACTION_REQUEST_SLICE_PERMISSION =
Jason Monk0c179a92018-04-18 10:37:19 -040069 "com.android.intent.action.REQUEST_SLICE_PERMISSION";
Jason Monke8f8be72018-01-21 10:10:35 -050070
Mady Mellor3267ed82018-02-21 11:42:31 -080071 /**
Jason Monk5e676a22018-03-08 14:18:55 -050072 * Category used to resolve intents that can be rendered as slices.
73 * <p>
74 * This category should be included on intent filters on providers that extend
75 * {@link SliceProvider}.
76 * @see SliceProvider
77 * @see SliceProvider#onMapIntentToUri(Intent)
78 * @see #mapIntentToUri(Intent)
79 */
80 @SdkConstant(SdkConstantType.INTENT_CATEGORY)
81 public static final String CATEGORY_SLICE = "android.app.slice.category.SLICE";
82
83 /**
Mady Mellor3267ed82018-02-21 11:42:31 -080084 * The meta-data key that allows an activity to easily be linked directly to a slice.
85 * <p>
86 * An activity can be statically linked to a slice uri by including a meta-data item
87 * for this key that contains a valid slice uri for the same application declaring
88 * the activity.
Jason Monk39b9fb32018-03-27 10:45:23 -040089 *
90 * <pre class="prettyprint">
91 * {@literal
92 * <activity android:name="com.example.mypkg.MyActivity">
93 * <meta-data android:name="android.metadata.SLICE_URI"
94 * android:value="content://com.example.mypkg/main_slice" />
95 * </activity>}
96 * </pre>
97 *
98 * @see #mapIntentToUri(Intent)
99 * @see SliceProvider#onMapIntentToUri(Intent)
Mady Mellor3267ed82018-02-21 11:42:31 -0800100 */
101 public static final String SLICE_METADATA_KEY = "android.metadata.SLICE_URI";
102
Jason Monk8f5f7ff2017-10-17 14:12:42 -0400103 private final ISliceManager mService;
104 private final Context mContext;
Jason Monk38df2802018-02-22 19:28:12 -0500105 private final IBinder mToken = new Binder();
Jason Monk8f5f7ff2017-10-17 14:12:42 -0400106
Jason Monke2c64512017-12-11 15:14:54 -0500107 /**
108 * @hide
109 */
Jason Monk8f5f7ff2017-10-17 14:12:42 -0400110 public SliceManager(Context context, Handler handler) throws ServiceNotFoundException {
111 mContext = context;
112 mService = ISliceManager.Stub.asInterface(
113 ServiceManager.getServiceOrThrow(Context.SLICE_SERVICE));
114 }
Jason Monk74f5e362017-12-06 08:56:33 -0500115
116 /**
Jason Monke2c64512017-12-11 15:14:54 -0500117 * Ensures that a slice is in a pinned state.
118 * <p>
119 * Pinned state is not persisted across reboots, so apps are expected to re-pin any slices
120 * they still care about after a reboot.
Jason Monk632def12018-02-01 15:21:16 -0500121 * <p>
122 * This may only be called by apps that are the default launcher for the device
123 * or the default voice interaction service. Otherwise will throw {@link SecurityException}.
Jason Monke2c64512017-12-11 15:14:54 -0500124 *
125 * @param uri The uri of the slice being pinned.
126 * @param specs The list of supported {@link SliceSpec}s of the callback.
127 * @see SliceProvider#onSlicePinned(Uri)
Jason Monk632def12018-02-01 15:21:16 -0500128 * @see Intent#ACTION_ASSIST
129 * @see Intent#CATEGORY_HOME
Jason Monk74f5e362017-12-06 08:56:33 -0500130 */
Jason Monk2d3932e2018-03-08 11:31:26 -0500131 public void pinSlice(@NonNull Uri uri, @NonNull Set<SliceSpec> specs) {
Jason Monk74f5e362017-12-06 08:56:33 -0500132 try {
Jason Monke2c64512017-12-11 15:14:54 -0500133 mService.pinSlice(mContext.getPackageName(), uri,
Jason Monk38df2802018-02-22 19:28:12 -0500134 specs.toArray(new SliceSpec[specs.size()]), mToken);
Jason Monk74f5e362017-12-06 08:56:33 -0500135 } catch (RemoteException e) {
136 throw e.rethrowFromSystemServer();
137 }
138 }
139
140 /**
Jason Monk2d3932e2018-03-08 11:31:26 -0500141 * @deprecated TO BE REMOVED
Jeff Sharkey3990ee12018-04-11 10:19:55 -0600142 * @removed
Jason Monk2d3932e2018-03-08 11:31:26 -0500143 */
144 @Deprecated
145 public void pinSlice(@NonNull Uri uri, @NonNull List<SliceSpec> specs) {
146 pinSlice(uri, new ArraySet<>(specs));
147 }
148
149 /**
Jason Monke2c64512017-12-11 15:14:54 -0500150 * Remove a pin for a slice.
151 * <p>
152 * If the slice has no other pins/callbacks then the slice will be unpinned.
Jason Monk632def12018-02-01 15:21:16 -0500153 * <p>
154 * This may only be called by apps that are the default launcher for the device
155 * or the default voice interaction service. Otherwise will throw {@link SecurityException}.
Jason Monke2c64512017-12-11 15:14:54 -0500156 *
157 * @param uri The uri of the slice being unpinned.
158 * @see #pinSlice
159 * @see SliceProvider#onSliceUnpinned(Uri)
Jason Monk632def12018-02-01 15:21:16 -0500160 * @see Intent#ACTION_ASSIST
161 * @see Intent#CATEGORY_HOME
Jason Monk74f5e362017-12-06 08:56:33 -0500162 */
Jason Monke2c64512017-12-11 15:14:54 -0500163 public void unpinSlice(@NonNull Uri uri) {
Jason Monk74f5e362017-12-06 08:56:33 -0500164 try {
Jason Monk38df2802018-02-22 19:28:12 -0500165 mService.unpinSlice(mContext.getPackageName(), uri, mToken);
Jason Monk74f5e362017-12-06 08:56:33 -0500166 } catch (RemoteException e) {
167 throw e.rethrowFromSystemServer();
168 }
169 }
170
171 /**
Jason Monke2c64512017-12-11 15:14:54 -0500172 * @hide
Jason Monk74f5e362017-12-06 08:56:33 -0500173 */
174 public boolean hasSliceAccess() {
175 try {
176 return mService.hasSliceAccess(mContext.getPackageName());
177 } catch (RemoteException e) {
178 throw e.rethrowFromSystemServer();
179 }
180 }
181
182 /**
Jason Monke2c64512017-12-11 15:14:54 -0500183 * Get the current set of specs for a pinned slice.
184 * <p>
185 * This is the set of specs supported for a specific pinned slice. It will take
186 * into account all clients and returns only specs supported by all.
187 * @see SliceSpec
Jason Monk74f5e362017-12-06 08:56:33 -0500188 */
Jason Monk2d3932e2018-03-08 11:31:26 -0500189 public @NonNull Set<SliceSpec> getPinnedSpecs(Uri uri) {
Jason Monk74f5e362017-12-06 08:56:33 -0500190 try {
Jason Monk2d3932e2018-03-08 11:31:26 -0500191 return new ArraySet<>(Arrays.asList(mService.getPinnedSpecs(uri,
192 mContext.getPackageName())));
Jason Monk74f5e362017-12-06 08:56:33 -0500193 } catch (RemoteException e) {
194 throw e.rethrowFromSystemServer();
195 }
196 }
197
198 /**
Jason Monkf88d25e2018-03-06 20:13:24 -0500199 * Get the list of currently pinned slices for this app.
200 * @see SliceProvider#onSlicePinned
201 */
202 public @NonNull List<Uri> getPinnedSlices() {
203 try {
204 return Arrays.asList(mService.getPinnedSlices(mContext.getPackageName()));
205 } catch (RemoteException e) {
206 throw e.rethrowFromSystemServer();
207 }
208 }
209
210 /**
Jason Monk5f8cc272018-01-16 17:57:20 -0500211 * Obtains a list of slices that are descendants of the specified Uri.
212 * <p>
213 * Not all slice providers will implement this functionality, in which case,
214 * an empty collection will be returned.
215 *
216 * @param uri The uri to look for descendants under.
217 * @return All slices within the space.
218 * @see SliceProvider#onGetSliceDescendants(Uri)
219 */
220 public @NonNull Collection<Uri> getSliceDescendants(@NonNull Uri uri) {
221 ContentResolver resolver = mContext.getContentResolver();
Jason Monk632def12018-02-01 15:21:16 -0500222 try (ContentProviderClient provider = resolver.acquireContentProviderClient(uri)) {
Jason Monk5f8cc272018-01-16 17:57:20 -0500223 Bundle extras = new Bundle();
224 extras.putParcelable(SliceProvider.EXTRA_BIND_URI, uri);
Jason Monk632def12018-02-01 15:21:16 -0500225 final Bundle res = provider.call(SliceProvider.METHOD_GET_DESCENDANTS, null, extras);
Jason Monk5f8cc272018-01-16 17:57:20 -0500226 return res.getParcelableArrayList(SliceProvider.EXTRA_SLICE_DESCENDANTS);
227 } catch (RemoteException e) {
228 Log.e(TAG, "Unable to get slice descendants", e);
Jason Monk5f8cc272018-01-16 17:57:20 -0500229 }
230 return Collections.emptyList();
231 }
232
233 /**
Jason Monkb9e06a82018-01-16 15:32:53 -0500234 * Turns a slice Uri into slice content.
235 *
236 * @param uri The URI to a slice provider
237 * @param supportedSpecs List of supported specs.
238 * @return The Slice provided by the app or null if none is given.
239 * @see Slice
240 */
Jason Monk2d3932e2018-03-08 11:31:26 -0500241 public @Nullable Slice bindSlice(@NonNull Uri uri, @NonNull Set<SliceSpec> supportedSpecs) {
Jason Monkb9e06a82018-01-16 15:32:53 -0500242 Preconditions.checkNotNull(uri, "uri");
243 ContentResolver resolver = mContext.getContentResolver();
Jason Monk632def12018-02-01 15:21:16 -0500244 try (ContentProviderClient provider = resolver.acquireContentProviderClient(uri)) {
245 if (provider == null) {
246 throw new IllegalArgumentException("Unknown URI " + uri);
247 }
Jason Monkb9e06a82018-01-16 15:32:53 -0500248 Bundle extras = new Bundle();
249 extras.putParcelable(SliceProvider.EXTRA_BIND_URI, uri);
250 extras.putParcelableArrayList(SliceProvider.EXTRA_SUPPORTED_SPECS,
251 new ArrayList<>(supportedSpecs));
Jason Monk632def12018-02-01 15:21:16 -0500252 final Bundle res = provider.call(SliceProvider.METHOD_SLICE, null, extras);
Jason Monkb9e06a82018-01-16 15:32:53 -0500253 Bundle.setDefusable(res, true);
254 if (res == null) {
255 return null;
256 }
257 return res.getParcelable(SliceProvider.EXTRA_SLICE);
258 } catch (RemoteException e) {
259 // Arbitrary and not worth documenting, as Activity
260 // Manager will kill this process shortly anyway.
261 return null;
Jason Monkb9e06a82018-01-16 15:32:53 -0500262 }
263 }
264
265 /**
Jason Monk2d3932e2018-03-08 11:31:26 -0500266 * @deprecated TO BE REMOVED
Jeff Sharkey3990ee12018-04-11 10:19:55 -0600267 * @removed
Jason Monk2d3932e2018-03-08 11:31:26 -0500268 */
269 @Deprecated
270 public @Nullable Slice bindSlice(@NonNull Uri uri, @NonNull List<SliceSpec> supportedSpecs) {
271 return bindSlice(uri, new ArraySet<>(supportedSpecs));
272 }
273
274 /**
Jason Monkf2008872018-02-23 08:59:31 -0500275 * Turns a slice intent into a slice uri. Expects an explicit intent.
Jason Monk5e676a22018-03-08 14:18:55 -0500276 * <p>
277 * This goes through a several stage resolution process to determine if any slice
278 * can represent this intent.
Jason Monk39b9fb32018-03-27 10:45:23 -0400279 * <ol>
280 * <li> If the intent contains data that {@link ContentResolver#getType} is
281 * {@link SliceProvider#SLICE_TYPE} then the data will be returned.</li>
Jason Monk5ffacd02018-04-10 15:00:18 -0400282 * <li>If the intent explicitly points at an activity, and that activity has
Jason Monk5e676a22018-03-08 14:18:55 -0500283 * meta-data for key {@link #SLICE_METADATA_KEY}, then the Uri specified there will be
Jason Monk39b9fb32018-03-27 10:45:23 -0400284 * returned.</li>
Jason Monk5ffacd02018-04-10 15:00:18 -0400285 * <li>Lastly, if the intent with {@link #CATEGORY_SLICE} added resolves to a provider, then
286 * the provider will be asked to {@link SliceProvider#onMapIntentToUri} and that result
287 * will be returned.</li>
Jason Monk39b9fb32018-03-27 10:45:23 -0400288 * <li>If no slice is found, then {@code null} is returned.</li>
289 * </ol>
Jason Monk7b8fef22018-01-30 16:04:14 -0500290 * @param intent The intent associated with a slice.
Jason Monkf2008872018-02-23 08:59:31 -0500291 * @return The Slice Uri provided by the app or null if none exists.
Jason Monk7b8fef22018-01-30 16:04:14 -0500292 * @see Slice
293 * @see SliceProvider#onMapIntentToUri(Intent)
294 * @see Intent
295 */
296 public @Nullable Uri mapIntentToUri(@NonNull Intent intent) {
Jason Monk7b8fef22018-01-30 16:04:14 -0500297 ContentResolver resolver = mContext.getContentResolver();
Jason Monk5ffacd02018-04-10 15:00:18 -0400298 final Uri staticUri = resolveStatic(intent, resolver);
299 if (staticUri != null) return staticUri;
Jason Monk7b8fef22018-01-30 16:04:14 -0500300 // Otherwise ask the app
Jason Monk5ffacd02018-04-10 15:00:18 -0400301 String authority = getAuthority(intent);
302 if (authority == null) return null;
Jason Monk7b8fef22018-01-30 16:04:14 -0500303 Uri uri = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
304 .authority(authority).build();
Jason Monk632def12018-02-01 15:21:16 -0500305 try (ContentProviderClient provider = resolver.acquireContentProviderClient(uri)) {
306 if (provider == null) {
307 throw new IllegalArgumentException("Unknown URI " + uri);
308 }
Jason Monk7b8fef22018-01-30 16:04:14 -0500309 Bundle extras = new Bundle();
310 extras.putParcelable(SliceProvider.EXTRA_INTENT, intent);
Jason Monk632def12018-02-01 15:21:16 -0500311 final Bundle res = provider.call(SliceProvider.METHOD_MAP_ONLY_INTENT, null, extras);
Jason Monk7b8fef22018-01-30 16:04:14 -0500312 if (res == null) {
313 return null;
314 }
315 return res.getParcelable(SliceProvider.EXTRA_SLICE);
316 } catch (RemoteException e) {
317 // Arbitrary and not worth documenting, as Activity
318 // Manager will kill this process shortly anyway.
319 return null;
Jason Monk7b8fef22018-01-30 16:04:14 -0500320 }
321 }
322
Jason Monk5ffacd02018-04-10 15:00:18 -0400323 private String getAuthority(Intent intent) {
324 Intent queryIntent = new Intent(intent);
325 if (!queryIntent.hasCategory(CATEGORY_SLICE)) {
326 queryIntent.addCategory(CATEGORY_SLICE);
327 }
328 List<ResolveInfo> providers =
329 mContext.getPackageManager().queryIntentContentProviders(queryIntent, 0);
330 return providers != null && !providers.isEmpty() ? providers.get(0).providerInfo.authority
331 : null;
332 }
333
334 private Uri resolveStatic(@NonNull Intent intent, ContentResolver resolver) {
335 Preconditions.checkNotNull(intent, "intent");
336 Preconditions.checkArgument(intent.getComponent() != null || intent.getPackage() != null
337 || intent.getData() != null,
338 "Slice intent must be explicit %s", intent);
339
340 // Check if the intent has data for the slice uri on it and use that
341 final Uri intentData = intent.getData();
342 if (intentData != null && SliceProvider.SLICE_TYPE.equals(resolver.getType(intentData))) {
343 return intentData;
344 }
345 // There are no providers, see if this activity has a direct link.
346 ResolveInfo resolve = mContext.getPackageManager().resolveActivity(intent,
347 PackageManager.GET_META_DATA);
348 if (resolve != null && resolve.activityInfo != null
349 && resolve.activityInfo.metaData != null
350 && resolve.activityInfo.metaData.containsKey(SLICE_METADATA_KEY)) {
351 return Uri.parse(
352 resolve.activityInfo.metaData.getString(SLICE_METADATA_KEY));
353 }
354 return null;
355 }
356
Jason Monk7b8fef22018-01-30 16:04:14 -0500357 /**
Jason Monk5ffacd02018-04-10 15:00:18 -0400358 * Turns a slice intent into slice content. Is a shortcut to perform the action
Jeff Sharkey3990ee12018-04-11 10:19:55 -0600359 * of both {@link #mapIntentToUri(Intent)} and {@link #bindSlice(Uri, Set)} at once.
Jason Monkb9e06a82018-01-16 15:32:53 -0500360 *
361 * @param intent The intent associated with a slice.
362 * @param supportedSpecs List of supported specs.
363 * @return The Slice provided by the app or null if none is given.
364 * @see Slice
365 * @see SliceProvider#onMapIntentToUri(Intent)
366 * @see Intent
367 */
368 public @Nullable Slice bindSlice(@NonNull Intent intent,
Jason Monk2d3932e2018-03-08 11:31:26 -0500369 @NonNull Set<SliceSpec> supportedSpecs) {
Jason Monkb9e06a82018-01-16 15:32:53 -0500370 Preconditions.checkNotNull(intent, "intent");
Jason Monk135f4172018-03-15 17:48:47 -0400371 Preconditions.checkArgument(intent.getComponent() != null || intent.getPackage() != null
372 || intent.getData() != null,
Jason Monk7b8fef22018-01-30 16:04:14 -0500373 "Slice intent must be explicit %s", intent);
Jason Monkb9e06a82018-01-16 15:32:53 -0500374 ContentResolver resolver = mContext.getContentResolver();
Jason Monk5ffacd02018-04-10 15:00:18 -0400375 final Uri staticUri = resolveStatic(intent, resolver);
376 if (staticUri != null) return bindSlice(staticUri, supportedSpecs);
Jason Monkb9e06a82018-01-16 15:32:53 -0500377 // Otherwise ask the app
Jason Monk5ffacd02018-04-10 15:00:18 -0400378 String authority = getAuthority(intent);
379 if (authority == null) return null;
Jason Monkb9e06a82018-01-16 15:32:53 -0500380 Uri uri = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
381 .authority(authority).build();
Jason Monk632def12018-02-01 15:21:16 -0500382 try (ContentProviderClient provider = resolver.acquireContentProviderClient(uri)) {
383 if (provider == null) {
384 throw new IllegalArgumentException("Unknown URI " + uri);
385 }
Jason Monkb9e06a82018-01-16 15:32:53 -0500386 Bundle extras = new Bundle();
387 extras.putParcelable(SliceProvider.EXTRA_INTENT, intent);
Jason Monk632def12018-02-01 15:21:16 -0500388 final Bundle res = provider.call(SliceProvider.METHOD_MAP_INTENT, null, extras);
Jason Monkb9e06a82018-01-16 15:32:53 -0500389 if (res == null) {
390 return null;
391 }
392 return res.getParcelable(SliceProvider.EXTRA_SLICE);
393 } catch (RemoteException e) {
394 // Arbitrary and not worth documenting, as Activity
395 // Manager will kill this process shortly anyway.
396 return null;
Jason Monkb9e06a82018-01-16 15:32:53 -0500397 }
398 }
399
400 /**
Jason Monk2d3932e2018-03-08 11:31:26 -0500401 * @deprecated TO BE REMOVED.
Jeff Sharkey3990ee12018-04-11 10:19:55 -0600402 * @removed
Jason Monk2d3932e2018-03-08 11:31:26 -0500403 */
404 @Deprecated
405 @Nullable
406 public Slice bindSlice(@NonNull Intent intent,
407 @NonNull List<SliceSpec> supportedSpecs) {
408 return bindSlice(intent, new ArraySet<>(supportedSpecs));
409 }
410
411 /**
Jason Monk71888552018-03-30 14:14:51 -0400412 * Determine whether a particular process and user ID has been granted
413 * permission to access a specific slice URI.
414 *
415 * @param uri The uri that is being checked.
416 * @param pid The process ID being checked against. Must be &gt; 0.
417 * @param uid The user ID being checked against. A uid of 0 is the root
418 * user, which will pass every permission check.
419 *
420 * @return {@link PackageManager#PERMISSION_GRANTED} if the given
421 * pid/uid is allowed to access that uri, or
422 * {@link PackageManager#PERMISSION_DENIED} if it is not.
423 *
424 * @see #grantSlicePermission(String, Uri)
425 */
426 public @PermissionResult int checkSlicePermission(@NonNull Uri uri, int pid, int uid) {
Jason Monkbf3eedc2018-04-05 20:56:42 -0400427 try {
428 return mService.checkSlicePermission(uri, null, pid, uid, null);
429 } catch (RemoteException e) {
430 throw e.rethrowFromSystemServer();
431 }
Jason Monk71888552018-03-30 14:14:51 -0400432 }
433
434 /**
435 * Grant permission to access a specific slice Uri to another package.
436 *
437 * @param toPackage The package you would like to allow to access the Uri.
438 * @param uri The Uri you would like to grant access to.
439 *
440 * @see #revokeSlicePermission
441 */
442 public void grantSlicePermission(@NonNull String toPackage, @NonNull Uri uri) {
Jason Monkbf3eedc2018-04-05 20:56:42 -0400443 try {
444 mService.grantSlicePermission(mContext.getPackageName(), toPackage, uri);
445 } catch (RemoteException e) {
446 throw e.rethrowFromSystemServer();
447 }
Jason Monk71888552018-03-30 14:14:51 -0400448 }
449
450 /**
451 * Remove permissions to access a particular content provider Uri
452 * that were previously added with {@link #grantSlicePermission} for a specific target
453 * package. The given Uri will match all previously granted Uris that are the same or a
454 * sub-path of the given Uri. That is, revoking "content://foo/target" will
455 * revoke both "content://foo/target" and "content://foo/target/sub", but not
456 * "content://foo". It will not remove any prefix grants that exist at a
457 * higher level.
458 *
459 * @param toPackage The package you would like to allow to access the Uri.
460 * @param uri The Uri you would like to revoke access to.
461 *
462 * @see #grantSlicePermission
463 */
464 public void revokeSlicePermission(@NonNull String toPackage, @NonNull Uri uri) {
Jason Monkbf3eedc2018-04-05 20:56:42 -0400465 try {
466 mService.revokeSlicePermission(mContext.getPackageName(), toPackage, uri);
467 } catch (RemoteException e) {
468 throw e.rethrowFromSystemServer();
469 }
Jason Monk71888552018-03-30 14:14:51 -0400470 }
471
472 /**
Jason Monke8f8be72018-01-21 10:10:35 -0500473 * Does the permission check to see if a caller has access to a specific slice.
474 * @hide
475 */
Jason Monk42e03f82018-03-30 11:26:56 -0400476 public void enforceSlicePermission(Uri uri, String pkg, int pid, int uid,
477 String[] autoGrantPermissions) {
Jason Monke8f8be72018-01-21 10:10:35 -0500478 try {
Jason Monkac112382018-03-23 15:06:35 -0400479 if (UserHandle.isSameApp(uid, Process.myUid())) {
480 return;
481 }
Jason Monke8f8be72018-01-21 10:10:35 -0500482 if (pkg == null) {
483 throw new SecurityException("No pkg specified");
484 }
Jason Monk42e03f82018-03-30 11:26:56 -0400485 int result = mService.checkSlicePermission(uri, pkg, pid, uid, autoGrantPermissions);
Jason Monke8f8be72018-01-21 10:10:35 -0500486 if (result == PERMISSION_DENIED) {
487 throw new SecurityException("User " + uid + " does not have slice permission for "
488 + uri + ".");
489 }
Jason Monke8f8be72018-01-21 10:10:35 -0500490 } catch (RemoteException e) {
491 throw e.rethrowFromSystemServer();
492 }
493 }
494
495 /**
496 * Called by SystemUI to grant a slice permission after a dialog is shown.
497 * @hide
498 */
499 public void grantPermissionFromUser(Uri uri, String pkg, boolean allSlices) {
500 try {
501 mService.grantPermissionFromUser(uri, pkg, mContext.getPackageName(), allSlices);
502 } catch (RemoteException e) {
503 throw e.rethrowFromSystemServer();
504 }
505 }
Jason Monk8f5f7ff2017-10-17 14:12:42 -0400506}