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 > 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