1 /*
2  * Copyright 2018 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 
17 package androidx.slice;
18 
19 import android.content.Context;
20 import android.content.Intent;
21 import android.content.pm.PackageManager;
22 import android.net.Uri;
23 
24 import androidx.annotation.NonNull;
25 import androidx.annotation.Nullable;
26 import androidx.annotation.RestrictTo;
27 import androidx.core.content.PermissionChecker;
28 import androidx.core.os.BuildCompat;
29 
30 import java.util.Collection;
31 import java.util.List;
32 import java.util.Set;
33 import java.util.concurrent.Executor;
34 
35 /**
36  * Class to handle interactions with {@link Slice}s.
37  * <p>
38  * The SliceManager manages permissions and pinned state for slices.
39  */
40 public abstract class SliceManager {
41 
42     /**
43      * Get a {@link SliceManager}.
44      */
45     @SuppressWarnings("NewApi")
getInstance(@onNull Context context)46     public static @NonNull SliceManager getInstance(@NonNull Context context) {
47         if (BuildCompat.isAtLeastP()) {
48             return new SliceManagerWrapper(context);
49         } else {
50             return new SliceManagerCompat(context);
51         }
52     }
53 
54     /**
55      * @hide
56      */
57     @RestrictTo(RestrictTo.Scope.LIBRARY)
SliceManager()58     SliceManager() {
59     }
60 
61     /**
62      * Adds a callback to a specific slice uri.
63      * <p>
64      * This is a convenience that performs a few slice actions at once. It will put
65      * the slice in a pinned state since there is a callback attached. It will also
66      * listen for content changes, when a content change observes, the android system
67      * will bind the new slice and provide it to all registered {@link SliceCallback}s.
68      *
69      * @param uri The uri of the slice being listened to.
70      * @param callback The listener that should receive the callbacks.
71      * @see SliceProvider#onSlicePinned(Uri)
72      */
registerSliceCallback(@onNull Uri uri, @NonNull SliceCallback callback)73     public abstract void registerSliceCallback(@NonNull Uri uri, @NonNull SliceCallback callback);
74 
75     /**
76      * Adds a callback to a specific slice uri.
77      * <p>
78      * This is a convenience that performs a few slice actions at once. It will put
79      * the slice in a pinned state since there is a callback attached. It will also
80      * listen for content changes, when a content change observes, the android system
81      * will bind the new slice and provide it to all registered {@link SliceCallback}s.
82      *
83      * @param uri The uri of the slice being listened to.
84      * @param callback The listener that should receive the callbacks.
85      * @see SliceProvider#onSlicePinned(Uri)
86      */
registerSliceCallback(@onNull Uri uri, @NonNull Executor executor, @NonNull SliceCallback callback)87     public abstract void registerSliceCallback(@NonNull Uri uri, @NonNull Executor executor,
88             @NonNull SliceCallback callback);
89 
90     /**
91      * Removes a callback for a specific slice uri.
92      * <p>
93      * Removes the app from the pinned state (if there are no other apps/callbacks pinning it)
94      * in addition to removing the callback.
95      *
96      * @param uri The uri of the slice being listened to
97      * @param callback The listener that should no longer receive callbacks.
98      * @see #registerSliceCallback
99      */
unregisterSliceCallback(@onNull Uri uri, @NonNull SliceCallback callback)100     public abstract void unregisterSliceCallback(@NonNull Uri uri, @NonNull SliceCallback callback);
101 
102     /**
103      * Ensures that a slice is in a pinned state.
104      * <p>
105      * Pinned state is not persisted across reboots, so apps are expected to re-pin any slices
106      * they still care about after a reboot.
107      *
108      * @param uri The uri of the slice being pinned.
109      * @see SliceProvider#onSlicePinned(Uri)
110      */
pinSlice(@onNull Uri uri)111     public abstract void pinSlice(@NonNull Uri uri);
112 
113     /**
114      * Remove a pin for a slice.
115      * <p>
116      * If the slice has no other pins/callbacks then the slice will be unpinned.
117      *
118      * @param uri The uri of the slice being unpinned.
119      * @see #pinSlice
120      * @see SliceProvider#onSliceUnpinned(Uri)
121      */
unpinSlice(@onNull Uri uri)122     public abstract void unpinSlice(@NonNull Uri uri);
123 
124     /**
125      * Get the current set of specs for a pinned slice.
126      * <p>
127      * This is the set of specs supported for a specific pinned slice. It will take
128      * into account all clients and returns only specs supported by all.
129      * @see SliceSpec
130      */
getPinnedSpecs(@onNull Uri uri)131     public abstract @NonNull Set<SliceSpec> getPinnedSpecs(@NonNull Uri uri);
132 
133     /**
134      * Turns a slice Uri into slice content.
135      *
136      * @param uri The URI to a slice provider
137      * @return The Slice provided by the app or null if none is given.
138      * @see Slice
139      */
bindSlice(@onNull Uri uri)140     public abstract @Nullable Slice bindSlice(@NonNull Uri uri);
141 
142     /**
143      * Turns a slice intent into slice content. Is a shortcut to perform the action
144      * of both {@link #mapIntentToUri(Intent)} and {@link #bindSlice(Uri)} at once.
145      *
146      * @param intent The intent associated with a slice.
147      * @return The Slice provided by the app or null if none is given.
148      * @see Slice
149      * @see androidx.slice.SliceProvider#onMapIntentToUri(Intent)
150      * @see Intent
151      */
bindSlice(@onNull Intent intent)152     public abstract @Nullable Slice bindSlice(@NonNull Intent intent);
153 
154     /**
155      * Turns a slice intent into a slice uri. Expects an explicit intent.
156      * <p>
157      * This goes through a several stage resolution process to determine if any slice
158      * can represent this intent.
159      * <ol>
160      *  <li> If the intent contains data that {@link android.content.ContentResolver#getType} is
161      *  {@link android.app.slice.SliceProvider#SLICE_TYPE} then the data will be returned.</li>
162      *  <li>If the intent explicitly points at an activity, and that activity has
163      *  meta-data for key {@link android.app.slice.SliceManager#SLICE_METADATA_KEY},
164      *  then the Uri specified there will be returned.</li>
165      *  <li>Lastly, if the intent with {@link android.app.slice.SliceManager#CATEGORY_SLICE} added
166      *  resolves to a provider, then the provider will be asked to
167      *  {@link SliceProvider#onMapIntentToUri} and that result will be returned.</li>
168      *  <li>If no slice is found, then {@code null} is returned.</li>
169      * </ol>
170      * @param intent The intent associated with a slice.
171      * @return The Slice Uri provided by the app or null if none exists.
172      * @see Slice
173      * @see SliceProvider#onMapIntentToUri(Intent)
174      * @see Intent
175      */
mapIntentToUri(@onNull Intent intent)176     public abstract @Nullable Uri mapIntentToUri(@NonNull Intent intent);
177 
178     /**
179      * Determine whether a particular process and user ID has been granted
180      * permission to access a specific slice URI.
181      *
182      * @param uri The uri that is being checked.
183      * @param pid The process ID being checked against.  Must be &gt; 0.
184      * @param uid The user ID being checked against.  A uid of 0 is the root
185      * user, which will pass every permission check.
186      *
187      * @return {@link PackageManager#PERMISSION_GRANTED} if the given
188      * pid/uid is allowed to access that uri, or
189      * {@link PackageManager#PERMISSION_DENIED} if it is not.
190      *
191      * @see #grantSlicePermission(String, Uri)
192      */
193     @PermissionChecker.PermissionResult
checkSlicePermission(@onNull Uri uri, int pid, int uid)194     public abstract int checkSlicePermission(@NonNull Uri uri, int pid, int uid);
195 
196     /**
197      * Grant permission to access a specific slice Uri to another package.
198      *
199      * @param toPackage The package you would like to allow to access the Uri.
200      * @param uri The Uri you would like to grant access to.
201      *
202      * @see #revokeSlicePermission
203      */
grantSlicePermission(@onNull String toPackage, @NonNull Uri uri)204     public abstract void grantSlicePermission(@NonNull String toPackage, @NonNull Uri uri);
205 
206     /**
207      * Remove permissions to access a particular content provider Uri
208      * that were previously added with {@link #grantSlicePermission} for a specific target
209      * package.  The given Uri will match all previously granted Uris that are the same or a
210      * sub-path of the given Uri.  That is, revoking "content://foo/target" will
211      * revoke both "content://foo/target" and "content://foo/target/sub", but not
212      * "content://foo".  It will not remove any prefix grants that exist at a
213      * higher level.
214      *
215      * @param toPackage The package you would like to allow to access the Uri.
216      * @param uri The Uri you would like to revoke access to.
217      *
218      * @see #grantSlicePermission
219      */
revokeSlicePermission(@onNull String toPackage, @NonNull Uri uri)220     public abstract void revokeSlicePermission(@NonNull String toPackage, @NonNull Uri uri);
221 
222     /**
223      * Obtains a list of slices that are descendants of the specified Uri.
224      * <p>
225      * Not all slice providers will implement this functionality, in which case,
226      * an empty collection will be returned.
227      *
228      * @param uri The uri to look for descendants under.
229      * @return All slices within the space.
230      * @see SliceProvider#onGetSliceDescendants(Uri)
231      */
getSliceDescendants(@onNull Uri uri)232     public abstract @NonNull Collection<Uri> getSliceDescendants(@NonNull Uri uri);
233 
234     /**
235      * Get the list of currently pinned slices for this app.
236      * @see SliceProvider#onSlicePinned
237      */
getPinnedSlices()238     public abstract @NonNull List<Uri> getPinnedSlices();
239 
240     /**
241      * Class that listens to changes in {@link Slice}s.
242      */
243     public interface SliceCallback {
244 
245         /**
246          * Called when slice is updated.
247          *
248          * @param s The updated slice.
249          * @see #registerSliceCallback
250          */
onSliceUpdated(@onNull Slice s)251         void onSliceUpdated(@NonNull Slice s);
252     }
253 }
254