1 /*
2  * Copyright (C) 2022 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 android.app.smartspace.uitemplatedata;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.annotation.SystemApi;
22 import android.app.smartspace.SmartspaceTarget;
23 import android.app.smartspace.SmartspaceUtils;
24 import android.os.Parcel;
25 import android.os.Parcelable;
26 
27 import java.util.List;
28 import java.util.Objects;
29 
30 /**
31  * Holds all the relevant data needed to render a Smartspace card with the carousel Ui Template.
32  *
33  * This template will add a sub-card displaying a list of carousel items within the default-template
34  * card:
35  * <ul>
36  *     <li> carouselItem1, carouselItem2, carouselItem3... </li>
37  * </ul>
38  *
39  * @hide
40  */
41 @SystemApi
42 public final class CarouselTemplateData extends BaseTemplateData {
43 
44     /** Lists of {@link CarouselItem}. */
45     @NonNull
46     private final List<CarouselItem> mCarouselItems;
47 
48     /** Tap action for the entire carousel secondary card, including the blank space */
49     @Nullable
50     private final TapAction mCarouselAction;
51 
CarouselTemplateData(@onNull Parcel in)52     CarouselTemplateData(@NonNull Parcel in) {
53         super(in);
54         mCarouselItems = in.createTypedArrayList(CarouselItem.CREATOR);
55         mCarouselAction = in.readTypedObject(TapAction.CREATOR);
56     }
57 
CarouselTemplateData(@martspaceTarget.UiTemplateType int templateType, @Nullable SubItemInfo primaryItem, @Nullable SubItemInfo subtitleItem, @Nullable SubItemInfo subtitleSupplementalItem, @Nullable SubItemInfo supplementalLineItem, @Nullable SubItemInfo supplementalAlarmItem, int layoutWeight, @NonNull List<CarouselItem> carouselItems, @Nullable TapAction carouselAction)58     private CarouselTemplateData(@SmartspaceTarget.UiTemplateType int templateType,
59             @Nullable SubItemInfo primaryItem,
60             @Nullable SubItemInfo subtitleItem,
61             @Nullable SubItemInfo subtitleSupplementalItem,
62             @Nullable SubItemInfo supplementalLineItem,
63             @Nullable SubItemInfo supplementalAlarmItem,
64             int layoutWeight,
65             @NonNull List<CarouselItem> carouselItems,
66             @Nullable TapAction carouselAction) {
67         super(templateType, primaryItem, subtitleItem, subtitleSupplementalItem,
68                 supplementalLineItem, supplementalAlarmItem, layoutWeight);
69 
70         mCarouselItems = carouselItems;
71         mCarouselAction = carouselAction;
72     }
73 
74     /** Returns the list of {@link CarouselItem}. Can be empty if not being set. */
75     @NonNull
getCarouselItems()76     public List<CarouselItem> getCarouselItems() {
77         return mCarouselItems;
78     }
79 
80     /** Returns the card's tap action. */
81     @Nullable
getCarouselAction()82     public TapAction getCarouselAction() {
83         return mCarouselAction;
84     }
85 
86     /**
87      * @see Parcelable.Creator
88      */
89     @NonNull
90     public static final Creator<CarouselTemplateData> CREATOR =
91             new Creator<CarouselTemplateData>() {
92                 @Override
93                 public CarouselTemplateData createFromParcel(Parcel in) {
94                     return new CarouselTemplateData(in);
95                 }
96 
97                 @Override
98                 public CarouselTemplateData[] newArray(int size) {
99                     return new CarouselTemplateData[size];
100                 }
101             };
102 
103     @Override
describeContents()104     public int describeContents() {
105         return 0;
106     }
107 
108     @Override
writeToParcel(@onNull Parcel out, int flags)109     public void writeToParcel(@NonNull Parcel out, int flags) {
110         super.writeToParcel(out, flags);
111         out.writeTypedList(mCarouselItems);
112         out.writeTypedObject(mCarouselAction, flags);
113     }
114 
115 
116     @Override
equals(Object o)117     public boolean equals(Object o) {
118         if (this == o) return true;
119         if (!(o instanceof CarouselTemplateData)) return false;
120         if (!super.equals(o)) return false;
121         CarouselTemplateData that = (CarouselTemplateData) o;
122         return mCarouselItems.equals(that.mCarouselItems) && Objects.equals(mCarouselAction,
123                 that.mCarouselAction);
124     }
125 
126     @Override
hashCode()127     public int hashCode() {
128         return Objects.hash(super.hashCode(), mCarouselItems, mCarouselAction);
129     }
130 
131     @Override
toString()132     public String toString() {
133         return super.toString() + " + SmartspaceCarouselUiTemplateData{"
134                 + "mCarouselItems=" + mCarouselItems
135                 + ", mCarouselActions=" + mCarouselAction
136                 + '}';
137     }
138 
139     /**
140      * A builder for {@link CarouselTemplateData} object.
141      *
142      * @hide
143      */
144     @SystemApi
145     public static final class Builder extends BaseTemplateData.Builder {
146 
147         private final List<CarouselItem> mCarouselItems;
148         private TapAction mCarouselAction;
149 
150         /**
151          * A builder for {@link CarouselTemplateData}.
152          */
Builder(@onNull List<CarouselItem> carouselItems)153         public Builder(@NonNull List<CarouselItem> carouselItems) {
154             super(SmartspaceTarget.UI_TEMPLATE_CAROUSEL);
155             mCarouselItems = Objects.requireNonNull(carouselItems);
156         }
157 
158         /**
159          * Sets the card tap action.
160          */
161         @NonNull
setCarouselAction(@onNull TapAction carouselAction)162         public Builder setCarouselAction(@NonNull TapAction carouselAction) {
163             mCarouselAction = carouselAction;
164             return this;
165         }
166 
167         /**
168          * Builds a new {@link CarouselTemplateData} instance.
169          *
170          * @throws IllegalStateException if the carousel data is invalid.
171          */
172         @NonNull
build()173         public CarouselTemplateData build() {
174             if (mCarouselItems.isEmpty()) {
175                 throw new IllegalStateException("Carousel data is empty");
176             }
177 
178             return new CarouselTemplateData(getTemplateType(), getPrimaryItem(),
179                     getSubtitleItem(), getSubtitleSupplemtnalItem(),
180                     getSupplementalLineItem(), getSupplementalAlarmItem(), getLayoutWeight(),
181                     mCarouselItems, mCarouselAction);
182         }
183     }
184 
185     /**
186      * Holds all the relevant data needed to render a carousel item.
187      *
188      * <ul>
189      *     <li> upper text </li>
190      *     <li> image </li>
191      *     <li> lower text </li>
192      * </ul>
193      */
194     public static final class CarouselItem implements Parcelable {
195 
196         /** Text which is above the image item. */
197         @Nullable
198         private final Text mUpperText;
199 
200         /** Image item. Can be empty. */
201         @Nullable
202         private final Icon mImage;
203 
204         /** Text which is under the image item. */
205         @Nullable
206         private final Text mLowerText;
207 
208         /**
209          * Tap action for this {@link CarouselItem} instance. {@code mCarouselAction} is used if not
210          * being set.
211          */
212         @Nullable
213         private final TapAction mTapAction;
214 
CarouselItem(@onNull Parcel in)215         CarouselItem(@NonNull Parcel in) {
216             mUpperText = in.readTypedObject(Text.CREATOR);
217             mImage = in.readTypedObject(Icon.CREATOR);
218             mLowerText = in.readTypedObject(Text.CREATOR);
219             mTapAction = in.readTypedObject(TapAction.CREATOR);
220         }
221 
CarouselItem(@ullable Text upperText, @Nullable Icon image, @Nullable Text lowerText, @Nullable TapAction tapAction)222         private CarouselItem(@Nullable Text upperText, @Nullable Icon image,
223                 @Nullable Text lowerText, @Nullable TapAction tapAction) {
224             mUpperText = upperText;
225             mImage = image;
226             mLowerText = lowerText;
227             mTapAction = tapAction;
228         }
229 
230         @Nullable
getUpperText()231         public Text getUpperText() {
232             return mUpperText;
233         }
234 
235         @Nullable
getImage()236         public Icon getImage() {
237             return mImage;
238         }
239 
240         @Nullable
getLowerText()241         public Text getLowerText() {
242             return mLowerText;
243         }
244 
245         @Nullable
getTapAction()246         public TapAction getTapAction() {
247             return mTapAction;
248         }
249 
250         /**
251          * @see Parcelable.Creator
252          */
253         @NonNull
254         public static final Creator<CarouselItem> CREATOR =
255                 new Creator<CarouselItem>() {
256                     @Override
257                     public CarouselItem createFromParcel(Parcel in) {
258                         return new CarouselItem(in);
259                     }
260 
261                     @Override
262                     public CarouselItem[] newArray(int size) {
263                         return new CarouselItem[size];
264                     }
265                 };
266 
267         @Override
describeContents()268         public int describeContents() {
269             return 0;
270         }
271 
272         @Override
writeToParcel(@onNull Parcel out, int flags)273         public void writeToParcel(@NonNull Parcel out, int flags) {
274             out.writeTypedObject(mUpperText, flags);
275             out.writeTypedObject(mImage, flags);
276             out.writeTypedObject(mLowerText, flags);
277             out.writeTypedObject(mTapAction, flags);
278         }
279 
280         @Override
equals(Object o)281         public boolean equals(Object o) {
282             if (this == o) return true;
283             if (!(o instanceof CarouselItem)) return false;
284             CarouselItem that = (CarouselItem) o;
285             return SmartspaceUtils.isEqual(mUpperText, that.mUpperText) && Objects.equals(
286                     mImage,
287                     that.mImage) && SmartspaceUtils.isEqual(mLowerText, that.mLowerText)
288                     && Objects.equals(mTapAction, that.mTapAction);
289         }
290 
291         @Override
hashCode()292         public int hashCode() {
293             return Objects.hash(mUpperText, mImage, mLowerText, mTapAction);
294         }
295 
296         @Override
toString()297         public String toString() {
298             return "CarouselItem{"
299                     + "mUpperText=" + mUpperText
300                     + ", mImage=" + mImage
301                     + ", mLowerText=" + mLowerText
302                     + ", mTapAction=" + mTapAction
303                     + '}';
304         }
305 
306         /**
307          * A builder for {@link CarouselItem} object.
308          *
309          * @hide
310          */
311         @SystemApi
312         public static final class Builder {
313 
314             private Text mUpperText;
315             private Icon mImage;
316             private Text mLowerText;
317             private TapAction mTapAction;
318 
319             /**
320              * Sets the upper text.
321              */
322             @NonNull
setUpperText(@ullable Text upperText)323             public Builder setUpperText(@Nullable Text upperText) {
324                 mUpperText = upperText;
325                 return this;
326             }
327 
328             /**
329              * Sets the image.
330              */
331             @NonNull
setImage(@ullable Icon image)332             public Builder setImage(@Nullable Icon image) {
333                 mImage = image;
334                 return this;
335             }
336 
337 
338             /**
339              * Sets the lower text.
340              */
341             @NonNull
setLowerText(@ullable Text lowerText)342             public Builder setLowerText(@Nullable Text lowerText) {
343                 mLowerText = lowerText;
344                 return this;
345             }
346 
347             /**
348              * Sets the tap action.
349              */
350             @NonNull
setTapAction(@ullable TapAction tapAction)351             public Builder setTapAction(@Nullable TapAction tapAction) {
352                 mTapAction = tapAction;
353                 return this;
354             }
355 
356             /**
357              * Builds a new CarouselItem instance.
358              *
359              * @throws IllegalStateException if all the rendering data is empty.
360              */
361             @NonNull
build()362             public CarouselItem build() {
363                 if (SmartspaceUtils.isEmpty(mUpperText) && mImage == null
364                         && SmartspaceUtils.isEmpty(
365                         mLowerText)) {
366                     throw new IllegalStateException("Carousel data is empty");
367                 }
368                 return new CarouselItem(mUpperText, mImage, mLowerText, mTapAction);
369             }
370         }
371     }
372 }
373