blob: 26498e81253a2de4d5fe337a8b8c12539ba94fb5 [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 Monkce1bead2018-05-31 14:12:52 -0400224 try (ContentProviderClient provider = resolver.acquireUnstableContentProviderClient(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 Monkce1bead2018-05-31 14:12:52 -0400246 try (ContentProviderClient provider = resolver.acquireUnstableContentProviderClient(uri)) {
Jason Monk632def12018-02-01 15:21:16 -0500247 if (provider == null) {
Steven Wua14c6b92018-05-22 09:08:22 -0400248 Log.w(TAG, String.format("Unknown URI: %s", uri));
249 return null;
Jason Monk632def12018-02-01 15:21:16 -0500250 }
Jason Monkb9e06a82018-01-16 15:32:53 -0500251 Bundle extras = new Bundle();
252 extras.putParcelable(SliceProvider.EXTRA_BIND_URI, uri);
253 extras.putParcelableArrayList(SliceProvider.EXTRA_SUPPORTED_SPECS,
254 new ArrayList<>(supportedSpecs));
Jason Monk632def12018-02-01 15:21:16 -0500255 final Bundle res = provider.call(SliceProvider.METHOD_SLICE, null, extras);
Jason Monkb9e06a82018-01-16 15:32:53 -0500256 Bundle.setDefusable(res, true);
257 if (res == null) {
258 return null;
259 }
260 return res.getParcelable(SliceProvider.EXTRA_SLICE);
261 } catch (RemoteException e) {
262 // Arbitrary and not worth documenting, as Activity
263 // Manager will kill this process shortly anyway.
264 return null;
Jason Monkb9e06a82018-01-16 15:32:53 -0500265 }
266 }
267
268 /**
Jason Monk2d3932e2018-03-08 11:31:26 -0500269 * @deprecated TO BE REMOVED
Jeff Sharkey3990ee12018-04-11 10:19:55 -0600270 * @removed
Jason Monk2d3932e2018-03-08 11:31:26 -0500271 */
272 @Deprecated
273 public @Nullable Slice bindSlice(@NonNull Uri uri, @NonNull List<SliceSpec> supportedSpecs) {
274 return bindSlice(uri, new ArraySet<>(supportedSpecs));
275 }
276
277 /**
Jason Monkf2008872018-02-23 08:59:31 -0500278 * Turns a slice intent into a slice uri. Expects an explicit intent.
Jason Monk5e676a22018-03-08 14:18:55 -0500279 * <p>
280 * This goes through a several stage resolution process to determine if any slice
281 * can represent this intent.
Jason Monk39b9fb32018-03-27 10:45:23 -0400282 * <ol>
283 * <li> If the intent contains data that {@link ContentResolver#getType} is
284 * {@link SliceProvider#SLICE_TYPE} then the data will be returned.</li>
Jason Monk5ffacd02018-04-10 15:00:18 -0400285 * <li>If the intent explicitly points at an activity, and that activity has
Jason Monk5e676a22018-03-08 14:18:55 -0500286 * meta-data for key {@link #SLICE_METADATA_KEY}, then the Uri specified there will be
Jason Monk39b9fb32018-03-27 10:45:23 -0400287 * returned.</li>
Jason Monk5ffacd02018-04-10 15:00:18 -0400288 * <li>Lastly, if the intent with {@link #CATEGORY_SLICE} added resolves to a provider, then
289 * the provider will be asked to {@link SliceProvider#onMapIntentToUri} and that result
290 * will be returned.</li>
Jason Monk39b9fb32018-03-27 10:45:23 -0400291 * <li>If no slice is found, then {@code null} is returned.</li>
292 * </ol>
Jason Monk7b8fef22018-01-30 16:04:14 -0500293 * @param intent The intent associated with a slice.
Jason Monkf2008872018-02-23 08:59:31 -0500294 * @return The Slice Uri provided by the app or null if none exists.
Jason Monk7b8fef22018-01-30 16:04:14 -0500295 * @see Slice
296 * @see SliceProvider#onMapIntentToUri(Intent)
297 * @see Intent
298 */
299 public @Nullable Uri mapIntentToUri(@NonNull Intent intent) {
Jason Monk7b8fef22018-01-30 16:04:14 -0500300 ContentResolver resolver = mContext.getContentResolver();
Jason Monk5ffacd02018-04-10 15:00:18 -0400301 final Uri staticUri = resolveStatic(intent, resolver);
302 if (staticUri != null) return staticUri;
Jason Monk7b8fef22018-01-30 16:04:14 -0500303 // Otherwise ask the app
Jason Monk5ffacd02018-04-10 15:00:18 -0400304 String authority = getAuthority(intent);
305 if (authority == null) return null;
Jason Monk7b8fef22018-01-30 16:04:14 -0500306 Uri uri = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
307 .authority(authority).build();
Jason Monkce1bead2018-05-31 14:12:52 -0400308 try (ContentProviderClient provider = resolver.acquireUnstableContentProviderClient(uri)) {
Jason Monk632def12018-02-01 15:21:16 -0500309 if (provider == null) {
Steven Wua14c6b92018-05-22 09:08:22 -0400310 Log.w(TAG, String.format("Unknown URI: %s", uri));
311 return null;
Jason Monk632def12018-02-01 15:21:16 -0500312 }
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
Jason Monk5ffacd02018-04-10 15:00:18 -0400327 private String getAuthority(Intent intent) {
328 Intent queryIntent = new Intent(intent);
329 if (!queryIntent.hasCategory(CATEGORY_SLICE)) {
330 queryIntent.addCategory(CATEGORY_SLICE);
331 }
332 List<ResolveInfo> providers =
333 mContext.getPackageManager().queryIntentContentProviders(queryIntent, 0);
334 return providers != null && !providers.isEmpty() ? providers.get(0).providerInfo.authority
335 : null;
336 }
337
338 private Uri resolveStatic(@NonNull Intent intent, ContentResolver resolver) {
339 Preconditions.checkNotNull(intent, "intent");
340 Preconditions.checkArgument(intent.getComponent() != null || intent.getPackage() != null
341 || intent.getData() != null,
342 "Slice intent must be explicit %s", intent);
343
344 // Check if the intent has data for the slice uri on it and use that
345 final Uri intentData = intent.getData();
346 if (intentData != null && SliceProvider.SLICE_TYPE.equals(resolver.getType(intentData))) {
347 return intentData;
348 }
349 // There are no providers, see if this activity has a direct link.
350 ResolveInfo resolve = mContext.getPackageManager().resolveActivity(intent,
351 PackageManager.GET_META_DATA);
352 if (resolve != null && resolve.activityInfo != null
353 && resolve.activityInfo.metaData != null
354 && resolve.activityInfo.metaData.containsKey(SLICE_METADATA_KEY)) {
355 return Uri.parse(
356 resolve.activityInfo.metaData.getString(SLICE_METADATA_KEY));
357 }
358 return null;
359 }
360
Jason Monk7b8fef22018-01-30 16:04:14 -0500361 /**
Jason Monk5ffacd02018-04-10 15:00:18 -0400362 * Turns a slice intent into slice content. Is a shortcut to perform the action
Jeff Sharkey3990ee12018-04-11 10:19:55 -0600363 * of both {@link #mapIntentToUri(Intent)} and {@link #bindSlice(Uri, Set)} at once.
Jason Monkb9e06a82018-01-16 15:32:53 -0500364 *
365 * @param intent The intent associated with a slice.
366 * @param supportedSpecs List of supported specs.
367 * @return The Slice provided by the app or null if none is given.
368 * @see Slice
369 * @see SliceProvider#onMapIntentToUri(Intent)
370 * @see Intent
371 */
372 public @Nullable Slice bindSlice(@NonNull Intent intent,
Jason Monk2d3932e2018-03-08 11:31:26 -0500373 @NonNull Set<SliceSpec> supportedSpecs) {
Jason Monkb9e06a82018-01-16 15:32:53 -0500374 Preconditions.checkNotNull(intent, "intent");
Jason Monk135f4172018-03-15 17:48:47 -0400375 Preconditions.checkArgument(intent.getComponent() != null || intent.getPackage() != null
376 || intent.getData() != null,
Jason Monk7b8fef22018-01-30 16:04:14 -0500377 "Slice intent must be explicit %s", intent);
Jason Monkb9e06a82018-01-16 15:32:53 -0500378 ContentResolver resolver = mContext.getContentResolver();
Jason Monk5ffacd02018-04-10 15:00:18 -0400379 final Uri staticUri = resolveStatic(intent, resolver);
380 if (staticUri != null) return bindSlice(staticUri, supportedSpecs);
Jason Monkb9e06a82018-01-16 15:32:53 -0500381 // Otherwise ask the app
Jason Monk5ffacd02018-04-10 15:00:18 -0400382 String authority = getAuthority(intent);
383 if (authority == null) return null;
Jason Monkb9e06a82018-01-16 15:32:53 -0500384 Uri uri = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
385 .authority(authority).build();
Jason Monkce1bead2018-05-31 14:12:52 -0400386 try (ContentProviderClient provider = resolver.acquireUnstableContentProviderClient(uri)) {
Jason Monk632def12018-02-01 15:21:16 -0500387 if (provider == null) {
Steven Wua14c6b92018-05-22 09:08:22 -0400388 Log.w(TAG, String.format("Unknown URI: %s", uri));
389 return null;
Jason Monk632def12018-02-01 15:21:16 -0500390 }
Jason Monkb9e06a82018-01-16 15:32:53 -0500391 Bundle extras = new Bundle();
392 extras.putParcelable(SliceProvider.EXTRA_INTENT, intent);
Jason Monk632def12018-02-01 15:21:16 -0500393 final Bundle res = provider.call(SliceProvider.METHOD_MAP_INTENT, null, extras);
Jason Monkb9e06a82018-01-16 15:32:53 -0500394 if (res == null) {
395 return null;
396 }
397 return res.getParcelable(SliceProvider.EXTRA_SLICE);
398 } catch (RemoteException e) {
399 // Arbitrary and not worth documenting, as Activity
400 // Manager will kill this process shortly anyway.
401 return null;
Jason Monkb9e06a82018-01-16 15:32:53 -0500402 }
403 }
404
405 /**
Jason Monk2d3932e2018-03-08 11:31:26 -0500406 * @deprecated TO BE REMOVED.
Jeff Sharkey3990ee12018-04-11 10:19:55 -0600407 * @removed
Jason Monk2d3932e2018-03-08 11:31:26 -0500408 */
409 @Deprecated
410 @Nullable
411 public Slice bindSlice(@NonNull Intent intent,
412 @NonNull List<SliceSpec> supportedSpecs) {
413 return bindSlice(intent, new ArraySet<>(supportedSpecs));
414 }
415
416 /**
Jason Monk71888552018-03-30 14:14:51 -0400417 * Determine whether a particular process and user ID has been granted
418 * permission to access a specific slice URI.
419 *
420 * @param uri The uri that is being checked.
421 * @param pid The process ID being checked against. Must be &gt; 0.
422 * @param uid The user ID being checked against. A uid of 0 is the root
423 * user, which will pass every permission check.
424 *
425 * @return {@link PackageManager#PERMISSION_GRANTED} if the given
426 * pid/uid is allowed to access that uri, or
427 * {@link PackageManager#PERMISSION_DENIED} if it is not.
428 *
429 * @see #grantSlicePermission(String, Uri)
430 */
431 public @PermissionResult int checkSlicePermission(@NonNull Uri uri, int pid, int uid) {
Jason Monkbf3eedc2018-04-05 20:56:42 -0400432 try {
433 return mService.checkSlicePermission(uri, null, pid, uid, null);
434 } catch (RemoteException e) {
435 throw e.rethrowFromSystemServer();
436 }
Jason Monk71888552018-03-30 14:14:51 -0400437 }
438
439 /**
440 * Grant permission to access a specific slice Uri to another package.
441 *
442 * @param toPackage The package you would like to allow to access the Uri.
443 * @param uri The Uri you would like to grant access to.
444 *
445 * @see #revokeSlicePermission
446 */
447 public void grantSlicePermission(@NonNull String toPackage, @NonNull Uri uri) {
Jason Monkbf3eedc2018-04-05 20:56:42 -0400448 try {
449 mService.grantSlicePermission(mContext.getPackageName(), toPackage, uri);
450 } catch (RemoteException e) {
451 throw e.rethrowFromSystemServer();
452 }
Jason Monk71888552018-03-30 14:14:51 -0400453 }
454
455 /**
456 * Remove permissions to access a particular content provider Uri
457 * that were previously added with {@link #grantSlicePermission} for a specific target
458 * package. The given Uri will match all previously granted Uris that are the same or a
459 * sub-path of the given Uri. That is, revoking "content://foo/target" will
460 * revoke both "content://foo/target" and "content://foo/target/sub", but not
461 * "content://foo". It will not remove any prefix grants that exist at a
462 * higher level.
463 *
464 * @param toPackage The package you would like to allow to access the Uri.
465 * @param uri The Uri you would like to revoke access to.
466 *
467 * @see #grantSlicePermission
468 */
469 public void revokeSlicePermission(@NonNull String toPackage, @NonNull Uri uri) {
Jason Monkbf3eedc2018-04-05 20:56:42 -0400470 try {
471 mService.revokeSlicePermission(mContext.getPackageName(), toPackage, uri);
472 } catch (RemoteException e) {
473 throw e.rethrowFromSystemServer();
474 }
Jason Monk71888552018-03-30 14:14:51 -0400475 }
476
477 /**
Jason Monke8f8be72018-01-21 10:10:35 -0500478 * Does the permission check to see if a caller has access to a specific slice.
479 * @hide
480 */
Jason Monk42e03f82018-03-30 11:26:56 -0400481 public void enforceSlicePermission(Uri uri, String pkg, int pid, int uid,
482 String[] autoGrantPermissions) {
Jason Monke8f8be72018-01-21 10:10:35 -0500483 try {
Jason Monkac112382018-03-23 15:06:35 -0400484 if (UserHandle.isSameApp(uid, Process.myUid())) {
485 return;
486 }
Jason Monke8f8be72018-01-21 10:10:35 -0500487 if (pkg == null) {
488 throw new SecurityException("No pkg specified");
489 }
Jason Monk42e03f82018-03-30 11:26:56 -0400490 int result = mService.checkSlicePermission(uri, pkg, pid, uid, autoGrantPermissions);
Jason Monke8f8be72018-01-21 10:10:35 -0500491 if (result == PERMISSION_DENIED) {
492 throw new SecurityException("User " + uid + " does not have slice permission for "
493 + uri + ".");
494 }
Jason Monke8f8be72018-01-21 10:10:35 -0500495 } catch (RemoteException e) {
496 throw e.rethrowFromSystemServer();
497 }
498 }
499
500 /**
501 * Called by SystemUI to grant a slice permission after a dialog is shown.
502 * @hide
503 */
504 public void grantPermissionFromUser(Uri uri, String pkg, boolean allSlices) {
505 try {
506 mService.grantPermissionFromUser(uri, pkg, mContext.getPackageName(), allSlices);
507 } catch (RemoteException e) {
508 throw e.rethrowFromSystemServer();
509 }
510 }
Jason Monk8f5f7ff2017-10-17 14:12:42 -0400511}