Jason Monk | d9edfa94 | 2017-09-25 12:38:53 -0400 | [diff] [blame] | 1 | /* |
| 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 | |
Jason Monk | d18651f | 2017-10-05 14:18:49 -0400 | [diff] [blame] | 17 | package android.app.slice; |
Jason Monk | d9edfa94 | 2017-09-25 12:38:53 -0400 | [diff] [blame] | 18 | |
| 19 | import android.annotation.NonNull; |
Jason Monk | d18651f | 2017-10-05 14:18:49 -0400 | [diff] [blame] | 20 | import android.annotation.Nullable; |
Jason Monk | d9edfa94 | 2017-09-25 12:38:53 -0400 | [diff] [blame] | 21 | import android.annotation.StringDef; |
| 22 | import android.app.PendingIntent; |
| 23 | import android.app.RemoteInput; |
| 24 | import android.graphics.drawable.Icon; |
| 25 | import android.net.Uri; |
Jason Monk | d18651f | 2017-10-05 14:18:49 -0400 | [diff] [blame] | 26 | import android.os.Bundle; |
Jason Monk | d9edfa94 | 2017-09-25 12:38:53 -0400 | [diff] [blame] | 27 | import android.os.Parcel; |
| 28 | import android.os.Parcelable; |
Jason Monk | d9edfa94 | 2017-09-25 12:38:53 -0400 | [diff] [blame] | 29 | |
Mady Mellor | 4575aa5 | 2017-09-29 09:49:59 -0700 | [diff] [blame] | 30 | import com.android.internal.util.ArrayUtils; |
Jason Monk | 8938932 | 2018-05-15 21:13:16 -0400 | [diff] [blame] | 31 | import com.android.internal.util.Preconditions; |
Mady Mellor | 4575aa5 | 2017-09-29 09:49:59 -0700 | [diff] [blame] | 32 | |
Jeff Sharkey | 5db9a91 | 2017-12-08 17:32:32 -0700 | [diff] [blame] | 33 | import java.lang.annotation.Retention; |
| 34 | import java.lang.annotation.RetentionPolicy; |
Jason Monk | d9edfa94 | 2017-09-25 12:38:53 -0400 | [diff] [blame] | 35 | import java.util.ArrayList; |
| 36 | import java.util.Arrays; |
Jason Monk | d18651f | 2017-10-05 14:18:49 -0400 | [diff] [blame] | 37 | import java.util.List; |
Jason Monk | d054fb3 | 2017-11-07 21:52:10 -0500 | [diff] [blame] | 38 | import java.util.Objects; |
Jason Monk | d9edfa94 | 2017-09-25 12:38:53 -0400 | [diff] [blame] | 39 | |
| 40 | /** |
| 41 | * A slice is a piece of app content and actions that can be surfaced outside of the app. |
| 42 | * |
| 43 | * <p>They are constructed using {@link Builder} in a tree structure |
| 44 | * that provides the OS some information about how the content should be displayed. |
Jason Monk | d9edfa94 | 2017-09-25 12:38:53 -0400 | [diff] [blame] | 45 | */ |
| 46 | public final class Slice implements Parcelable { |
| 47 | |
| 48 | /** |
| 49 | * @hide |
| 50 | */ |
Jeff Sharkey | 5db9a91 | 2017-12-08 17:32:32 -0700 | [diff] [blame] | 51 | @StringDef(prefix = { "HINT_" }, value = { |
| 52 | HINT_TITLE, |
| 53 | HINT_LIST, |
| 54 | HINT_LIST_ITEM, |
| 55 | HINT_LARGE, |
| 56 | HINT_ACTIONS, |
| 57 | HINT_SELECTED, |
| 58 | HINT_NO_TINT, |
Mady Mellor | 225e0da | 2017-11-02 14:09:12 -0700 | [diff] [blame] | 59 | HINT_SHORTCUT, |
Jeff Sharkey | 5db9a91 | 2017-12-08 17:32:32 -0700 | [diff] [blame] | 60 | HINT_TOGGLE, |
| 61 | HINT_HORIZONTAL, |
| 62 | HINT_PARTIAL, |
Mady Mellor | 15e2c5d | 2018-03-01 16:46:56 -0800 | [diff] [blame] | 63 | HINT_SEE_MORE, |
Mady Mellor | 930f9a5 | 2018-03-16 09:30:28 -0700 | [diff] [blame] | 64 | HINT_KEYWORDS, |
Jason Monk | 106387f | 2018-03-06 16:32:28 -0500 | [diff] [blame] | 65 | HINT_ERROR, |
Mady Mellor | 930f9a5 | 2018-03-16 09:30:28 -0700 | [diff] [blame] | 66 | HINT_TTL, |
| 67 | HINT_LAST_UPDATED, |
Mady Mellor | 33c5a84 | 2018-03-19 16:23:15 -0700 | [diff] [blame] | 68 | HINT_PERMISSION_REQUEST, |
Jeff Sharkey | 5db9a91 | 2017-12-08 17:32:32 -0700 | [diff] [blame] | 69 | }) |
| 70 | @Retention(RetentionPolicy.SOURCE) |
| 71 | public @interface SliceHint {} |
Jason Monk | 106387f | 2018-03-06 16:32:28 -0500 | [diff] [blame] | 72 | /** |
| 73 | * @hide |
| 74 | */ |
| 75 | @StringDef(prefix = { "SUBTYPE_" }, value = { |
| 76 | SUBTYPE_COLOR, |
| 77 | SUBTYPE_CONTENT_DESCRIPTION, |
| 78 | SUBTYPE_MAX, |
| 79 | SUBTYPE_MESSAGE, |
| 80 | SUBTYPE_PRIORITY, |
| 81 | SUBTYPE_RANGE, |
| 82 | SUBTYPE_SOURCE, |
| 83 | SUBTYPE_TOGGLE, |
| 84 | SUBTYPE_VALUE, |
Mady Mellor | 209af08 | 2018-03-30 14:06:26 -0700 | [diff] [blame] | 85 | SUBTYPE_LAYOUT_DIRECTION, |
Jason Monk | 106387f | 2018-03-06 16:32:28 -0500 | [diff] [blame] | 86 | }) |
| 87 | @Retention(RetentionPolicy.SOURCE) |
| 88 | public @interface SliceSubtype {} |
Jason Monk | d9edfa94 | 2017-09-25 12:38:53 -0400 | [diff] [blame] | 89 | |
| 90 | /** |
Mady Mellor | b367fb7 | 2017-10-24 11:44:16 -0700 | [diff] [blame] | 91 | * Hint that this content is a title of other content in the slice. This can also indicate that |
| 92 | * the content should be used in the shortcut representation of the slice (icon, label, action), |
| 93 | * normally this should be indicated by adding the hint on the action containing that content. |
| 94 | * |
Jason Monk | d054fb3 | 2017-11-07 21:52:10 -0500 | [diff] [blame] | 95 | * @see SliceItem#FORMAT_ACTION |
Jason Monk | d9edfa94 | 2017-09-25 12:38:53 -0400 | [diff] [blame] | 96 | */ |
| 97 | public static final String HINT_TITLE = "title"; |
| 98 | /** |
| 99 | * Hint that all sub-items/sub-slices within this content should be considered |
| 100 | * to have {@link #HINT_LIST_ITEM}. |
| 101 | */ |
| 102 | public static final String HINT_LIST = "list"; |
| 103 | /** |
| 104 | * Hint that this item is part of a list and should be formatted as if is part |
| 105 | * of a list. |
| 106 | */ |
| 107 | public static final String HINT_LIST_ITEM = "list_item"; |
| 108 | /** |
| 109 | * Hint that this content is important and should be larger when displayed if |
| 110 | * possible. |
| 111 | */ |
| 112 | public static final String HINT_LARGE = "large"; |
| 113 | /** |
| 114 | * Hint that this slice contains a number of actions that can be grouped together |
| 115 | * in a sort of controls area of the UI. |
| 116 | */ |
| 117 | public static final String HINT_ACTIONS = "actions"; |
| 118 | /** |
| 119 | * Hint indicating that this item (and its sub-items) are the current selection. |
| 120 | */ |
| 121 | public static final String HINT_SELECTED = "selected"; |
| 122 | /** |
Jason Monk | d9edfa94 | 2017-09-25 12:38:53 -0400 | [diff] [blame] | 123 | * Hint to indicate that this content should not be tinted. |
| 124 | */ |
| 125 | public static final String HINT_NO_TINT = "no_tint"; |
Jason Monk | d18651f | 2017-10-05 14:18:49 -0400 | [diff] [blame] | 126 | /** |
Mady Mellor | 225e0da | 2017-11-02 14:09:12 -0700 | [diff] [blame] | 127 | * Hint to indicate that this content should only be displayed if the slice is presented |
| 128 | * as a shortcut. |
Mady Mellor | b367fb7 | 2017-10-24 11:44:16 -0700 | [diff] [blame] | 129 | */ |
Mady Mellor | 225e0da | 2017-11-02 14:09:12 -0700 | [diff] [blame] | 130 | public static final String HINT_SHORTCUT = "shortcut"; |
Mady Mellor | b367fb7 | 2017-10-24 11:44:16 -0700 | [diff] [blame] | 131 | /** |
Mady Mellor | 39bf435 | 2017-12-11 16:52:18 -0800 | [diff] [blame] | 132 | * Hint indicating this content should be shown instead of the normal content when the slice |
| 133 | * is in small format. |
| 134 | */ |
| 135 | public static final String HINT_SUMMARY = "summary"; |
| 136 | /** |
Mady Mellor | fc2b340 | 2017-11-08 14:15:43 -0800 | [diff] [blame] | 137 | * Hint to indicate that this content has a toggle action associated with it. To indicate that |
| 138 | * the toggle is on, use {@link #HINT_SELECTED}. When the toggle state changes, the intent |
| 139 | * associated with it will be sent along with an extra {@link #EXTRA_TOGGLE_STATE} which can be |
| 140 | * retrieved to see the new state of the toggle. |
| 141 | * @hide |
| 142 | */ |
| 143 | public static final String HINT_TOGGLE = "toggle"; |
| 144 | /** |
Jason Monk | d054fb3 | 2017-11-07 21:52:10 -0500 | [diff] [blame] | 145 | * Hint that list items within this slice or subslice would appear better |
| 146 | * if organized horizontally. |
| 147 | */ |
| 148 | public static final String HINT_HORIZONTAL = "horizontal"; |
| 149 | /** |
Jason Monk | d18651f | 2017-10-05 14:18:49 -0400 | [diff] [blame] | 150 | * Hint to indicate that this slice is incomplete and an update will be sent once |
| 151 | * loading is complete. Slices which contain HINT_PARTIAL will not be cached by the |
| 152 | * OS and should not be cached by apps. |
| 153 | */ |
| 154 | public static final String HINT_PARTIAL = "partial"; |
Jason Monk | 740a650 | 2017-12-10 13:49:59 -0500 | [diff] [blame] | 155 | /** |
Mady Mellor | fd1cbb8 | 2018-01-10 14:27:03 -0800 | [diff] [blame] | 156 | * A hint representing that this item should be used to indicate that there's more |
| 157 | * content associated with this slice. |
| 158 | */ |
| 159 | public static final String HINT_SEE_MORE = "see_more"; |
Mady Mellor | fc2b340 | 2017-11-08 14:15:43 -0800 | [diff] [blame] | 160 | /** |
Jason Monk | b8e5fa9 | 2018-03-06 17:50:20 -0500 | [diff] [blame] | 161 | * @see Builder#setCallerNeeded |
| 162 | * @hide |
Jason Monk | e8f8be7 | 2018-01-21 10:10:35 -0500 | [diff] [blame] | 163 | */ |
| 164 | public static final String HINT_CALLER_NEEDED = "caller_needed"; |
| 165 | /** |
Mady Mellor | 15e2c5d | 2018-03-01 16:46:56 -0800 | [diff] [blame] | 166 | * A hint to indicate that the contents of this subslice represent a list of keywords |
| 167 | * related to the parent slice. |
Jason Monk | 106387f | 2018-03-06 16:32:28 -0500 | [diff] [blame] | 168 | * Expected to be on an item of format {@link SliceItem#FORMAT_SLICE}. |
Mady Mellor | 15e2c5d | 2018-03-01 16:46:56 -0800 | [diff] [blame] | 169 | */ |
Mady Mellor | 930f9a5 | 2018-03-16 09:30:28 -0700 | [diff] [blame] | 170 | public static final String HINT_KEYWORDS = "keywords"; |
Mady Mellor | 15e2c5d | 2018-03-01 16:46:56 -0800 | [diff] [blame] | 171 | /** |
Jason Monk | 106387f | 2018-03-06 16:32:28 -0500 | [diff] [blame] | 172 | * A hint to indicate that this slice represents an error. |
| 173 | */ |
| 174 | public static final String HINT_ERROR = "error"; |
| 175 | /** |
Mady Mellor | 930f9a5 | 2018-03-16 09:30:28 -0700 | [diff] [blame] | 176 | * Hint indicating an item representing a time-to-live for the content. |
| 177 | */ |
| 178 | public static final String HINT_TTL = "ttl"; |
| 179 | /** |
| 180 | * Hint indicating an item representing when the content was created or last updated. |
| 181 | */ |
| 182 | public static final String HINT_LAST_UPDATED = "last_updated"; |
| 183 | /** |
Mady Mellor | 33c5a84 | 2018-03-19 16:23:15 -0700 | [diff] [blame] | 184 | * A hint to indicate that this slice represents a permission request for showing |
| 185 | * slices. |
| 186 | */ |
| 187 | public static final String HINT_PERMISSION_REQUEST = "permission_request"; |
| 188 | /** |
Mady Mellor | 209af08 | 2018-03-30 14:06:26 -0700 | [diff] [blame] | 189 | * Subtype to indicate that this item indicates the layout direction for content |
| 190 | * in the slice. |
| 191 | * Expected to be an item of format {@link SliceItem#FORMAT_INT}. |
| 192 | */ |
| 193 | public static final String SUBTYPE_LAYOUT_DIRECTION = "layout_direction"; |
| 194 | /** |
Mady Mellor | fc2b340 | 2017-11-08 14:15:43 -0800 | [diff] [blame] | 195 | * Key to retrieve an extra added to an intent when a control is changed. |
Mady Mellor | fc2b340 | 2017-11-08 14:15:43 -0800 | [diff] [blame] | 196 | */ |
| 197 | public static final String EXTRA_TOGGLE_STATE = "android.app.slice.extra.TOGGLE_STATE"; |
Jason Monk | d054fb3 | 2017-11-07 21:52:10 -0500 | [diff] [blame] | 198 | /** |
Amin Shaikh | a151170 | 2018-01-17 14:30:47 -0500 | [diff] [blame] | 199 | * Key to retrieve an extra added to an intent when the value of a slider is changed. |
Amin Shaikh | 60593c2 | 2018-01-30 10:35:59 -0500 | [diff] [blame] | 200 | * @deprecated remove once support lib is update to use EXTRA_RANGE_VALUE instead |
Jeff Sharkey | 3990ee1 | 2018-04-11 10:19:55 -0600 | [diff] [blame] | 201 | * @removed |
Amin Shaikh | a151170 | 2018-01-17 14:30:47 -0500 | [diff] [blame] | 202 | */ |
Amin Shaikh | 60593c2 | 2018-01-30 10:35:59 -0500 | [diff] [blame] | 203 | @Deprecated |
Amin Shaikh | a151170 | 2018-01-17 14:30:47 -0500 | [diff] [blame] | 204 | public static final String EXTRA_SLIDER_VALUE = "android.app.slice.extra.SLIDER_VALUE"; |
| 205 | /** |
Amin Shaikh | 60593c2 | 2018-01-30 10:35:59 -0500 | [diff] [blame] | 206 | * Key to retrieve an extra added to an intent when the value of an input range is changed. |
| 207 | */ |
| 208 | public static final String EXTRA_RANGE_VALUE = "android.app.slice.extra.RANGE_VALUE"; |
| 209 | /** |
Jason Monk | d054fb3 | 2017-11-07 21:52:10 -0500 | [diff] [blame] | 210 | * Subtype to indicate that this is a message as part of a communication |
| 211 | * sequence in this slice. |
Jason Monk | 106387f | 2018-03-06 16:32:28 -0500 | [diff] [blame] | 212 | * Expected to be on an item of format {@link SliceItem#FORMAT_SLICE}. |
Jason Monk | d054fb3 | 2017-11-07 21:52:10 -0500 | [diff] [blame] | 213 | */ |
| 214 | public static final String SUBTYPE_MESSAGE = "message"; |
| 215 | /** |
| 216 | * Subtype to tag the source (i.e. sender) of a {@link #SUBTYPE_MESSAGE}. |
Jason Monk | 106387f | 2018-03-06 16:32:28 -0500 | [diff] [blame] | 217 | * Expected to be on an item of format {@link SliceItem#FORMAT_TEXT}, |
| 218 | * {@link SliceItem#FORMAT_IMAGE} or an {@link SliceItem#FORMAT_SLICE} containing them. |
Jason Monk | d054fb3 | 2017-11-07 21:52:10 -0500 | [diff] [blame] | 219 | */ |
| 220 | public static final String SUBTYPE_SOURCE = "source"; |
Jason Monk | 740a650 | 2017-12-10 13:49:59 -0500 | [diff] [blame] | 221 | /** |
| 222 | * Subtype to tag an item as representing a color. |
Jason Monk | 106387f | 2018-03-06 16:32:28 -0500 | [diff] [blame] | 223 | * Expected to be on an item of format {@link SliceItem#FORMAT_INT}. |
Jason Monk | 740a650 | 2017-12-10 13:49:59 -0500 | [diff] [blame] | 224 | */ |
| 225 | public static final String SUBTYPE_COLOR = "color"; |
| 226 | /** |
Amin Shaikh | a151170 | 2018-01-17 14:30:47 -0500 | [diff] [blame] | 227 | * Subtype to tag an item as representing a slider. |
Amin Shaikh | 60593c2 | 2018-01-30 10:35:59 -0500 | [diff] [blame] | 228 | * @deprecated remove once support lib is update to use SUBTYPE_RANGE instead |
Jeff Sharkey | 3990ee1 | 2018-04-11 10:19:55 -0600 | [diff] [blame] | 229 | * @removed |
Jason Monk | 740a650 | 2017-12-10 13:49:59 -0500 | [diff] [blame] | 230 | */ |
Amin Shaikh | 60593c2 | 2018-01-30 10:35:59 -0500 | [diff] [blame] | 231 | @Deprecated |
Jason Monk | 740a650 | 2017-12-10 13:49:59 -0500 | [diff] [blame] | 232 | public static final String SUBTYPE_SLIDER = "slider"; |
Mady Mellor | 79e7ce3 | 2017-11-27 18:25:32 -0800 | [diff] [blame] | 233 | /** |
Amin Shaikh | 60593c2 | 2018-01-30 10:35:59 -0500 | [diff] [blame] | 234 | * Subtype to tag an item as representing a range. |
Jason Monk | 106387f | 2018-03-06 16:32:28 -0500 | [diff] [blame] | 235 | * Expected to be on an item of format {@link SliceItem#FORMAT_SLICE} containing |
| 236 | * a {@link #SUBTYPE_VALUE} and possibly a {@link #SUBTYPE_MAX}. |
Amin Shaikh | 60593c2 | 2018-01-30 10:35:59 -0500 | [diff] [blame] | 237 | */ |
| 238 | public static final String SUBTYPE_RANGE = "range"; |
| 239 | /** |
| 240 | * Subtype to tag an item as representing the max int value for a {@link #SUBTYPE_RANGE}. |
Jason Monk | 106387f | 2018-03-06 16:32:28 -0500 | [diff] [blame] | 241 | * Expected to be on an item of format {@link SliceItem#FORMAT_INT}. |
Amin Shaikh | a151170 | 2018-01-17 14:30:47 -0500 | [diff] [blame] | 242 | */ |
| 243 | public static final String SUBTYPE_MAX = "max"; |
| 244 | /** |
Amin Shaikh | 60593c2 | 2018-01-30 10:35:59 -0500 | [diff] [blame] | 245 | * Subtype to tag an item as representing the current int value for a {@link #SUBTYPE_RANGE}. |
Jason Monk | 106387f | 2018-03-06 16:32:28 -0500 | [diff] [blame] | 246 | * Expected to be on an item of format {@link SliceItem#FORMAT_INT}. |
Amin Shaikh | a151170 | 2018-01-17 14:30:47 -0500 | [diff] [blame] | 247 | */ |
| 248 | public static final String SUBTYPE_VALUE = "value"; |
| 249 | /** |
Mady Mellor | 79e7ce3 | 2017-11-27 18:25:32 -0800 | [diff] [blame] | 250 | * Subtype to indicate that this content has a toggle action associated with it. To indicate |
| 251 | * that the toggle is on, use {@link #HINT_SELECTED}. When the toggle state changes, the |
| 252 | * intent associated with it will be sent along with an extra {@link #EXTRA_TOGGLE_STATE} |
| 253 | * which can be retrieved to see the new state of the toggle. |
| 254 | */ |
| 255 | public static final String SUBTYPE_TOGGLE = "toggle"; |
Mady Mellor | ca8e884 | 2017-12-20 09:57:53 -0800 | [diff] [blame] | 256 | /** |
| 257 | * Subtype to tag an item representing priority. |
Jason Monk | 106387f | 2018-03-06 16:32:28 -0500 | [diff] [blame] | 258 | * Expected to be on an item of format {@link SliceItem#FORMAT_INT}. |
Mady Mellor | ca8e884 | 2017-12-20 09:57:53 -0800 | [diff] [blame] | 259 | */ |
| 260 | public static final String SUBTYPE_PRIORITY = "priority"; |
Mady Mellor | 0c99ecc | 2017-12-20 10:01:40 -0800 | [diff] [blame] | 261 | /** |
| 262 | * Subtype to tag an item to use as a content description. |
Jason Monk | 106387f | 2018-03-06 16:32:28 -0500 | [diff] [blame] | 263 | * Expected to be on an item of format {@link SliceItem#FORMAT_TEXT}. |
Mady Mellor | 0c99ecc | 2017-12-20 10:01:40 -0800 | [diff] [blame] | 264 | */ |
| 265 | public static final String SUBTYPE_CONTENT_DESCRIPTION = "content_description"; |
Mady Mellor | 930f9a5 | 2018-03-16 09:30:28 -0700 | [diff] [blame] | 266 | /** |
| 267 | * Subtype to tag an item as representing a time in milliseconds since midnight, |
| 268 | * January 1, 1970 UTC. |
| 269 | */ |
| 270 | public static final String SUBTYPE_MILLIS = "millis"; |
Jason Monk | d9edfa94 | 2017-09-25 12:38:53 -0400 | [diff] [blame] | 271 | |
| 272 | private final SliceItem[] mItems; |
| 273 | private final @SliceHint String[] mHints; |
Jason Monk | 2af1998 | 2017-11-07 19:38:27 -0500 | [diff] [blame] | 274 | private SliceSpec mSpec; |
Jason Monk | d9edfa94 | 2017-09-25 12:38:53 -0400 | [diff] [blame] | 275 | private Uri mUri; |
| 276 | |
Jason Monk | 2af1998 | 2017-11-07 19:38:27 -0500 | [diff] [blame] | 277 | Slice(ArrayList<SliceItem> items, @SliceHint String[] hints, Uri uri, SliceSpec spec) { |
Jason Monk | d9edfa94 | 2017-09-25 12:38:53 -0400 | [diff] [blame] | 278 | mHints = hints; |
| 279 | mItems = items.toArray(new SliceItem[items.size()]); |
| 280 | mUri = uri; |
Jason Monk | 2af1998 | 2017-11-07 19:38:27 -0500 | [diff] [blame] | 281 | mSpec = spec; |
Jason Monk | d9edfa94 | 2017-09-25 12:38:53 -0400 | [diff] [blame] | 282 | } |
| 283 | |
| 284 | protected Slice(Parcel in) { |
| 285 | mHints = in.readStringArray(); |
| 286 | int n = in.readInt(); |
| 287 | mItems = new SliceItem[n]; |
| 288 | for (int i = 0; i < n; i++) { |
| 289 | mItems[i] = SliceItem.CREATOR.createFromParcel(in); |
| 290 | } |
| 291 | mUri = Uri.CREATOR.createFromParcel(in); |
Jason Monk | 2af1998 | 2017-11-07 19:38:27 -0500 | [diff] [blame] | 292 | mSpec = in.readTypedObject(SliceSpec.CREATOR); |
| 293 | } |
| 294 | |
| 295 | /** |
| 296 | * @return The spec for this slice |
| 297 | */ |
| 298 | public @Nullable SliceSpec getSpec() { |
| 299 | return mSpec; |
Jason Monk | d9edfa94 | 2017-09-25 12:38:53 -0400 | [diff] [blame] | 300 | } |
| 301 | |
| 302 | /** |
Mady Mellor | 4575aa5 | 2017-09-29 09:49:59 -0700 | [diff] [blame] | 303 | * @return The Uri that this Slice represents. |
Jason Monk | d9edfa94 | 2017-09-25 12:38:53 -0400 | [diff] [blame] | 304 | */ |
| 305 | public Uri getUri() { |
| 306 | return mUri; |
| 307 | } |
| 308 | |
| 309 | /** |
| 310 | * @return All child {@link SliceItem}s that this Slice contains. |
| 311 | */ |
Jason Monk | d18651f | 2017-10-05 14:18:49 -0400 | [diff] [blame] | 312 | public List<SliceItem> getItems() { |
| 313 | return Arrays.asList(mItems); |
Jason Monk | d9edfa94 | 2017-09-25 12:38:53 -0400 | [diff] [blame] | 314 | } |
| 315 | |
| 316 | /** |
| 317 | * @return All hints associated with this Slice. |
| 318 | */ |
Jason Monk | d18651f | 2017-10-05 14:18:49 -0400 | [diff] [blame] | 319 | public @SliceHint List<String> getHints() { |
| 320 | return Arrays.asList(mHints); |
Jason Monk | d9edfa94 | 2017-09-25 12:38:53 -0400 | [diff] [blame] | 321 | } |
| 322 | |
Jason Monk | d9edfa94 | 2017-09-25 12:38:53 -0400 | [diff] [blame] | 323 | @Override |
| 324 | public void writeToParcel(Parcel dest, int flags) { |
| 325 | dest.writeStringArray(mHints); |
| 326 | dest.writeInt(mItems.length); |
| 327 | for (int i = 0; i < mItems.length; i++) { |
| 328 | mItems[i].writeToParcel(dest, flags); |
| 329 | } |
| 330 | mUri.writeToParcel(dest, 0); |
Jason Monk | 2af1998 | 2017-11-07 19:38:27 -0500 | [diff] [blame] | 331 | dest.writeTypedObject(mSpec, flags); |
Jason Monk | d9edfa94 | 2017-09-25 12:38:53 -0400 | [diff] [blame] | 332 | } |
| 333 | |
| 334 | @Override |
| 335 | public int describeContents() { |
| 336 | return 0; |
| 337 | } |
| 338 | |
| 339 | /** |
Mady Mellor | 4575aa5 | 2017-09-29 09:49:59 -0700 | [diff] [blame] | 340 | * @hide |
| 341 | */ |
| 342 | public boolean hasHint(@SliceHint String hint) { |
| 343 | return ArrayUtils.contains(mHints, hint); |
| 344 | } |
| 345 | |
| 346 | /** |
Jason Monk | b8e5fa9 | 2018-03-06 17:50:20 -0500 | [diff] [blame] | 347 | * Returns whether the caller for this slice matters. |
| 348 | * @see Builder#setCallerNeeded |
| 349 | */ |
| 350 | public boolean isCallerNeeded() { |
| 351 | return hasHint(HINT_CALLER_NEEDED); |
| 352 | } |
| 353 | |
| 354 | /** |
Jason Monk | d9edfa94 | 2017-09-25 12:38:53 -0400 | [diff] [blame] | 355 | * A Builder used to construct {@link Slice}s |
| 356 | */ |
| 357 | public static class Builder { |
| 358 | |
| 359 | private final Uri mUri; |
| 360 | private ArrayList<SliceItem> mItems = new ArrayList<>(); |
| 361 | private @SliceHint ArrayList<String> mHints = new ArrayList<>(); |
Jason Monk | 2af1998 | 2017-11-07 19:38:27 -0500 | [diff] [blame] | 362 | private SliceSpec mSpec; |
Jason Monk | d9edfa94 | 2017-09-25 12:38:53 -0400 | [diff] [blame] | 363 | |
| 364 | /** |
Jason Monk | 106387f | 2018-03-06 16:32:28 -0500 | [diff] [blame] | 365 | * @deprecated TO BE REMOVED |
Jeff Sharkey | 3990ee1 | 2018-04-11 10:19:55 -0600 | [diff] [blame] | 366 | * @removed |
Jason Monk | d9edfa94 | 2017-09-25 12:38:53 -0400 | [diff] [blame] | 367 | */ |
Jason Monk | 106387f | 2018-03-06 16:32:28 -0500 | [diff] [blame] | 368 | @Deprecated |
Jason Monk | d9edfa94 | 2017-09-25 12:38:53 -0400 | [diff] [blame] | 369 | public Builder(@NonNull Uri uri) { |
| 370 | mUri = uri; |
| 371 | } |
| 372 | |
| 373 | /** |
Jason Monk | 106387f | 2018-03-06 16:32:28 -0500 | [diff] [blame] | 374 | * Create a builder which will construct a {@link Slice} for the given Uri. |
| 375 | * @param uri Uri to tag for this slice. |
| 376 | * @param spec the spec for this slice. |
| 377 | */ |
| 378 | public Builder(@NonNull Uri uri, SliceSpec spec) { |
| 379 | mUri = uri; |
| 380 | mSpec = spec; |
| 381 | } |
| 382 | |
| 383 | /** |
Jason Monk | d9edfa94 | 2017-09-25 12:38:53 -0400 | [diff] [blame] | 384 | * Create a builder for a {@link Slice} that is a sub-slice of the slice |
| 385 | * being constructed by the provided builder. |
| 386 | * @param parent The builder constructing the parent slice |
| 387 | */ |
| 388 | public Builder(@NonNull Slice.Builder parent) { |
| 389 | mUri = parent.mUri.buildUpon().appendPath("_gen") |
| 390 | .appendPath(String.valueOf(mItems.size())).build(); |
| 391 | } |
| 392 | |
| 393 | /** |
Jason Monk | b8e5fa9 | 2018-03-06 17:50:20 -0500 | [diff] [blame] | 394 | * Tells the system whether for this slice the return value of |
Jeff Sharkey | 3990ee1 | 2018-04-11 10:19:55 -0600 | [diff] [blame] | 395 | * {@link SliceProvider#onBindSlice(Uri, java.util.Set)} may be different depending on |
Jason Monk | b8e5fa9 | 2018-03-06 17:50:20 -0500 | [diff] [blame] | 396 | * {@link SliceProvider#getCallingPackage()} and should not be cached for multiple |
| 397 | * apps. |
| 398 | */ |
| 399 | public Builder setCallerNeeded(boolean callerNeeded) { |
| 400 | if (callerNeeded) { |
| 401 | mHints.add(HINT_CALLER_NEEDED); |
| 402 | } else { |
| 403 | mHints.remove(HINT_CALLER_NEEDED); |
| 404 | } |
| 405 | return this; |
| 406 | } |
| 407 | |
| 408 | /** |
Jason Monk | d9edfa94 | 2017-09-25 12:38:53 -0400 | [diff] [blame] | 409 | * Add hints to the Slice being constructed |
| 410 | */ |
Jason Monk | 106387f | 2018-03-06 16:32:28 -0500 | [diff] [blame] | 411 | public Builder addHints(@SliceHint List<String> hints) { |
| 412 | mHints.addAll(hints); |
Jason Monk | d9edfa94 | 2017-09-25 12:38:53 -0400 | [diff] [blame] | 413 | return this; |
| 414 | } |
| 415 | |
| 416 | /** |
Jason Monk | 106387f | 2018-03-06 16:32:28 -0500 | [diff] [blame] | 417 | * @deprecated TO BE REMOVED |
Jeff Sharkey | 3990ee1 | 2018-04-11 10:19:55 -0600 | [diff] [blame] | 418 | * @removed |
Jason Monk | 2af1998 | 2017-11-07 19:38:27 -0500 | [diff] [blame] | 419 | */ |
| 420 | public Builder setSpec(SliceSpec spec) { |
| 421 | mSpec = spec; |
| 422 | return this; |
| 423 | } |
| 424 | |
| 425 | /** |
Jason Monk | d9edfa94 | 2017-09-25 12:38:53 -0400 | [diff] [blame] | 426 | * Add a sub-slice to the slice being constructed |
Jason Monk | d054fb3 | 2017-11-07 21:52:10 -0500 | [diff] [blame] | 427 | * @param subType Optional template-specific type information |
Andrew Solovay | 6eaf48ea | 2018-12-12 15:38:06 -0800 | [diff] [blame] | 428 | * @see SliceItem#getSubType() |
Jason Monk | d054fb3 | 2017-11-07 21:52:10 -0500 | [diff] [blame] | 429 | */ |
Jason Monk | 106387f | 2018-03-06 16:32:28 -0500 | [diff] [blame] | 430 | public Builder addSubSlice(@NonNull Slice slice, @Nullable @SliceSubtype String subType) { |
Jason Monk | 8938932 | 2018-05-15 21:13:16 -0400 | [diff] [blame] | 431 | Preconditions.checkNotNull(slice); |
Jason Monk | d054fb3 | 2017-11-07 21:52:10 -0500 | [diff] [blame] | 432 | mItems.add(new SliceItem(slice, SliceItem.FORMAT_SLICE, subType, |
| 433 | slice.getHints().toArray(new String[slice.getHints().size()]))); |
Jason Monk | d9edfa94 | 2017-09-25 12:38:53 -0400 | [diff] [blame] | 434 | return this; |
| 435 | } |
| 436 | |
| 437 | /** |
| 438 | * Add an action to the slice being constructed |
Jason Monk | d054fb3 | 2017-11-07 21:52:10 -0500 | [diff] [blame] | 439 | * @param subType Optional template-specific type information |
Andrew Solovay | 6eaf48ea | 2018-12-12 15:38:06 -0800 | [diff] [blame] | 440 | * @see SliceItem#getSubType() |
Jason Monk | d054fb3 | 2017-11-07 21:52:10 -0500 | [diff] [blame] | 441 | */ |
| 442 | public Slice.Builder addAction(@NonNull PendingIntent action, @NonNull Slice s, |
Jason Monk | 106387f | 2018-03-06 16:32:28 -0500 | [diff] [blame] | 443 | @Nullable @SliceSubtype String subType) { |
Jason Monk | 8938932 | 2018-05-15 21:13:16 -0400 | [diff] [blame] | 444 | Preconditions.checkNotNull(action); |
| 445 | Preconditions.checkNotNull(s); |
Jason Monk | 2af1998 | 2017-11-07 19:38:27 -0500 | [diff] [blame] | 446 | List<String> hints = s.getHints(); |
| 447 | s.mSpec = null; |
Jason Monk | d054fb3 | 2017-11-07 21:52:10 -0500 | [diff] [blame] | 448 | mItems.add(new SliceItem(action, s, SliceItem.FORMAT_ACTION, subType, hints.toArray( |
Jason Monk | 2af1998 | 2017-11-07 19:38:27 -0500 | [diff] [blame] | 449 | new String[hints.size()]))); |
Jason Monk | d9edfa94 | 2017-09-25 12:38:53 -0400 | [diff] [blame] | 450 | return this; |
| 451 | } |
| 452 | |
| 453 | /** |
| 454 | * Add text to the slice being constructed |
Jason Monk | d054fb3 | 2017-11-07 21:52:10 -0500 | [diff] [blame] | 455 | * @param subType Optional template-specific type information |
Andrew Solovay | 6eaf48ea | 2018-12-12 15:38:06 -0800 | [diff] [blame] | 456 | * @see SliceItem#getSubType() |
Jason Monk | d9edfa94 | 2017-09-25 12:38:53 -0400 | [diff] [blame] | 457 | */ |
Jason Monk | 106387f | 2018-03-06 16:32:28 -0500 | [diff] [blame] | 458 | public Builder addText(CharSequence text, @Nullable @SliceSubtype String subType, |
| 459 | @SliceHint List<String> hints) { |
Jason Monk | d054fb3 | 2017-11-07 21:52:10 -0500 | [diff] [blame] | 460 | mItems.add(new SliceItem(text, SliceItem.FORMAT_TEXT, subType, hints)); |
Jason Monk | d9edfa94 | 2017-09-25 12:38:53 -0400 | [diff] [blame] | 461 | return this; |
| 462 | } |
| 463 | |
| 464 | /** |
Jason Monk | d054fb3 | 2017-11-07 21:52:10 -0500 | [diff] [blame] | 465 | * Add an image to the slice being constructed |
| 466 | * @param subType Optional template-specific type information |
Andrew Solovay | 6eaf48ea | 2018-12-12 15:38:06 -0800 | [diff] [blame] | 467 | * @see SliceItem#getSubType() |
Jason Monk | d054fb3 | 2017-11-07 21:52:10 -0500 | [diff] [blame] | 468 | */ |
Jason Monk | 106387f | 2018-03-06 16:32:28 -0500 | [diff] [blame] | 469 | public Builder addIcon(Icon icon, @Nullable @SliceSubtype String subType, |
| 470 | @SliceHint List<String> hints) { |
Jason Monk | 8938932 | 2018-05-15 21:13:16 -0400 | [diff] [blame] | 471 | Preconditions.checkNotNull(icon); |
Jason Monk | d054fb3 | 2017-11-07 21:52:10 -0500 | [diff] [blame] | 472 | mItems.add(new SliceItem(icon, SliceItem.FORMAT_IMAGE, subType, hints)); |
| 473 | return this; |
| 474 | } |
| 475 | |
| 476 | /** |
Jason Monk | d18651f | 2017-10-05 14:18:49 -0400 | [diff] [blame] | 477 | * Add remote input to the slice being constructed |
Jason Monk | d054fb3 | 2017-11-07 21:52:10 -0500 | [diff] [blame] | 478 | * @param subType Optional template-specific type information |
Andrew Solovay | 6eaf48ea | 2018-12-12 15:38:06 -0800 | [diff] [blame] | 479 | * @see SliceItem#getSubType() |
Jason Monk | d18651f | 2017-10-05 14:18:49 -0400 | [diff] [blame] | 480 | */ |
Jason Monk | 106387f | 2018-03-06 16:32:28 -0500 | [diff] [blame] | 481 | public Slice.Builder addRemoteInput(RemoteInput remoteInput, |
| 482 | @Nullable @SliceSubtype String subType, |
Jason Monk | d054fb3 | 2017-11-07 21:52:10 -0500 | [diff] [blame] | 483 | @SliceHint List<String> hints) { |
Jason Monk | 8938932 | 2018-05-15 21:13:16 -0400 | [diff] [blame] | 484 | Preconditions.checkNotNull(remoteInput); |
Jason Monk | d054fb3 | 2017-11-07 21:52:10 -0500 | [diff] [blame] | 485 | mItems.add(new SliceItem(remoteInput, SliceItem.FORMAT_REMOTE_INPUT, |
| 486 | subType, hints)); |
Jason Monk | d9edfa94 | 2017-09-25 12:38:53 -0400 | [diff] [blame] | 487 | return this; |
| 488 | } |
| 489 | |
| 490 | /** |
Amin Shaikh | 31062cb | 2018-02-16 15:13:25 -0500 | [diff] [blame] | 491 | * Add an integer to the slice being constructed |
Jason Monk | d054fb3 | 2017-11-07 21:52:10 -0500 | [diff] [blame] | 492 | * @param subType Optional template-specific type information |
Andrew Solovay | 6eaf48ea | 2018-12-12 15:38:06 -0800 | [diff] [blame] | 493 | * @see SliceItem#getSubType() |
Jason Monk | 740a650 | 2017-12-10 13:49:59 -0500 | [diff] [blame] | 494 | */ |
Jason Monk | 106387f | 2018-03-06 16:32:28 -0500 | [diff] [blame] | 495 | public Builder addInt(int value, @Nullable @SliceSubtype String subType, |
| 496 | @SliceHint List<String> hints) { |
Jason Monk | 740a650 | 2017-12-10 13:49:59 -0500 | [diff] [blame] | 497 | mItems.add(new SliceItem(value, SliceItem.FORMAT_INT, subType, hints)); |
Jason Monk | d9edfa94 | 2017-09-25 12:38:53 -0400 | [diff] [blame] | 498 | return this; |
| 499 | } |
| 500 | |
| 501 | /** |
Jason Monk | 106387f | 2018-03-06 16:32:28 -0500 | [diff] [blame] | 502 | * @deprecated TO BE REMOVED. |
Jeff Sharkey | 3990ee1 | 2018-04-11 10:19:55 -0600 | [diff] [blame] | 503 | * @removed |
Jason Monk | d18651f | 2017-10-05 14:18:49 -0400 | [diff] [blame] | 504 | */ |
Jason Monk | 106387f | 2018-03-06 16:32:28 -0500 | [diff] [blame] | 505 | @Deprecated |
| 506 | public Slice.Builder addTimestamp(long time, @Nullable @SliceSubtype String subType, |
Jason Monk | d054fb3 | 2017-11-07 21:52:10 -0500 | [diff] [blame] | 507 | @SliceHint List<String> hints) { |
Jason Monk | 106387f | 2018-03-06 16:32:28 -0500 | [diff] [blame] | 508 | return addLong(time, subType, hints); |
Jason Monk | d18651f | 2017-10-05 14:18:49 -0400 | [diff] [blame] | 509 | } |
| 510 | |
| 511 | /** |
Jason Monk | 106387f | 2018-03-06 16:32:28 -0500 | [diff] [blame] | 512 | * Add a long to the slice being constructed |
Jason Monk | d054fb3 | 2017-11-07 21:52:10 -0500 | [diff] [blame] | 513 | * @param subType Optional template-specific type information |
Andrew Solovay | 6eaf48ea | 2018-12-12 15:38:06 -0800 | [diff] [blame] | 514 | * @see SliceItem#getSubType() |
Jason Monk | d9edfa94 | 2017-09-25 12:38:53 -0400 | [diff] [blame] | 515 | */ |
Jason Monk | 106387f | 2018-03-06 16:32:28 -0500 | [diff] [blame] | 516 | public Slice.Builder addLong(long value, @Nullable @SliceSubtype String subType, |
| 517 | @SliceHint List<String> hints) { |
| 518 | mItems.add(new SliceItem(value, SliceItem.FORMAT_LONG, subType, |
| 519 | hints.toArray(new String[hints.size()]))); |
Jason Monk | d9edfa94 | 2017-09-25 12:38:53 -0400 | [diff] [blame] | 520 | return this; |
| 521 | } |
| 522 | |
| 523 | /** |
Jason Monk | fed72bf | 2017-12-08 18:19:32 -0500 | [diff] [blame] | 524 | * Add a bundle to the slice being constructed. |
| 525 | * <p>Expected to be used for support library extension, should not be used for general |
| 526 | * development |
| 527 | * @param subType Optional template-specific type information |
Andrew Solovay | 6eaf48ea | 2018-12-12 15:38:06 -0800 | [diff] [blame] | 528 | * @see SliceItem#getSubType() |
Jason Monk | fed72bf | 2017-12-08 18:19:32 -0500 | [diff] [blame] | 529 | */ |
Jason Monk | 106387f | 2018-03-06 16:32:28 -0500 | [diff] [blame] | 530 | public Slice.Builder addBundle(Bundle bundle, @Nullable @SliceSubtype String subType, |
| 531 | @SliceHint List<String> hints) { |
Jason Monk | 8938932 | 2018-05-15 21:13:16 -0400 | [diff] [blame] | 532 | Preconditions.checkNotNull(bundle); |
Jason Monk | fed72bf | 2017-12-08 18:19:32 -0500 | [diff] [blame] | 533 | mItems.add(new SliceItem(bundle, SliceItem.FORMAT_BUNDLE, subType, |
| 534 | hints)); |
| 535 | return this; |
| 536 | } |
| 537 | |
| 538 | /** |
Jason Monk | d9edfa94 | 2017-09-25 12:38:53 -0400 | [diff] [blame] | 539 | * Construct the slice. |
| 540 | */ |
| 541 | public Slice build() { |
Jason Monk | 2af1998 | 2017-11-07 19:38:27 -0500 | [diff] [blame] | 542 | return new Slice(mItems, mHints.toArray(new String[mHints.size()]), mUri, mSpec); |
Jason Monk | d9edfa94 | 2017-09-25 12:38:53 -0400 | [diff] [blame] | 543 | } |
| 544 | } |
| 545 | |
| 546 | public static final Creator<Slice> CREATOR = new Creator<Slice>() { |
| 547 | @Override |
| 548 | public Slice createFromParcel(Parcel in) { |
| 549 | return new Slice(in); |
| 550 | } |
| 551 | |
| 552 | @Override |
| 553 | public Slice[] newArray(int size) { |
| 554 | return new Slice[size]; |
| 555 | } |
| 556 | }; |
Mady Mellor | 4575aa5 | 2017-09-29 09:49:59 -0700 | [diff] [blame] | 557 | |
| 558 | /** |
| 559 | * @hide |
| 560 | * @return A string representation of this slice. |
| 561 | */ |
Jason Monk | d18651f | 2017-10-05 14:18:49 -0400 | [diff] [blame] | 562 | public String toString() { |
| 563 | return toString(""); |
Mady Mellor | 4575aa5 | 2017-09-29 09:49:59 -0700 | [diff] [blame] | 564 | } |
| 565 | |
Jason Monk | d18651f | 2017-10-05 14:18:49 -0400 | [diff] [blame] | 566 | private String toString(String indent) { |
Mady Mellor | 4575aa5 | 2017-09-29 09:49:59 -0700 | [diff] [blame] | 567 | StringBuilder sb = new StringBuilder(); |
| 568 | for (int i = 0; i < mItems.length; i++) { |
| 569 | sb.append(indent); |
Jason Monk | d054fb3 | 2017-11-07 21:52:10 -0500 | [diff] [blame] | 570 | if (Objects.equals(mItems[i].getFormat(), SliceItem.FORMAT_SLICE)) { |
Mady Mellor | 4575aa5 | 2017-09-29 09:49:59 -0700 | [diff] [blame] | 571 | sb.append("slice:\n"); |
Jason Monk | d18651f | 2017-10-05 14:18:49 -0400 | [diff] [blame] | 572 | sb.append(mItems[i].getSlice().toString(indent + " ")); |
Jason Monk | d054fb3 | 2017-11-07 21:52:10 -0500 | [diff] [blame] | 573 | } else if (Objects.equals(mItems[i].getFormat(), SliceItem.FORMAT_TEXT)) { |
Mady Mellor | 4575aa5 | 2017-09-29 09:49:59 -0700 | [diff] [blame] | 574 | sb.append("text: "); |
| 575 | sb.append(mItems[i].getText()); |
| 576 | sb.append("\n"); |
| 577 | } else { |
Jason Monk | d054fb3 | 2017-11-07 21:52:10 -0500 | [diff] [blame] | 578 | sb.append(mItems[i].getFormat()); |
Mady Mellor | 4575aa5 | 2017-09-29 09:49:59 -0700 | [diff] [blame] | 579 | sb.append("\n"); |
| 580 | } |
| 581 | } |
| 582 | return sb.toString(); |
| 583 | } |
Jason Monk | d9edfa94 | 2017-09-25 12:38:53 -0400 | [diff] [blame] | 584 | } |