blob: f682ec1c31d40b7c4584e6686e998039aa6e61c8 [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 Monka66dfee2018-05-11 08:23:59 -070026import android.annotation.WorkerThread;
Jason Monk632def12018-02-01 15:21:16 -050027import android.content.ContentProviderClient;
Jason Monkb9e06a82018-01-16 15:32:53 -050028import android.content.ContentResolver;
Jason Monk8f5f7ff2017-10-17 14:12:42 -040029import android.content.Context;
Jason Monkb9e06a82018-01-16 15:32:53 -050030import android.content.Intent;
Jason Monkf2008872018-02-23 08:59:31 -050031import android.content.pm.PackageManager;
Jason Monk71888552018-03-30 14:14:51 -040032import android.content.pm.PackageManager.PermissionResult;
Jason Monkb9e06a82018-01-16 15:32:53 -050033import android.content.pm.ResolveInfo;
Jason Monk74f5e362017-12-06 08:56:33 -050034import android.net.Uri;
Jason Monk38df2802018-02-22 19:28:12 -050035import android.os.Binder;
Jason Monkb9e06a82018-01-16 15:32:53 -050036import android.os.Bundle;
Jason Monk8f5f7ff2017-10-17 14:12:42 -040037import android.os.Handler;
Jason Monk38df2802018-02-22 19:28:12 -050038import android.os.IBinder;
Jason Monkac112382018-03-23 15:06:35 -040039import android.os.Process;
Jason Monk74f5e362017-12-06 08:56:33 -050040import android.os.RemoteException;
Jason Monk8f5f7ff2017-10-17 14:12:42 -040041import android.os.ServiceManager;
42import android.os.ServiceManager.ServiceNotFoundException;
Jason Monkac112382018-03-23 15:06:35 -040043import android.os.UserHandle;
Jason Monk2d3932e2018-03-08 11:31:26 -050044import android.util.ArraySet;
Jason Monk5f8cc272018-01-16 17:57:20 -050045import android.util.Log;
Jason Monke2c64512017-12-11 15:14:54 -050046
Jason Monkb9e06a82018-01-16 15:32:53 -050047import com.android.internal.util.Preconditions;
48
49import java.util.ArrayList;
Jason Monke2c64512017-12-11 15:14:54 -050050import java.util.Arrays;
Jason Monk5f8cc272018-01-16 17:57:20 -050051import java.util.Collection;
52import java.util.Collections;
Jason Monke2c64512017-12-11 15:14:54 -050053import java.util.List;
Jason Monk2d3932e2018-03-08 11:31:26 -050054import java.util.Set;
Jason Monk8f5f7ff2017-10-17 14:12:42 -040055
56/**
Jason Monke2c64512017-12-11 15:14:54 -050057 * Class to handle interactions with {@link Slice}s.
58 * <p>
59 * The SliceManager manages permissions and pinned state for slices.
Jason Monk8f5f7ff2017-10-17 14:12:42 -040060 */
61@SystemService(Context.SLICE_SERVICE)
62public class SliceManager {
63
Jason Monk5f8cc272018-01-16 17:57:20 -050064 private static final String TAG = "SliceManager";
65
Jason Monke8f8be72018-01-21 10:10:35 -050066 /**
67 * @hide
68 */
69 public static final String ACTION_REQUEST_SLICE_PERMISSION =
Jason Monk0c179a92018-04-18 10:37:19 -040070 "com.android.intent.action.REQUEST_SLICE_PERMISSION";
Jason Monke8f8be72018-01-21 10:10:35 -050071
Mady Mellor3267ed82018-02-21 11:42:31 -080072 /**
Jason Monk5e676a22018-03-08 14:18:55 -050073 * Category used to resolve intents that can be rendered as slices.
74 * <p>
75 * This category should be included on intent filters on providers that extend
76 * {@link SliceProvider}.
77 * @see SliceProvider
78 * @see SliceProvider#onMapIntentToUri(Intent)
79 * @see #mapIntentToUri(Intent)
80 */
81 @SdkConstant(SdkConstantType.INTENT_CATEGORY)
82 public static final String CATEGORY_SLICE = "android.app.slice.category.SLICE";
83
84 /**
Mady Mellor3267ed82018-02-21 11:42:31 -080085 * The meta-data key that allows an activity to easily be linked directly to a slice.
86 * <p>
87 * An activity can be statically linked to a slice uri by including a meta-data item
88 * for this key that contains a valid slice uri for the same application declaring
89 * the activity.
Jason Monk39b9fb32018-03-27 10:45:23 -040090 *
91 * <pre class="prettyprint">
92 * {@literal
93 * <activity android:name="com.example.mypkg.MyActivity">
94 * <meta-data android:name="android.metadata.SLICE_URI"
95 * android:value="content://com.example.mypkg/main_slice" />
96 * </activity>}
97 * </pre>
98 *
99 * @see #mapIntentToUri(Intent)
100 * @see SliceProvider#onMapIntentToUri(Intent)
Mady Mellor3267ed82018-02-21 11:42:31 -0800101 */
102 public static final String SLICE_METADATA_KEY = "android.metadata.SLICE_URI";
103
Jason Monk8f5f7ff2017-10-17 14:12:42 -0400104 private final ISliceManager mService;
105 private final Context mContext;
Jason Monk38df2802018-02-22 19:28:12 -0500106 private final IBinder mToken = new Binder();
Jason Monk8f5f7ff2017-10-17 14:12:42 -0400107
Jason Monke2c64512017-12-11 15:14:54 -0500108 /**
109 * @hide
110 */
Jason Monk8f5f7ff2017-10-17 14:12:42 -0400111 public SliceManager(Context context, Handler handler) throws ServiceNotFoundException {
112 mContext = context;
113 mService = ISliceManager.Stub.asInterface(
114 ServiceManager.getServiceOrThrow(Context.SLICE_SERVICE));
115 }
Jason Monk74f5e362017-12-06 08:56:33 -0500116
117 /**
Jason Monke2c64512017-12-11 15:14:54 -0500118 * Ensures that a slice is in a pinned state.
119 * <p>
120 * Pinned state is not persisted across reboots, so apps are expected to re-pin any slices
121 * they still care about after a reboot.
Jason Monk632def12018-02-01 15:21:16 -0500122 * <p>
123 * This may only be called by apps that are the default launcher for the device
124 * or the default voice interaction service. Otherwise will throw {@link SecurityException}.
Jason Monke2c64512017-12-11 15:14:54 -0500125 *
126 * @param uri The uri of the slice being pinned.
127 * @param specs The list of supported {@link SliceSpec}s of the callback.
128 * @see SliceProvider#onSlicePinned(Uri)
Jason Monk632def12018-02-01 15:21:16 -0500129 * @see Intent#ACTION_ASSIST
130 * @see Intent#CATEGORY_HOME
Jason Monk74f5e362017-12-06 08:56:33 -0500131 */
Jason Monk2d3932e2018-03-08 11:31:26 -0500132 public void pinSlice(@NonNull Uri uri, @NonNull Set<SliceSpec> specs) {
Jason Monk74f5e362017-12-06 08:56:33 -0500133 try {
Jason Monke2c64512017-12-11 15:14:54 -0500134 mService.pinSlice(mContext.getPackageName(), uri,
Jason Monk38df2802018-02-22 19:28:12 -0500135 specs.toArray(new SliceSpec[specs.size()]), mToken);
Jason Monk74f5e362017-12-06 08:56:33 -0500136 } catch (RemoteException e) {
137 throw e.rethrowFromSystemServer();
138 }
139 }
140
141 /**
Jason Monk2d3932e2018-03-08 11:31:26 -0500142 * @deprecated TO BE REMOVED
Jeff Sharkey3990ee12018-04-11 10:19:55 -0600143 * @removed
Jason Monk2d3932e2018-03-08 11:31:26 -0500144 */
145 @Deprecated
146 public void pinSlice(@NonNull Uri uri, @NonNull List<SliceSpec> specs) {
147 pinSlice(uri, new ArraySet<>(specs));
148 }
149
150 /**
Jason Monke2c64512017-12-11 15:14:54 -0500151 * Remove a pin for a slice.
152 * <p>
153 * If the slice has no other pins/callbacks then the slice will be unpinned.
Jason Monk632def12018-02-01 15:21:16 -0500154 * <p>
155 * This may only be called by apps that are the default launcher for the device
156 * or the default voice interaction service. Otherwise will throw {@link SecurityException}.
Jason Monke2c64512017-12-11 15:14:54 -0500157 *
158 * @param uri The uri of the slice being unpinned.
159 * @see #pinSlice
160 * @see SliceProvider#onSliceUnpinned(Uri)
Jason Monk632def12018-02-01 15:21:16 -0500161 * @see Intent#ACTION_ASSIST
162 * @see Intent#CATEGORY_HOME
Jason Monk74f5e362017-12-06 08:56:33 -0500163 */
Jason Monke2c64512017-12-11 15:14:54 -0500164 public void unpinSlice(@NonNull Uri uri) {
Jason Monk74f5e362017-12-06 08:56:33 -0500165 try {
Jason Monk38df2802018-02-22 19:28:12 -0500166 mService.unpinSlice(mContext.getPackageName(), uri, mToken);
Jason Monk74f5e362017-12-06 08:56:33 -0500167 } catch (RemoteException e) {
168 throw e.rethrowFromSystemServer();
169 }
170 }
171
172 /**
Jason Monke2c64512017-12-11 15:14:54 -0500173 * @hide
Jason Monk74f5e362017-12-06 08:56:33 -0500174 */
175 public boolean hasSliceAccess() {
176 try {
177 return mService.hasSliceAccess(mContext.getPackageName());
178 } catch (RemoteException e) {
179 throw e.rethrowFromSystemServer();
180 }
181 }
182
183 /**
Jason Monke2c64512017-12-11 15:14:54 -0500184 * Get the current set of specs for a pinned slice.
185 * <p>
186 * This is the set of specs supported for a specific pinned slice. It will take
187 * into account all clients and returns only specs supported by all.
188 * @see SliceSpec
Jason Monk74f5e362017-12-06 08:56:33 -0500189 */
Jason Monk2d3932e2018-03-08 11:31:26 -0500190 public @NonNull Set<SliceSpec> getPinnedSpecs(Uri uri) {
Jason Monk74f5e362017-12-06 08:56:33 -0500191 try {
Jason Monk2d3932e2018-03-08 11:31:26 -0500192 return new ArraySet<>(Arrays.asList(mService.getPinnedSpecs(uri,
193 mContext.getPackageName())));
Jason Monk74f5e362017-12-06 08:56:33 -0500194 } catch (RemoteException e) {
195 throw e.rethrowFromSystemServer();
196 }
197 }
198
199 /**
Jason Monkf88d25e2018-03-06 20:13:24 -0500200 * Get the list of currently pinned slices for this app.
201 * @see SliceProvider#onSlicePinned
202 */
203 public @NonNull List<Uri> getPinnedSlices() {
204 try {
205 return Arrays.asList(mService.getPinnedSlices(mContext.getPackageName()));
206 } catch (RemoteException e) {
207 throw e.rethrowFromSystemServer();
208 }
209 }
210
211 /**
Jason Monk5f8cc272018-01-16 17:57:20 -0500212 * Obtains a list of slices that are descendants of the specified Uri.
213 * <p>
214 * Not all slice providers will implement this functionality, in which case,
215 * an empty collection will be returned.
216 *
217 * @param uri The uri to look for descendants under.
218 * @return All slices within the space.
219 * @see SliceProvider#onGetSliceDescendants(Uri)
220 */
Jason Monka66dfee2018-05-11 08:23:59 -0700221 @WorkerThread
Jason Monk5f8cc272018-01-16 17:57:20 -0500222 public @NonNull Collection<Uri> getSliceDescendants(@NonNull Uri uri) {
223 ContentResolver resolver = mContext.getContentResolver();
Jason Monk632def12018-02-01 15:21:16 -0500224 try (ContentProviderClient provider = resolver.acquireContentProviderClient(uri)) {
Jason Monk5f8cc272018-01-16 17:57:20 -0500225 Bundle extras = new Bundle();
226 extras.putParcelable(SliceProvider.EXTRA_BIND_URI, uri);
Jason Monk632def12018-02-01 15:21:16 -0500227 final Bundle res = provider.call(SliceProvider.METHOD_GET_DESCENDANTS, null, extras);
Jason Monk5f8cc272018-01-16 17:57:20 -0500228 return res.getParcelableArrayList(SliceProvider.EXTRA_SLICE_DESCENDANTS);
229 } catch (RemoteException e) {
230 Log.e(TAG, "Unable to get slice descendants", e);
Jason Monk5f8cc272018-01-16 17:57:20 -0500231 }
232 return Collections.emptyList();
233 }
234
235 /**
Jason Monkb9e06a82018-01-16 15:32:53 -0500236 * Turns a slice Uri into slice content.
237 *
238 * @param uri The URI to a slice provider
239 * @param supportedSpecs List of supported specs.
240 * @return The Slice provided by the app or null if none is given.
241 * @see Slice
242 */
Jason Monk2d3932e2018-03-08 11:31:26 -0500243 public @Nullable Slice bindSlice(@NonNull Uri uri, @NonNull Set<SliceSpec> supportedSpecs) {
Jason Monkb9e06a82018-01-16 15:32:53 -0500244 Preconditions.checkNotNull(uri, "uri");
245 ContentResolver resolver = mContext.getContentResolver();
Jason Monk632def12018-02-01 15:21:16 -0500246 try (ContentProviderClient provider = resolver.acquireContentProviderClient(uri)) {
247 if (provider == null) {
248 throw new IllegalArgumentException("Unknown URI " + uri);
249 }
Jason Monkb9e06a82018-01-16 15:32:53 -0500250 Bundle extras = new Bundle();
251 extras.putParcelable(SliceProvider.EXTRA_BIND_URI, uri);
252 extras.putParcelableArrayList(SliceProvider.EXTRA_SUPPORTED_SPECS,
253 new ArrayList<>(supportedSpecs));
Jason Monk632def12018-02-01 15:21:16 -0500254 final Bundle res = provider.call(SliceProvider.METHOD_SLICE, null, extras);
Jason Monkb9e06a82018-01-16 15:32:53 -0500255 Bundle.setDefusable(res, true);
256 if (res == null) {
257 return null;
258 }
259 return res.getParcelable(SliceProvider.EXTRA_SLICE);
260 } catch (RemoteException e) {
261 // Arbitrary and not worth documenting, as Activity
262 // Manager will kill this process shortly anyway.
263 return null;
Jason Monkb9e06a82018-01-16 15:32:53 -0500264 }
265 }
266
267 /**
Jason Monk2d3932e2018-03-08 11:31:26 -0500268 * @deprecated TO BE REMOVED
Jeff Sharkey3990ee12018-04-11 10:19:55 -0600269 * @removed
Jason Monk2d3932e2018-03-08 11:31:26 -0500270 */
271 @Deprecated
272 public @Nullable Slice bindSlice(@NonNull Uri uri, @NonNull List<SliceSpec> supportedSpecs) {
273 return bindSlice(uri, new ArraySet<>(supportedSpecs));
274 }
275
276 /**
Jason Monkf2008872018-02-23 08:59:31 -0500277 * Turns a slice intent into a slice uri. Expects an explicit intent.
Jason Monk5e676a22018-03-08 14:18:55 -0500278 * <p>
279 * This goes through a several stage resolution process to determine if any slice
280 * can represent this intent.
Jason Monk39b9fb32018-03-27 10:45:23 -0400281 * <ol>
282 * <li> If the intent contains data that {@link ContentResolver#getType} is
283 * {@link SliceProvider#SLICE_TYPE} then the data will be returned.</li>
Jason Monk5ffacd02018-04-10 15:00:18 -0400284 * <li>If the intent explicitly points at an activity, and that activity has
Jason Monk5e676a22018-03-08 14:18:55 -0500285 * meta-data for key {@link #SLICE_METADATA_KEY}, then the Uri specified there will be
Jason Monk39b9fb32018-03-27 10:45:23 -0400286 * returned.</li>
Jason Monk5ffacd02018-04-10 15:00:18 -0400287 * <li>Lastly, if the intent with {@link #CATEGORY_SLICE} added resolves to a provider, then
288 * the provider will be asked to {@link SliceProvider#onMapIntentToUri} and that result
289 * will be returned.</li>
Jason Monk39b9fb32018-03-27 10:45:23 -0400290 * <li>If no slice is found, then {@code null} is returned.</li>
291 * </ol>
Jason Monk7b8fef22018-01-30 16:04:14 -0500292 * @param intent The intent associated with a slice.
Jason Monkf2008872018-02-23 08:59:31 -0500293 * @return The Slice Uri provided by the app or null if none exists.
Jason Monk7b8fef22018-01-30 16:04:14 -0500294 * @see Slice
295 * @see SliceProvider#onMapIntentToUri(Intent)
296 * @see Intent
297 */
298 public @Nullable Uri mapIntentToUri(@NonNull Intent intent) {
Jason Monk7b8fef22018-01-30 16:04:14 -0500299 ContentResolver resolver = mContext.getContentResolver();
Jason Monk5ffacd02018-04-10 15:00:18 -0400300 final Uri staticUri = resolveStatic(intent, resolver);
301 if (staticUri != null) return staticUri;
Jason Monk7b8fef22018-01-30 16:04:14 -0500302 // Otherwise ask the app
Jason Monk5ffacd02018-04-10 15:00:18 -0400303 String authority = getAuthority(intent);
304 if (authority == null) return null;
Jason Monk7b8fef22018-01-30 16:04:14 -0500305 Uri uri = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
306 .authority(authority).build();
Jason Monk632def12018-02-01 15:21:16 -0500307 try (ContentProviderClient provider = resolver.acquireContentProviderClient(uri)) {
308 if (provider == null) {
309 throw new IllegalArgumentException("Unknown URI " + uri);
310 }
Jason Monk7b8fef22018-01-30 16:04:14 -0500311 Bundle extras = new Bundle();
312 extras.putParcelable(SliceProvider.EXTRA_INTENT, intent);
Jason Monk632def12018-02-01 15:21:16 -0500313 final Bundle res = provider.call(SliceProvider.METHOD_MAP_ONLY_INTENT, null, extras);
Jason Monk7b8fef22018-01-30 16:04:14 -0500314 if (res == null) {
315 return null;
316 }
317 return res.getParcelable(SliceProvider.EXTRA_SLICE);
318 } catch (RemoteException e) {
319 // Arbitrary and not worth documenting, as Activity
320 // Manager will kill this process shortly anyway.
321 return null;
Jason Monk7b8fef22018-01-30 16:04:14 -0500322 }
323 }
324
Jason Monk5ffacd02018-04-10 15:00:18 -0400325 private String getAuthority(Intent intent) {
326 Intent queryIntent = new Intent(intent);
327 if (!queryIntent.hasCategory(CATEGORY_SLICE)) {
328 queryIntent.addCategory(CATEGORY_SLICE);
329 }
330 List<ResolveInfo> providers =
331 mContext.getPackageManager().queryIntentContentProviders(queryIntent, 0);
332 return providers != null && !providers.isEmpty() ? providers.get(0).providerInfo.authority
333 : null;
334 }
335
336 private Uri resolveStatic(@NonNull Intent intent, ContentResolver resolver) {
337 Preconditions.checkNotNull(intent, "intent");
338 Preconditions.checkArgument(intent.getComponent() != null || intent.getPackage() != null
339 || intent.getData() != null,
340 "Slice intent must be explicit %s", intent);
341
342 // Check if the intent has data for the slice uri on it and use that
343 final Uri intentData = intent.getData();
344 if (intentData != null && SliceProvider.SLICE_TYPE.equals(resolver.getType(intentData))) {
345 return intentData;
346 }
347 // There are no providers, see if this activity has a direct link.
348 ResolveInfo resolve = mContext.getPackageManager().resolveActivity(intent,
349 PackageManager.GET_META_DATA);
350 if (resolve != null && resolve.activityInfo != null
351 && resolve.activityInfo.metaData != null
352 && resolve.activityInfo.metaData.containsKey(SLICE_METADATA_KEY)) {
353 return Uri.parse(
354 resolve.activityInfo.metaData.getString(SLICE_METADATA_KEY));
355 }
356 return null;
357 }
358
Jason Monk7b8fef22018-01-30 16:04:14 -0500359 /**
Jason Monk5ffacd02018-04-10 15:00:18 -0400360 * Turns a slice intent into slice content. Is a shortcut to perform the action
Jeff Sharkey3990ee12018-04-11 10:19:55 -0600361 * of both {@link #mapIntentToUri(Intent)} and {@link #bindSlice(Uri, Set)} at once.
Jason Monkb9e06a82018-01-16 15:32:53 -0500362 *
363 * @param intent The intent associated with a slice.
364 * @param supportedSpecs List of supported specs.
365 * @return The Slice provided by the app or null if none is given.
366 * @see Slice
367 * @see SliceProvider#onMapIntentToUri(Intent)
368 * @see Intent
369 */
370 public @Nullable Slice bindSlice(@NonNull Intent intent,
Jason Monk2d3932e2018-03-08 11:31:26 -0500371 @NonNull Set<SliceSpec> supportedSpecs) {
Jason Monkb9e06a82018-01-16 15:32:53 -0500372 Preconditions.checkNotNull(intent, "intent");
Jason Monk135f4172018-03-15 17:48:47 -0400373 Preconditions.checkArgument(intent.getComponent() != null || intent.getPackage() != null
374 || intent.getData() != null,
Jason Monk7b8fef22018-01-30 16:04:14 -0500375 "Slice intent must be explicit %s", intent);
Jason Monkb9e06a82018-01-16 15:32:53 -0500376 ContentResolver resolver = mContext.getContentResolver();
Jason Monk5ffacd02018-04-10 15:00:18 -0400377 final Uri staticUri = resolveStatic(intent, resolver);
378 if (staticUri != null) return bindSlice(staticUri, supportedSpecs);
Jason Monkb9e06a82018-01-16 15:32:53 -0500379 // Otherwise ask the app
Jason Monk5ffacd02018-04-10 15:00:18 -0400380 String authority = getAuthority(intent);
381 if (authority == null) return null;
Jason Monkb9e06a82018-01-16 15:32:53 -0500382 Uri uri = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
383 .authority(authority).build();
Jason Monk632def12018-02-01 15:21:16 -0500384 try (ContentProviderClient provider = resolver.acquireContentProviderClient(uri)) {
385 if (provider == null) {
386 throw new IllegalArgumentException("Unknown URI " + uri);
387 }
Jason Monkb9e06a82018-01-16 15:32:53 -0500388 Bundle extras = new Bundle();
389 extras.putParcelable(SliceProvider.EXTRA_INTENT, intent);
Jason Monk632def12018-02-01 15:21:16 -0500390 final Bundle res = provider.call(SliceProvider.METHOD_MAP_INTENT, null, extras);
Jason Monkb9e06a82018-01-16 15:32:53 -0500391 if (res == null) {
392 return null;
393 }
394 return res.getParcelable(SliceProvider.EXTRA_SLICE);
395 } catch (RemoteException e) {
396 // Arbitrary and not worth documenting, as Activity
397 // Manager will kill this process shortly anyway.
398 return null;
Jason Monkb9e06a82018-01-16 15:32:53 -0500399 }
400 }
401
402 /**
Jason Monk2d3932e2018-03-08 11:31:26 -0500403 * @deprecated TO BE REMOVED.
Jeff Sharkey3990ee12018-04-11 10:19:55 -0600404 * @removed
Jason Monk2d3932e2018-03-08 11:31:26 -0500405 */
406 @Deprecated
407 @Nullable
408 public Slice bindSlice(@NonNull Intent intent,
409 @NonNull List<SliceSpec> supportedSpecs) {
410 return bindSlice(intent, new ArraySet<>(supportedSpecs));
411 }
412
413 /**
Jason Monk71888552018-03-30 14:14:51 -0400414 * Determine whether a particular process and user ID has been granted
415 * permission to access a specific slice URI.
416 *
417 * @param uri The uri that is being checked.
418 * @param pid The process ID being checked against. Must be &gt; 0.
419 * @param uid The user ID being checked against. A uid of 0 is the root
420 * user, which will pass every permission check.
421 *
422 * @return {@link PackageManager#PERMISSION_GRANTED} if the given
423 * pid/uid is allowed to access that uri, or
424 * {@link PackageManager#PERMISSION_DENIED} if it is not.
425 *
426 * @see #grantSlicePermission(String, Uri)
427 */
428 public @PermissionResult int checkSlicePermission(@NonNull Uri uri, int pid, int uid) {
Jason Monkbf3eedc2018-04-05 20:56:42 -0400429 try {
430 return mService.checkSlicePermission(uri, null, pid, uid, null);
431 } catch (RemoteException e) {
432 throw e.rethrowFromSystemServer();
433 }
Jason Monk71888552018-03-30 14:14:51 -0400434 }
435
436 /**
437 * Grant permission to access a specific slice Uri to another package.
438 *
439 * @param toPackage The package you would like to allow to access the Uri.
440 * @param uri The Uri you would like to grant access to.
441 *
442 * @see #revokeSlicePermission
443 */
444 public void grantSlicePermission(@NonNull String toPackage, @NonNull Uri uri) {
Jason Monkbf3eedc2018-04-05 20:56:42 -0400445 try {
446 mService.grantSlicePermission(mContext.getPackageName(), toPackage, uri);
447 } catch (RemoteException e) {
448 throw e.rethrowFromSystemServer();
449 }
Jason Monk71888552018-03-30 14:14:51 -0400450 }
451
452 /**
453 * Remove permissions to access a particular content provider Uri
454 * that were previously added with {@link #grantSlicePermission} for a specific target
455 * package. The given Uri will match all previously granted Uris that are the same or a
456 * sub-path of the given Uri. That is, revoking "content://foo/target" will
457 * revoke both "content://foo/target" and "content://foo/target/sub", but not
458 * "content://foo". It will not remove any prefix grants that exist at a
459 * higher level.
460 *
461 * @param toPackage The package you would like to allow to access the Uri.
462 * @param uri The Uri you would like to revoke access to.
463 *
464 * @see #grantSlicePermission
465 */
466 public void revokeSlicePermission(@NonNull String toPackage, @NonNull Uri uri) {
Jason Monkbf3eedc2018-04-05 20:56:42 -0400467 try {
468 mService.revokeSlicePermission(mContext.getPackageName(), toPackage, uri);
469 } catch (RemoteException e) {
470 throw e.rethrowFromSystemServer();
471 }
Jason Monk71888552018-03-30 14:14:51 -0400472 }
473
474 /**
Jason Monke8f8be72018-01-21 10:10:35 -0500475 * Does the permission check to see if a caller has access to a specific slice.
476 * @hide
477 */
Jason Monk42e03f82018-03-30 11:26:56 -0400478 public void enforceSlicePermission(Uri uri, String pkg, int pid, int uid,
479 String[] autoGrantPermissions) {
Jason Monke8f8be72018-01-21 10:10:35 -0500480 try {
Jason Monkac112382018-03-23 15:06:35 -0400481 if (UserHandle.isSameApp(uid, Process.myUid())) {
482 return;
483 }
Jason Monke8f8be72018-01-21 10:10:35 -0500484 if (pkg == null) {
485 throw new SecurityException("No pkg specified");
486 }
Jason Monk42e03f82018-03-30 11:26:56 -0400487 int result = mService.checkSlicePermission(uri, pkg, pid, uid, autoGrantPermissions);
Jason Monke8f8be72018-01-21 10:10:35 -0500488 if (result == PERMISSION_DENIED) {
489 throw new SecurityException("User " + uid + " does not have slice permission for "
490 + uri + ".");
491 }
Jason Monke8f8be72018-01-21 10:10:35 -0500492 } catch (RemoteException e) {
493 throw e.rethrowFromSystemServer();
494 }
495 }
496
497 /**
498 * Called by SystemUI to grant a slice permission after a dialog is shown.
499 * @hide
500 */
501 public void grantPermissionFromUser(Uri uri, String pkg, boolean allSlices) {
502 try {
503 mService.grantPermissionFromUser(uri, pkg, mContext.getPackageName(), allSlices);
504 } catch (RemoteException e) {
505 throw e.rethrowFromSystemServer();
506 }
507 }
Jason Monk8f5f7ff2017-10-17 14:12:42 -0400508}