blob: dc8a3b92eaa919148d2f201eda3f85ed4ad8f576 [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 =
69 "android.intent.action.REQUEST_SLICE_PERMISSION";
70
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
142 */
143 @Deprecated
144 public void pinSlice(@NonNull Uri uri, @NonNull List<SliceSpec> specs) {
145 pinSlice(uri, new ArraySet<>(specs));
146 }
147
148 /**
Jason Monke2c64512017-12-11 15:14:54 -0500149 * Remove a pin for a slice.
150 * <p>
151 * If the slice has no other pins/callbacks then the slice will be unpinned.
Jason Monk632def12018-02-01 15:21:16 -0500152 * <p>
153 * This may only be called by apps that are the default launcher for the device
154 * or the default voice interaction service. Otherwise will throw {@link SecurityException}.
Jason Monke2c64512017-12-11 15:14:54 -0500155 *
156 * @param uri The uri of the slice being unpinned.
157 * @see #pinSlice
158 * @see SliceProvider#onSliceUnpinned(Uri)
Jason Monk632def12018-02-01 15:21:16 -0500159 * @see Intent#ACTION_ASSIST
160 * @see Intent#CATEGORY_HOME
Jason Monk74f5e362017-12-06 08:56:33 -0500161 */
Jason Monke2c64512017-12-11 15:14:54 -0500162 public void unpinSlice(@NonNull Uri uri) {
Jason Monk74f5e362017-12-06 08:56:33 -0500163 try {
Jason Monk38df2802018-02-22 19:28:12 -0500164 mService.unpinSlice(mContext.getPackageName(), uri, mToken);
Jason Monk74f5e362017-12-06 08:56:33 -0500165 } catch (RemoteException e) {
166 throw e.rethrowFromSystemServer();
167 }
168 }
169
170 /**
Jason Monke2c64512017-12-11 15:14:54 -0500171 * @hide
Jason Monk74f5e362017-12-06 08:56:33 -0500172 */
173 public boolean hasSliceAccess() {
174 try {
175 return mService.hasSliceAccess(mContext.getPackageName());
176 } catch (RemoteException e) {
177 throw e.rethrowFromSystemServer();
178 }
179 }
180
181 /**
Jason Monke2c64512017-12-11 15:14:54 -0500182 * Get the current set of specs for a pinned slice.
183 * <p>
184 * This is the set of specs supported for a specific pinned slice. It will take
185 * into account all clients and returns only specs supported by all.
186 * @see SliceSpec
Jason Monk74f5e362017-12-06 08:56:33 -0500187 */
Jason Monk2d3932e2018-03-08 11:31:26 -0500188 public @NonNull Set<SliceSpec> getPinnedSpecs(Uri uri) {
Jason Monk74f5e362017-12-06 08:56:33 -0500189 try {
Jason Monk2d3932e2018-03-08 11:31:26 -0500190 return new ArraySet<>(Arrays.asList(mService.getPinnedSpecs(uri,
191 mContext.getPackageName())));
Jason Monk74f5e362017-12-06 08:56:33 -0500192 } catch (RemoteException e) {
193 throw e.rethrowFromSystemServer();
194 }
195 }
196
197 /**
Jason Monkf88d25e2018-03-06 20:13:24 -0500198 * Get the list of currently pinned slices for this app.
199 * @see SliceProvider#onSlicePinned
200 */
201 public @NonNull List<Uri> getPinnedSlices() {
202 try {
203 return Arrays.asList(mService.getPinnedSlices(mContext.getPackageName()));
204 } catch (RemoteException e) {
205 throw e.rethrowFromSystemServer();
206 }
207 }
208
209 /**
Jason Monk5f8cc272018-01-16 17:57:20 -0500210 * Obtains a list of slices that are descendants of the specified Uri.
211 * <p>
212 * Not all slice providers will implement this functionality, in which case,
213 * an empty collection will be returned.
214 *
215 * @param uri The uri to look for descendants under.
216 * @return All slices within the space.
217 * @see SliceProvider#onGetSliceDescendants(Uri)
218 */
219 public @NonNull Collection<Uri> getSliceDescendants(@NonNull Uri uri) {
220 ContentResolver resolver = mContext.getContentResolver();
Jason Monk632def12018-02-01 15:21:16 -0500221 try (ContentProviderClient provider = resolver.acquireContentProviderClient(uri)) {
Jason Monk5f8cc272018-01-16 17:57:20 -0500222 Bundle extras = new Bundle();
223 extras.putParcelable(SliceProvider.EXTRA_BIND_URI, uri);
Jason Monk632def12018-02-01 15:21:16 -0500224 final Bundle res = provider.call(SliceProvider.METHOD_GET_DESCENDANTS, null, extras);
Jason Monk5f8cc272018-01-16 17:57:20 -0500225 return res.getParcelableArrayList(SliceProvider.EXTRA_SLICE_DESCENDANTS);
226 } catch (RemoteException e) {
227 Log.e(TAG, "Unable to get slice descendants", e);
Jason Monk5f8cc272018-01-16 17:57:20 -0500228 }
229 return Collections.emptyList();
230 }
231
232 /**
Jason Monkb9e06a82018-01-16 15:32:53 -0500233 * Turns a slice Uri into slice content.
234 *
235 * @param uri The URI to a slice provider
236 * @param supportedSpecs List of supported specs.
237 * @return The Slice provided by the app or null if none is given.
238 * @see Slice
239 */
Jason Monk2d3932e2018-03-08 11:31:26 -0500240 public @Nullable Slice bindSlice(@NonNull Uri uri, @NonNull Set<SliceSpec> supportedSpecs) {
Jason Monkb9e06a82018-01-16 15:32:53 -0500241 Preconditions.checkNotNull(uri, "uri");
242 ContentResolver resolver = mContext.getContentResolver();
Jason Monk632def12018-02-01 15:21:16 -0500243 try (ContentProviderClient provider = resolver.acquireContentProviderClient(uri)) {
244 if (provider == null) {
245 throw new IllegalArgumentException("Unknown URI " + uri);
246 }
Jason Monkb9e06a82018-01-16 15:32:53 -0500247 Bundle extras = new Bundle();
248 extras.putParcelable(SliceProvider.EXTRA_BIND_URI, uri);
249 extras.putParcelableArrayList(SliceProvider.EXTRA_SUPPORTED_SPECS,
250 new ArrayList<>(supportedSpecs));
Jason Monk632def12018-02-01 15:21:16 -0500251 final Bundle res = provider.call(SliceProvider.METHOD_SLICE, null, extras);
Jason Monkb9e06a82018-01-16 15:32:53 -0500252 Bundle.setDefusable(res, true);
253 if (res == null) {
254 return null;
255 }
256 return res.getParcelable(SliceProvider.EXTRA_SLICE);
257 } catch (RemoteException e) {
258 // Arbitrary and not worth documenting, as Activity
259 // Manager will kill this process shortly anyway.
260 return null;
Jason Monkb9e06a82018-01-16 15:32:53 -0500261 }
262 }
263
264 /**
Jason Monk2d3932e2018-03-08 11:31:26 -0500265 * @deprecated TO BE REMOVED
266 */
267 @Deprecated
268 public @Nullable Slice bindSlice(@NonNull Uri uri, @NonNull List<SliceSpec> supportedSpecs) {
269 return bindSlice(uri, new ArraySet<>(supportedSpecs));
270 }
271
272 /**
Jason Monkf2008872018-02-23 08:59:31 -0500273 * Turns a slice intent into a slice uri. Expects an explicit intent.
Jason Monk5e676a22018-03-08 14:18:55 -0500274 * <p>
275 * This goes through a several stage resolution process to determine if any slice
276 * can represent this intent.
Jason Monk39b9fb32018-03-27 10:45:23 -0400277 * <ol>
278 * <li> If the intent contains data that {@link ContentResolver#getType} is
279 * {@link SliceProvider#SLICE_TYPE} then the data will be returned.</li>
280 * <li>If the intent with {@link #CATEGORY_SLICE} added resolves to a provider, then
Jason Monk5e676a22018-03-08 14:18:55 -0500281 * the provider will be asked to {@link SliceProvider#onMapIntentToUri} and that result
Jason Monk39b9fb32018-03-27 10:45:23 -0400282 * will be returned.</li>
283 * <li>Lastly, if the intent explicitly points at an activity, and that activity has
Jason Monk5e676a22018-03-08 14:18:55 -0500284 * meta-data for key {@link #SLICE_METADATA_KEY}, then the Uri specified there will be
Jason Monk39b9fb32018-03-27 10:45:23 -0400285 * returned.</li>
286 * <li>If no slice is found, then {@code null} is returned.</li>
287 * </ol>
Jason Monk7b8fef22018-01-30 16:04:14 -0500288 * @param intent The intent associated with a slice.
Jason Monkf2008872018-02-23 08:59:31 -0500289 * @return The Slice Uri provided by the app or null if none exists.
Jason Monk7b8fef22018-01-30 16:04:14 -0500290 * @see Slice
291 * @see SliceProvider#onMapIntentToUri(Intent)
292 * @see Intent
293 */
294 public @Nullable Uri mapIntentToUri(@NonNull Intent intent) {
295 Preconditions.checkNotNull(intent, "intent");
Jason Monk135f4172018-03-15 17:48:47 -0400296 Preconditions.checkArgument(intent.getComponent() != null || intent.getPackage() != null
297 || intent.getData() != null,
Jason Monk7b8fef22018-01-30 16:04:14 -0500298 "Slice intent must be explicit %s", intent);
299 ContentResolver resolver = mContext.getContentResolver();
300
301 // Check if the intent has data for the slice uri on it and use that
302 final Uri intentData = intent.getData();
303 if (intentData != null && SliceProvider.SLICE_TYPE.equals(resolver.getType(intentData))) {
304 return intentData;
305 }
306 // Otherwise ask the app
Jason Monk5e676a22018-03-08 14:18:55 -0500307 Intent queryIntent = new Intent(intent);
308 if (!queryIntent.hasCategory(CATEGORY_SLICE)) {
309 queryIntent.addCategory(CATEGORY_SLICE);
310 }
Jason Monk7b8fef22018-01-30 16:04:14 -0500311 List<ResolveInfo> providers =
Jason Monk5e676a22018-03-08 14:18:55 -0500312 mContext.getPackageManager().queryIntentContentProviders(queryIntent, 0);
Jason Monk7b8fef22018-01-30 16:04:14 -0500313 if (providers == null || providers.isEmpty()) {
Jason Monkf2008872018-02-23 08:59:31 -0500314 // There are no providers, see if this activity has a direct link.
315 ResolveInfo resolve = mContext.getPackageManager().resolveActivity(intent,
316 PackageManager.GET_META_DATA);
317 if (resolve != null && resolve.activityInfo != null
318 && resolve.activityInfo.metaData != null
319 && resolve.activityInfo.metaData.containsKey(SLICE_METADATA_KEY)) {
320 return Uri.parse(
321 resolve.activityInfo.metaData.getString(SLICE_METADATA_KEY));
322 }
323 return null;
Jason Monk7b8fef22018-01-30 16:04:14 -0500324 }
325 String authority = providers.get(0).providerInfo.authority;
326 Uri uri = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
327 .authority(authority).build();
Jason Monk632def12018-02-01 15:21:16 -0500328 try (ContentProviderClient provider = resolver.acquireContentProviderClient(uri)) {
329 if (provider == null) {
330 throw new IllegalArgumentException("Unknown URI " + uri);
331 }
Jason Monk7b8fef22018-01-30 16:04:14 -0500332 Bundle extras = new Bundle();
333 extras.putParcelable(SliceProvider.EXTRA_INTENT, intent);
Jason Monk632def12018-02-01 15:21:16 -0500334 final Bundle res = provider.call(SliceProvider.METHOD_MAP_ONLY_INTENT, null, extras);
Jason Monk7b8fef22018-01-30 16:04:14 -0500335 if (res == null) {
336 return null;
337 }
338 return res.getParcelable(SliceProvider.EXTRA_SLICE);
339 } catch (RemoteException e) {
340 // Arbitrary and not worth documenting, as Activity
341 // Manager will kill this process shortly anyway.
342 return null;
Jason Monk7b8fef22018-01-30 16:04:14 -0500343 }
344 }
345
346 /**
Jason Monkb9e06a82018-01-16 15:32:53 -0500347 * Turns a slice intent into slice content. Expects an explicit intent. If there is no
348 * {@link android.content.ContentProvider} associated with the given intent this will throw
349 * {@link IllegalArgumentException}.
350 *
351 * @param intent The intent associated with a slice.
352 * @param supportedSpecs List of supported specs.
353 * @return The Slice provided by the app or null if none is given.
354 * @see Slice
355 * @see SliceProvider#onMapIntentToUri(Intent)
356 * @see Intent
357 */
358 public @Nullable Slice bindSlice(@NonNull Intent intent,
Jason Monk2d3932e2018-03-08 11:31:26 -0500359 @NonNull Set<SliceSpec> supportedSpecs) {
Jason Monkb9e06a82018-01-16 15:32:53 -0500360 Preconditions.checkNotNull(intent, "intent");
Jason Monk135f4172018-03-15 17:48:47 -0400361 Preconditions.checkArgument(intent.getComponent() != null || intent.getPackage() != null
362 || intent.getData() != null,
Jason Monk7b8fef22018-01-30 16:04:14 -0500363 "Slice intent must be explicit %s", intent);
Jason Monkb9e06a82018-01-16 15:32:53 -0500364 ContentResolver resolver = mContext.getContentResolver();
365
366 // Check if the intent has data for the slice uri on it and use that
367 final Uri intentData = intent.getData();
368 if (intentData != null && SliceProvider.SLICE_TYPE.equals(resolver.getType(intentData))) {
369 return bindSlice(intentData, supportedSpecs);
370 }
371 // Otherwise ask the app
372 List<ResolveInfo> providers =
373 mContext.getPackageManager().queryIntentContentProviders(intent, 0);
Jason Monk7b8fef22018-01-30 16:04:14 -0500374 if (providers == null || providers.isEmpty()) {
Jason Monkf2008872018-02-23 08:59:31 -0500375 // There are no providers, see if this activity has a direct link.
376 ResolveInfo resolve = mContext.getPackageManager().resolveActivity(intent,
377 PackageManager.GET_META_DATA);
378 if (resolve != null && resolve.activityInfo != null
379 && resolve.activityInfo.metaData != null
380 && resolve.activityInfo.metaData.containsKey(SLICE_METADATA_KEY)) {
381 return bindSlice(Uri.parse(resolve.activityInfo.metaData
382 .getString(SLICE_METADATA_KEY)), supportedSpecs);
383 }
384 return null;
Jason Monkb9e06a82018-01-16 15:32:53 -0500385 }
386 String authority = providers.get(0).providerInfo.authority;
387 Uri uri = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
388 .authority(authority).build();
Jason Monk632def12018-02-01 15:21:16 -0500389 try (ContentProviderClient provider = resolver.acquireContentProviderClient(uri)) {
390 if (provider == null) {
391 throw new IllegalArgumentException("Unknown URI " + uri);
392 }
Jason Monkb9e06a82018-01-16 15:32:53 -0500393 Bundle extras = new Bundle();
394 extras.putParcelable(SliceProvider.EXTRA_INTENT, intent);
395 extras.putParcelableArrayList(SliceProvider.EXTRA_SUPPORTED_SPECS,
396 new ArrayList<>(supportedSpecs));
Jason Monk632def12018-02-01 15:21:16 -0500397 final Bundle res = provider.call(SliceProvider.METHOD_MAP_INTENT, null, extras);
Jason Monkb9e06a82018-01-16 15:32:53 -0500398 if (res == null) {
399 return null;
400 }
401 return res.getParcelable(SliceProvider.EXTRA_SLICE);
402 } catch (RemoteException e) {
403 // Arbitrary and not worth documenting, as Activity
404 // Manager will kill this process shortly anyway.
405 return null;
Jason Monkb9e06a82018-01-16 15:32:53 -0500406 }
407 }
408
409 /**
Jason Monk2d3932e2018-03-08 11:31:26 -0500410 * @deprecated TO BE REMOVED.
411 */
412 @Deprecated
413 @Nullable
414 public Slice bindSlice(@NonNull Intent intent,
415 @NonNull List<SliceSpec> supportedSpecs) {
416 return bindSlice(intent, new ArraySet<>(supportedSpecs));
417 }
418
419 /**
Jason Monk71888552018-03-30 14:14:51 -0400420 * Determine whether a particular process and user ID has been granted
421 * permission to access a specific slice URI.
422 *
423 * @param uri The uri that is being checked.
424 * @param pid The process ID being checked against. Must be &gt; 0.
425 * @param uid The user ID being checked against. A uid of 0 is the root
426 * user, which will pass every permission check.
427 *
428 * @return {@link PackageManager#PERMISSION_GRANTED} if the given
429 * pid/uid is allowed to access that uri, or
430 * {@link PackageManager#PERMISSION_DENIED} if it is not.
431 *
432 * @see #grantSlicePermission(String, Uri)
433 */
434 public @PermissionResult int checkSlicePermission(@NonNull Uri uri, int pid, int uid) {
Jason Monkbf3eedc2018-04-05 20:56:42 -0400435 try {
436 return mService.checkSlicePermission(uri, null, pid, uid, null);
437 } catch (RemoteException e) {
438 throw e.rethrowFromSystemServer();
439 }
Jason Monk71888552018-03-30 14:14:51 -0400440 }
441
442 /**
443 * Grant permission to access a specific slice Uri to another package.
444 *
445 * @param toPackage The package you would like to allow to access the Uri.
446 * @param uri The Uri you would like to grant access to.
447 *
448 * @see #revokeSlicePermission
449 */
450 public void grantSlicePermission(@NonNull String toPackage, @NonNull Uri uri) {
Jason Monkbf3eedc2018-04-05 20:56:42 -0400451 try {
452 mService.grantSlicePermission(mContext.getPackageName(), toPackage, uri);
453 } catch (RemoteException e) {
454 throw e.rethrowFromSystemServer();
455 }
Jason Monk71888552018-03-30 14:14:51 -0400456 }
457
458 /**
459 * Remove permissions to access a particular content provider Uri
460 * that were previously added with {@link #grantSlicePermission} for a specific target
461 * package. The given Uri will match all previously granted Uris that are the same or a
462 * sub-path of the given Uri. That is, revoking "content://foo/target" will
463 * revoke both "content://foo/target" and "content://foo/target/sub", but not
464 * "content://foo". It will not remove any prefix grants that exist at a
465 * higher level.
466 *
467 * @param toPackage The package you would like to allow to access the Uri.
468 * @param uri The Uri you would like to revoke access to.
469 *
470 * @see #grantSlicePermission
471 */
472 public void revokeSlicePermission(@NonNull String toPackage, @NonNull Uri uri) {
Jason Monkbf3eedc2018-04-05 20:56:42 -0400473 try {
474 mService.revokeSlicePermission(mContext.getPackageName(), toPackage, uri);
475 } catch (RemoteException e) {
476 throw e.rethrowFromSystemServer();
477 }
Jason Monk71888552018-03-30 14:14:51 -0400478 }
479
480 /**
Jason Monke8f8be72018-01-21 10:10:35 -0500481 * Does the permission check to see if a caller has access to a specific slice.
482 * @hide
483 */
Jason Monk42e03f82018-03-30 11:26:56 -0400484 public void enforceSlicePermission(Uri uri, String pkg, int pid, int uid,
485 String[] autoGrantPermissions) {
Jason Monke8f8be72018-01-21 10:10:35 -0500486 try {
Jason Monkac112382018-03-23 15:06:35 -0400487 if (UserHandle.isSameApp(uid, Process.myUid())) {
488 return;
489 }
Jason Monke8f8be72018-01-21 10:10:35 -0500490 if (pkg == null) {
491 throw new SecurityException("No pkg specified");
492 }
Jason Monk42e03f82018-03-30 11:26:56 -0400493 int result = mService.checkSlicePermission(uri, pkg, pid, uid, autoGrantPermissions);
Jason Monke8f8be72018-01-21 10:10:35 -0500494 if (result == PERMISSION_DENIED) {
495 throw new SecurityException("User " + uid + " does not have slice permission for "
496 + uri + ".");
497 }
Jason Monke8f8be72018-01-21 10:10:35 -0500498 } catch (RemoteException e) {
499 throw e.rethrowFromSystemServer();
500 }
501 }
502
503 /**
504 * Called by SystemUI to grant a slice permission after a dialog is shown.
505 * @hide
506 */
507 public void grantPermissionFromUser(Uri uri, String pkg, boolean allSlices) {
508 try {
509 mService.grantPermissionFromUser(uri, pkg, mContext.getPackageName(), allSlices);
510 } catch (RemoteException e) {
511 throw e.rethrowFromSystemServer();
512 }
513 }
Jason Monk8f5f7ff2017-10-17 14:12:42 -0400514}