blob: 7d8e394dbc355b76dfd6314cce794130fdf37029 [file] [log] [blame]
Jason Monkd9edfa942017-09-25 12:38:53 -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 */
Jason Monkd18651f2017-10-05 14:18:49 -040016package android.app.slice;
Jason Monkd9edfa942017-09-25 12:38:53 -040017
Mady Mellor3b0a72f2017-10-19 10:12:09 -070018import android.annotation.NonNull;
Jason Monke8f8be72018-01-21 10:10:35 -050019import android.app.PendingIntent;
20import android.content.ComponentName;
Jason Monkd9edfa942017-09-25 12:38:53 -040021import android.content.ContentProvider;
22import android.content.ContentResolver;
23import android.content.ContentValues;
Jason Monke8f8be72018-01-21 10:10:35 -050024import android.content.Context;
Jason Monkb40dad52017-11-01 16:01:40 -040025import android.content.Intent;
Mady Mellor3b0a72f2017-10-19 10:12:09 -070026import android.content.IntentFilter;
Jason Monke8f8be72018-01-21 10:10:35 -050027import android.content.pm.PackageManager;
28import android.content.pm.PackageManager.NameNotFoundException;
29import android.content.pm.ProviderInfo;
Jason Monkd9edfa942017-09-25 12:38:53 -040030import android.database.ContentObserver;
31import android.database.Cursor;
32import android.net.Uri;
Jason Monkb40dad52017-11-01 16:01:40 -040033import android.os.Binder;
Jason Monkd9edfa942017-09-25 12:38:53 -040034import android.os.Bundle;
35import android.os.CancellationSignal;
36import android.os.Handler;
Jason Monkb40dad52017-11-01 16:01:40 -040037import android.os.Process;
Jason Monkd18651f2017-10-05 14:18:49 -040038import android.os.StrictMode;
39import android.os.StrictMode.ThreadPolicy;
Jason Monkd9edfa942017-09-25 12:38:53 -040040import android.util.Log;
41
Jason Monk5f8cc272018-01-16 17:57:20 -050042import java.util.ArrayList;
Jason Monk106387f2018-03-06 16:32:28 -050043import java.util.Arrays;
Jason Monk5f8cc272018-01-16 17:57:20 -050044import java.util.Collection;
45import java.util.Collections;
Jason Monk2af19982017-11-07 19:38:27 -050046import java.util.List;
Jason Monk2d3932e2018-03-08 11:31:26 -050047import java.util.Set;
Jason Monkd9edfa942017-09-25 12:38:53 -040048
49/**
Mady Mellor3b0a72f2017-10-19 10:12:09 -070050 * A SliceProvider allows an app to provide content to be displayed in system spaces. This content
51 * is templated and can contain actions, and the behavior of how it is surfaced is specific to the
52 * system surface.
53 * <p>
54 * Slices are not currently live content. They are bound once and shown to the user. If the content
55 * changes due to a callback from user interaction, then
56 * {@link ContentResolver#notifyChange(Uri, ContentObserver)} should be used to notify the system.
57 * </p>
58 * <p>
59 * The provider needs to be declared in the manifest to provide the authority for the app. The
60 * authority for most slices is expected to match the package of the application.
61 * </p>
Jason Monkd9edfa942017-09-25 12:38:53 -040062 *
Jason Monkd9edfa942017-09-25 12:38:53 -040063 * <pre class="prettyprint">
64 * {@literal
65 * <provider
Jason Monkad594512018-03-08 11:35:55 -050066 * android:name="com.example.mypkg.MySliceProvider"
67 * android:authorities="com.example.mypkg" />}
Jason Monkd9edfa942017-09-25 12:38:53 -040068 * </pre>
Mady Mellor3b0a72f2017-10-19 10:12:09 -070069 * <p>
70 * Slices can be identified by a Uri or by an Intent. To link an Intent with a slice, the provider
71 * must have an {@link IntentFilter} matching the slice intent. When a slice is being requested via
72 * an intent, {@link #onMapIntentToUri(Intent)} can be called and is expected to return an
73 * appropriate Uri representing the slice.
74 *
75 * <pre class="prettyprint">
76 * {@literal
77 * <provider
Jason Monkad594512018-03-08 11:35:55 -050078 * android:name="com.example.mypkg.MySliceProvider"
79 * android:authorities="com.example.mypkg">
Mady Mellor3b0a72f2017-10-19 10:12:09 -070080 * <intent-filter>
Jason Monkad594512018-03-08 11:35:55 -050081 * <action android:name="com.example.mypkg.intent.action.MY_SLICE_INTENT" />
Jason Monk5e676a22018-03-08 14:18:55 -050082 * <category android:name="android.app.slice.category.SLICE" />
Mady Mellor3b0a72f2017-10-19 10:12:09 -070083 * </intent-filter>
84 * </provider>}
85 * </pre>
Jason Monkd9edfa942017-09-25 12:38:53 -040086 *
87 * @see Slice
Jason Monkd9edfa942017-09-25 12:38:53 -040088 */
89public abstract class SliceProvider extends ContentProvider {
Jason Monkd18651f2017-10-05 14:18:49 -040090 /**
Jason Monka9b3d732018-01-22 15:37:00 -050091 * This is the Android platform's MIME type for a URI
Jason Monkd18651f2017-10-05 14:18:49 -040092 * containing a slice implemented through {@link SliceProvider}.
93 */
94 public static final String SLICE_TYPE = "vnd.android.slice";
95
Jason Monkd9edfa942017-09-25 12:38:53 -040096 private static final String TAG = "SliceProvider";
97 /**
98 * @hide
99 */
100 public static final String EXTRA_BIND_URI = "slice_uri";
101 /**
102 * @hide
103 */
Jason Monk2af19982017-11-07 19:38:27 -0500104 public static final String EXTRA_SUPPORTED_SPECS = "supported_specs";
105 /**
106 * @hide
107 */
Jason Monkd9edfa942017-09-25 12:38:53 -0400108 public static final String METHOD_SLICE = "bind_slice";
109 /**
110 * @hide
111 */
Mady Mellor3b0a72f2017-10-19 10:12:09 -0700112 public static final String METHOD_MAP_INTENT = "map_slice";
113 /**
114 * @hide
115 */
Jason Monk7b8fef22018-01-30 16:04:14 -0500116 public static final String METHOD_MAP_ONLY_INTENT = "map_only";
117 /**
118 * @hide
119 */
Jason Monk74f5e362017-12-06 08:56:33 -0500120 public static final String METHOD_PIN = "pin";
121 /**
122 * @hide
123 */
124 public static final String METHOD_UNPIN = "unpin";
125 /**
126 * @hide
127 */
Jason Monk5f8cc272018-01-16 17:57:20 -0500128 public static final String METHOD_GET_DESCENDANTS = "get_descendants";
129 /**
130 * @hide
131 */
Mady Mellor3b0a72f2017-10-19 10:12:09 -0700132 public static final String EXTRA_INTENT = "slice_intent";
133 /**
134 * @hide
135 */
Jason Monkd9edfa942017-09-25 12:38:53 -0400136 public static final String EXTRA_SLICE = "slice";
Jason Monk5f8cc272018-01-16 17:57:20 -0500137 /**
138 * @hide
139 */
140 public static final String EXTRA_SLICE_DESCENDANTS = "slice_descendants";
Jason Monke8f8be72018-01-21 10:10:35 -0500141 /**
142 * @hide
143 */
144 public static final String EXTRA_PKG = "pkg";
145 /**
146 * @hide
147 */
148 public static final String EXTRA_PROVIDER_PKG = "provider_pkg";
Jason Monkd9edfa942017-09-25 12:38:53 -0400149
150 private static final boolean DEBUG = false;
151
Jason Monk66cffd52018-03-12 16:42:48 -0400152 private static final long SLICE_BIND_ANR = 2000;
Jason Monk42e03f82018-03-30 11:26:56 -0400153 private final String[] mAutoGrantPermissions;
Jason Monke8f8be72018-01-21 10:10:35 -0500154
Jason Monk66cffd52018-03-12 16:42:48 -0400155 private String mCallback;
156 private SliceManager mSliceManager;
Jason Monke8f8be72018-01-21 10:10:35 -0500157
Jason Monk42e03f82018-03-30 11:26:56 -0400158 /**
159 * A version of constructing a SliceProvider that allows autogranting slice permissions
160 * to apps that hold specific platform permissions.
161 * <p>
162 * When an app tries to bind a slice from this provider that it does not have access to,
163 * This provider will check if the caller holds permissions to any of the autoGrantPermissions
164 * specified, if they do they will be granted persisted uri access to all slices of this
165 * provider.
166 *
167 * @param autoGrantPermissions List of permissions that holders are auto-granted access
168 * to slices.
169 */
170 public SliceProvider(@NonNull String... autoGrantPermissions) {
171 mAutoGrantPermissions = autoGrantPermissions;
172 }
173
174 public SliceProvider() {
175 mAutoGrantPermissions = new String[0];
176 }
177
Jason Monke8f8be72018-01-21 10:10:35 -0500178 @Override
179 public void attachInfo(Context context, ProviderInfo info) {
180 super.attachInfo(context, info);
181 mSliceManager = context.getSystemService(SliceManager.class);
182 }
183
Jason Monkd9edfa942017-09-25 12:38:53 -0400184 /**
Jason Monk66cffd52018-03-12 16:42:48 -0400185 * Implemented to create a slice.
Jason Monkd18651f2017-10-05 14:18:49 -0400186 * <p>
187 * onBindSlice should return as quickly as possible so that the UI tied
188 * to this slice can be responsive. No network or other IO will be allowed
189 * during onBindSlice. Any loading that needs to be done should happen
Jason Monk66cffd52018-03-12 16:42:48 -0400190 * in the background with a call to {@link ContentResolver#notifyChange(Uri, ContentObserver)}
Jason Monkd18651f2017-10-05 14:18:49 -0400191 * when the app is ready to provide the complete data in onBindSlice.
192 * <p>
Jason Monk2af19982017-11-07 19:38:27 -0500193 * The slice returned should have a spec that is compatible with one of
194 * the supported specs.
Jason Monkd18651f2017-10-05 14:18:49 -0400195 *
Jason Monk2af19982017-11-07 19:38:27 -0500196 * @param sliceUri Uri to bind.
197 * @param supportedSpecs List of supported specs.
Jason Monkd9edfa942017-09-25 12:38:53 -0400198 * @see {@link Slice}.
Jason Monkd18651f2017-10-05 14:18:49 -0400199 * @see {@link Slice#HINT_PARTIAL}
Jason Monkd9edfa942017-09-25 12:38:53 -0400200 */
Jason Monk2d3932e2018-03-08 11:31:26 -0500201 public Slice onBindSlice(Uri sliceUri, Set<SliceSpec> supportedSpecs) {
202 return onBindSlice(sliceUri, new ArrayList<>(supportedSpecs));
203 }
204
205 /**
206 * @deprecated TO BE REMOVED
Jeff Sharkey3990ee12018-04-11 10:19:55 -0600207 * @removed
Jason Monk2d3932e2018-03-08 11:31:26 -0500208 */
209 @Deprecated
Jason Monk2af19982017-11-07 19:38:27 -0500210 public Slice onBindSlice(Uri sliceUri, List<SliceSpec> supportedSpecs) {
Jason Monk2af19982017-11-07 19:38:27 -0500211 return null;
212 }
Jason Monkd9edfa942017-09-25 12:38:53 -0400213
Mady Mellor3b0a72f2017-10-19 10:12:09 -0700214 /**
Jason Monke2c64512017-12-11 15:14:54 -0500215 * Called to inform an app that a slice has been pinned.
216 * <p>
217 * Pinning is a way that slice hosts use to notify apps of which slices
218 * they care about updates for. When a slice is pinned the content is
219 * expected to be relatively fresh and kept up to date.
220 * <p>
221 * Being pinned does not provide any escalated privileges for the slice
222 * provider. So apps should do things such as turn on syncing or schedule
223 * a job in response to a onSlicePinned.
224 * <p>
225 * Pinned state is not persisted through a reboot, and apps can expect a
226 * new call to onSlicePinned for any slices that should remain pinned
227 * after a reboot occurs.
228 *
229 * @param sliceUri The uri of the slice being unpinned.
230 * @see #onSliceUnpinned(Uri)
Jason Monk74f5e362017-12-06 08:56:33 -0500231 */
232 public void onSlicePinned(Uri sliceUri) {
233 }
234
235 /**
Jason Monke2c64512017-12-11 15:14:54 -0500236 * Called to inform an app that a slices is no longer pinned.
237 * <p>
238 * This means that no other apps on the device care about updates to this
239 * slice anymore and therefore it is not important to be updated. Any syncs
240 * or jobs related to this slice should be cancelled.
241 * @see #onSlicePinned(Uri)
Jason Monk74f5e362017-12-06 08:56:33 -0500242 */
243 public void onSliceUnpinned(Uri sliceUri) {
244 }
245
246 /**
Jason Monk5f8cc272018-01-16 17:57:20 -0500247 * Obtains a list of slices that are descendants of the specified Uri.
248 * <p>
249 * Implementing this is optional for a SliceProvider, but does provide a good
250 * discovery mechanism for finding slice Uris.
251 *
252 * @param uri The uri to look for descendants under.
253 * @return All slices within the space.
254 * @see SliceManager#getSliceDescendants(Uri)
255 */
256 public @NonNull Collection<Uri> onGetSliceDescendants(@NonNull Uri uri) {
257 return Collections.emptyList();
258 }
259
260 /**
Mady Mellor3b0a72f2017-10-19 10:12:09 -0700261 * This method must be overridden if an {@link IntentFilter} is specified on the SliceProvider.
262 * In that case, this method can be called and is expected to return a non-null Uri representing
263 * a slice. Otherwise this will throw {@link UnsupportedOperationException}.
264 *
Jason Monk5e676a22018-03-08 14:18:55 -0500265 * Any intent filter added to a slice provider should also contain
266 * {@link SliceManager#CATEGORY_SLICE}, because otherwise it will not be detected by
267 * {@link SliceManager#mapIntentToUri(Intent)}.
268 *
Mady Mellor3b0a72f2017-10-19 10:12:09 -0700269 * @return Uri representing the slice associated with the provided intent.
Jason Monk5e676a22018-03-08 14:18:55 -0500270 * @see Slice
271 * @see SliceManager#mapIntentToUri(Intent)
Mady Mellor3b0a72f2017-10-19 10:12:09 -0700272 */
273 public @NonNull Uri onMapIntentToUri(Intent intent) {
274 throw new UnsupportedOperationException(
275 "This provider has not implemented intent to uri mapping");
276 }
277
Jason Monkac112382018-03-23 15:06:35 -0400278 /**
279 * Called when an app requests a slice it does not have write permission
280 * to the uri for.
281 * <p>
282 * The return value will be the action on a slice that prompts the user that
283 * the calling app wants to show slices from this app. The default implementation
284 * launches a dialog that allows the user to grant access to this slice. Apps
285 * that do not want to allow this user grant, can override this and instead
286 * launch their own dialog with different behavior.
287 *
288 * @param sliceUri the Uri of the slice attempting to be bound.
289 * @see #getCallingPackage()
290 */
291 public @NonNull PendingIntent onCreatePermissionRequest(Uri sliceUri) {
292 return createPermissionIntent(getContext(), sliceUri, getCallingPackage());
293 }
294
Jason Monkd9edfa942017-09-25 12:38:53 -0400295 @Override
296 public final int update(Uri uri, ContentValues values, String selection,
297 String[] selectionArgs) {
298 if (DEBUG) Log.d(TAG, "update " + uri);
299 return 0;
300 }
301
302 @Override
303 public final int delete(Uri uri, String selection, String[] selectionArgs) {
304 if (DEBUG) Log.d(TAG, "delete " + uri);
305 return 0;
306 }
307
308 @Override
309 public final Cursor query(Uri uri, String[] projection, String selection,
310 String[] selectionArgs, String sortOrder) {
311 if (DEBUG) Log.d(TAG, "query " + uri);
312 return null;
313 }
314
315 @Override
316 public final Cursor query(Uri uri, String[] projection, String selection, String[]
317 selectionArgs, String sortOrder, CancellationSignal cancellationSignal) {
318 if (DEBUG) Log.d(TAG, "query " + uri);
319 return null;
320 }
321
322 @Override
323 public final Cursor query(Uri uri, String[] projection, Bundle queryArgs,
324 CancellationSignal cancellationSignal) {
325 if (DEBUG) Log.d(TAG, "query " + uri);
326 return null;
327 }
328
329 @Override
330 public final Uri insert(Uri uri, ContentValues values) {
331 if (DEBUG) Log.d(TAG, "insert " + uri);
332 return null;
333 }
334
335 @Override
336 public final String getType(Uri uri) {
337 if (DEBUG) Log.d(TAG, "getType " + uri);
Jason Monkd18651f2017-10-05 14:18:49 -0400338 return SLICE_TYPE;
Jason Monkd9edfa942017-09-25 12:38:53 -0400339 }
340
341 @Override
Jason Monkd18651f2017-10-05 14:18:49 -0400342 public Bundle call(String method, String arg, Bundle extras) {
Jason Monkd9edfa942017-09-25 12:38:53 -0400343 if (method.equals(METHOD_SLICE)) {
Jason Monk74848ae2018-01-21 17:11:57 -0500344 Uri uri = getUriWithoutUserId(extras.getParcelable(EXTRA_BIND_URI));
Jason Monk2af19982017-11-07 19:38:27 -0500345 List<SliceSpec> supportedSpecs = extras.getParcelableArrayList(EXTRA_SUPPORTED_SPECS);
Jason Monkd9edfa942017-09-25 12:38:53 -0400346
Jason Monke8f8be72018-01-21 10:10:35 -0500347 String callingPackage = getCallingPackage();
Jason Monk3a1d2e972018-01-29 16:58:11 -0500348 int callingUid = Binder.getCallingUid();
349 int callingPid = Binder.getCallingPid();
Jason Monkac112382018-03-23 15:06:35 -0400350
Jason Monk3a1d2e972018-01-29 16:58:11 -0500351 Slice s = handleBindSlice(uri, supportedSpecs, callingPackage, callingUid, callingPid);
Jason Monkd9edfa942017-09-25 12:38:53 -0400352 Bundle b = new Bundle();
353 b.putParcelable(EXTRA_SLICE, s);
354 return b;
Mady Mellor3b0a72f2017-10-19 10:12:09 -0700355 } else if (method.equals(METHOD_MAP_INTENT)) {
Mady Mellor3b0a72f2017-10-19 10:12:09 -0700356 Intent intent = extras.getParcelable(EXTRA_INTENT);
Jason Monk74f5e362017-12-06 08:56:33 -0500357 if (intent == null) return null;
Mady Mellor3b0a72f2017-10-19 10:12:09 -0700358 Uri uri = onMapIntentToUri(intent);
Jason Monk2af19982017-11-07 19:38:27 -0500359 List<SliceSpec> supportedSpecs = extras.getParcelableArrayList(EXTRA_SUPPORTED_SPECS);
Mady Mellor3b0a72f2017-10-19 10:12:09 -0700360 Bundle b = new Bundle();
361 if (uri != null) {
Jason Monk3a1d2e972018-01-29 16:58:11 -0500362 Slice s = handleBindSlice(uri, supportedSpecs, getCallingPackage(),
363 Binder.getCallingUid(), Binder.getCallingPid());
Mady Mellor3b0a72f2017-10-19 10:12:09 -0700364 b.putParcelable(EXTRA_SLICE, s);
365 } else {
366 b.putParcelable(EXTRA_SLICE, null);
367 }
368 return b;
Jason Monk7b8fef22018-01-30 16:04:14 -0500369 } else if (method.equals(METHOD_MAP_ONLY_INTENT)) {
370 Intent intent = extras.getParcelable(EXTRA_INTENT);
371 if (intent == null) return null;
372 Uri uri = onMapIntentToUri(intent);
373 Bundle b = new Bundle();
374 b.putParcelable(EXTRA_SLICE, uri);
375 return b;
Jason Monk74f5e362017-12-06 08:56:33 -0500376 } else if (method.equals(METHOD_PIN)) {
Jason Monk74848ae2018-01-21 17:11:57 -0500377 Uri uri = getUriWithoutUserId(extras.getParcelable(EXTRA_BIND_URI));
Jason Monke8f8be72018-01-21 10:10:35 -0500378 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
379 throw new SecurityException("Only the system can pin/unpin slices");
Jason Monk74f5e362017-12-06 08:56:33 -0500380 }
381 handlePinSlice(uri);
382 } else if (method.equals(METHOD_UNPIN)) {
Jason Monk74848ae2018-01-21 17:11:57 -0500383 Uri uri = getUriWithoutUserId(extras.getParcelable(EXTRA_BIND_URI));
Jason Monke8f8be72018-01-21 10:10:35 -0500384 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
385 throw new SecurityException("Only the system can pin/unpin slices");
Jason Monk74f5e362017-12-06 08:56:33 -0500386 }
387 handleUnpinSlice(uri);
Jason Monk5f8cc272018-01-16 17:57:20 -0500388 } else if (method.equals(METHOD_GET_DESCENDANTS)) {
Jason Monk74848ae2018-01-21 17:11:57 -0500389 Uri uri = getUriWithoutUserId(extras.getParcelable(EXTRA_BIND_URI));
Jason Monk5f8cc272018-01-16 17:57:20 -0500390 Bundle b = new Bundle();
391 b.putParcelableArrayList(EXTRA_SLICE_DESCENDANTS,
392 new ArrayList<>(handleGetDescendants(uri)));
393 return b;
Jason Monkd9edfa942017-09-25 12:38:53 -0400394 }
395 return super.call(method, arg, extras);
396 }
397
Jason Monk5f8cc272018-01-16 17:57:20 -0500398 private Collection<Uri> handleGetDescendants(Uri uri) {
Jason Monk66cffd52018-03-12 16:42:48 -0400399 mCallback = "onGetSliceDescendants";
400 Handler.getMain().postDelayed(mAnr, SLICE_BIND_ANR);
401 try {
Jason Monk5f8cc272018-01-16 17:57:20 -0500402 return onGetSliceDescendants(uri);
Jason Monk66cffd52018-03-12 16:42:48 -0400403 } finally {
404 Handler.getMain().removeCallbacks(mAnr);
Jason Monk5f8cc272018-01-16 17:57:20 -0500405 }
406 }
407
Jason Monk74f5e362017-12-06 08:56:33 -0500408 private void handlePinSlice(Uri sliceUri) {
Jason Monk66cffd52018-03-12 16:42:48 -0400409 mCallback = "onSlicePinned";
410 Handler.getMain().postDelayed(mAnr, SLICE_BIND_ANR);
411 try {
Jason Monk74f5e362017-12-06 08:56:33 -0500412 onSlicePinned(sliceUri);
Jason Monk66cffd52018-03-12 16:42:48 -0400413 } finally {
414 Handler.getMain().removeCallbacks(mAnr);
Jason Monk74f5e362017-12-06 08:56:33 -0500415 }
416 }
417
418 private void handleUnpinSlice(Uri sliceUri) {
Jason Monk66cffd52018-03-12 16:42:48 -0400419 mCallback = "onSliceUnpinned";
420 Handler.getMain().postDelayed(mAnr, SLICE_BIND_ANR);
421 try {
Jason Monk74f5e362017-12-06 08:56:33 -0500422 onSliceUnpinned(sliceUri);
Jason Monk66cffd52018-03-12 16:42:48 -0400423 } finally {
424 Handler.getMain().removeCallbacks(mAnr);
Jason Monk74f5e362017-12-06 08:56:33 -0500425 }
426 }
427
Jason Monke8f8be72018-01-21 10:10:35 -0500428 private Slice handleBindSlice(Uri sliceUri, List<SliceSpec> supportedSpecs,
Jason Monk3a1d2e972018-01-29 16:58:11 -0500429 String callingPkg, int callingUid, int callingPid) {
Jason Monke8f8be72018-01-21 10:10:35 -0500430 // This can be removed once Slice#bindSlice is removed and everyone is using
431 // SliceManager#bindSlice.
432 String pkg = callingPkg != null ? callingPkg
Jason Monk3a1d2e972018-01-29 16:58:11 -0500433 : getContext().getPackageManager().getNameForUid(callingUid);
Jason Monkac112382018-03-23 15:06:35 -0400434 try {
435 mSliceManager.enforceSlicePermission(sliceUri, pkg,
Jason Monk42e03f82018-03-30 11:26:56 -0400436 callingPid, callingUid, mAutoGrantPermissions);
Jason Monkac112382018-03-23 15:06:35 -0400437 } catch (SecurityException e) {
438 return createPermissionSlice(getContext(), sliceUri, pkg);
Jason Monke8f8be72018-01-21 10:10:35 -0500439 }
Jason Monk66cffd52018-03-12 16:42:48 -0400440 mCallback = "onBindSlice";
441 Handler.getMain().postDelayed(mAnr, SLICE_BIND_ANR);
442 try {
443 return onBindSliceStrict(sliceUri, supportedSpecs);
444 } finally {
445 Handler.getMain().removeCallbacks(mAnr);
Lucas Dupine0653fa2017-10-23 14:31:45 -0700446 }
447 }
448
Jason Monke8f8be72018-01-21 10:10:35 -0500449 /**
450 * @hide
451 */
Jason Monkac112382018-03-23 15:06:35 -0400452 public Slice createPermissionSlice(Context context, Uri sliceUri,
Jason Monke8f8be72018-01-21 10:10:35 -0500453 String callingPackage) {
Jason Monkac112382018-03-23 15:06:35 -0400454 PendingIntent action;
455 mCallback = "onCreatePermissionRequest";
456 Handler.getMain().postDelayed(mAnr, SLICE_BIND_ANR);
457 try {
458 action = onCreatePermissionRequest(sliceUri);
459 } finally {
460 Handler.getMain().removeCallbacks(mAnr);
461 }
Mady Mellor33c5a842018-03-19 16:23:15 -0700462 Slice.Builder parent = new Slice.Builder(sliceUri);
463 Slice.Builder childAction = new Slice.Builder(parent)
464 .addHints(Arrays.asList(Slice.HINT_TITLE, Slice.HINT_SHORTCUT))
465 .addAction(action, new Slice.Builder(parent).build(), null);
466
467 parent.addSubSlice(new Slice.Builder(sliceUri.buildUpon().appendPath("permission").build())
468 .addText(getPermissionString(context, callingPackage), null,
469 Collections.emptyList())
470 .addSubSlice(childAction.build(), null)
471 .build(), null);
472 return parent.addHints(Arrays.asList(Slice.HINT_PERMISSION_REQUEST)).build();
Jason Monke8f8be72018-01-21 10:10:35 -0500473 }
474
475 /**
476 * @hide
477 */
478 public static PendingIntent createPermissionIntent(Context context, Uri sliceUri,
479 String callingPackage) {
480 Intent intent = new Intent(SliceManager.ACTION_REQUEST_SLICE_PERMISSION);
481 intent.setComponent(new ComponentName("com.android.systemui",
482 "com.android.systemui.SlicePermissionActivity"));
483 intent.putExtra(EXTRA_BIND_URI, sliceUri);
484 intent.putExtra(EXTRA_PKG, callingPackage);
485 intent.putExtra(EXTRA_PROVIDER_PKG, context.getPackageName());
486 // Unique pending intent.
487 intent.setData(sliceUri.buildUpon().appendQueryParameter("package", callingPackage)
488 .build());
489
490 return PendingIntent.getActivity(context, 0, intent, 0);
491 }
492
493 /**
494 * @hide
495 */
496 public static CharSequence getPermissionString(Context context, String callingPackage) {
497 PackageManager pm = context.getPackageManager();
498 try {
499 return context.getString(
500 com.android.internal.R.string.slices_permission_request,
501 pm.getApplicationInfo(callingPackage, 0).loadLabel(pm),
502 context.getApplicationInfo().loadLabel(pm));
503 } catch (NameNotFoundException e) {
504 // This shouldn't be possible since the caller is verified.
505 throw new RuntimeException("Unknown calling app", e);
506 }
507 }
508
Jason Monk66cffd52018-03-12 16:42:48 -0400509 private Slice onBindSliceStrict(Uri sliceUri, List<SliceSpec> supportedSpecs) {
Lucas Dupine0653fa2017-10-23 14:31:45 -0700510 ThreadPolicy oldPolicy = StrictMode.getThreadPolicy();
Jason Monkd9edfa942017-09-25 12:38:53 -0400511 try {
Lucas Dupine0653fa2017-10-23 14:31:45 -0700512 StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
513 .detectAll()
514 .penaltyDeath()
515 .build());
Jason Monk2af19982017-11-07 19:38:27 -0500516 return onBindSlice(sliceUri, supportedSpecs);
Lucas Dupine0653fa2017-10-23 14:31:45 -0700517 } finally {
518 StrictMode.setThreadPolicy(oldPolicy);
Jason Monkd9edfa942017-09-25 12:38:53 -0400519 }
520 }
Jason Monk66cffd52018-03-12 16:42:48 -0400521
522 private final Runnable mAnr = () -> {
523 Process.sendSignal(Process.myPid(), Process.SIGNAL_QUIT);
524 Log.wtf(TAG, "Timed out while handling slice callback " + mCallback);
525 };
Jason Monkd9edfa942017-09-25 12:38:53 -0400526}