1 /*
2  * Copyright (C) 2021 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 com.android.car.qc;
18 
19 import android.app.PendingIntent;
20 import android.graphics.drawable.Icon;
21 import android.os.Parcel;
22 
23 import androidx.annotation.NonNull;
24 import androidx.annotation.Nullable;
25 
26 import java.util.ArrayList;
27 import java.util.Collections;
28 import java.util.List;
29 
30 /**
31  * Quick Control Row Element
32  * ---------------------------------------
33  * |            | Title       |          |
34  * | StartItems | Subtitle    | EndItems |
35  * |            | ActionText  |          |
36  * |            | Sliders     |          |
37  * ---------------------------------------
38  */
39 public class QCRow extends QCItem {
40     private final String mTitle;
41     private final String mSubtitle;
42     private final String mActionText;
43     @QCCategory
44     private final int mCategory;
45     private final Icon mStartIcon;
46     private final boolean mIsStartIconTintable;
47     private final QCSlider mSlider;
48     private final List<QCActionItem> mStartItems;
49     private final List<QCActionItem> mEndItems;
50     private final PendingIntent mPrimaryAction;
51     private PendingIntent mDisabledClickAction;
QCRow(@ullable String title, @Nullable String subtitle, @Nullable String actionText, @QCCategory int category, boolean isEnabled, boolean isClickableWhileDisabled, @Nullable PendingIntent primaryAction, @Nullable PendingIntent disabledClickAction, @Nullable Icon startIcon, boolean isIconTintable, @Nullable QCSlider slider, @NonNull List<QCActionItem> startItems, @NonNull List<QCActionItem> endItems)52     public QCRow(@Nullable String title, @Nullable String subtitle,
53             @Nullable String actionText, @QCCategory int category,
54             boolean isEnabled, boolean isClickableWhileDisabled,
55             @Nullable PendingIntent primaryAction,
56             @Nullable PendingIntent disabledClickAction, @Nullable Icon startIcon,
57             boolean isIconTintable, @Nullable QCSlider slider,
58             @NonNull List<QCActionItem> startItems, @NonNull List<QCActionItem> endItems) {
59         super(QC_TYPE_ROW, isEnabled, isClickableWhileDisabled);
60         mTitle = title;
61         mSubtitle = subtitle;
62         mActionText = actionText;
63         mCategory = category;
64         mPrimaryAction = primaryAction;
65         mDisabledClickAction = disabledClickAction;
66         mStartIcon = startIcon;
67         mIsStartIconTintable = isIconTintable;
68         mSlider = slider;
69         mStartItems = Collections.unmodifiableList(startItems);
70         mEndItems = Collections.unmodifiableList(endItems);
71     }
72 
QCRow(@onNull Parcel in)73     public QCRow(@NonNull Parcel in) {
74         super(in);
75         mTitle = in.readString();
76         mSubtitle = in.readString();
77         mActionText = in.readString();
78         mCategory = in.readInt();
79         boolean hasIcon = in.readBoolean();
80         if (hasIcon) {
81             mStartIcon = Icon.CREATOR.createFromParcel(in);
82         } else {
83             mStartIcon = null;
84         }
85         mIsStartIconTintable = in.readBoolean();
86         boolean hasSlider = in.readBoolean();
87         if (hasSlider) {
88             mSlider = QCSlider.CREATOR.createFromParcel(in);
89         } else {
90             mSlider = null;
91         }
92         List<QCActionItem> startItems = new ArrayList<>();
93         int startItemCount = in.readInt();
94         for (int i = 0; i < startItemCount; i++) {
95             startItems.add(QCActionItem.CREATOR.createFromParcel(in));
96         }
97         mStartItems = Collections.unmodifiableList(startItems);
98         List<QCActionItem> endItems = new ArrayList<>();
99         int endItemCount = in.readInt();
100         for (int i = 0; i < endItemCount; i++) {
101             endItems.add(QCActionItem.CREATOR.createFromParcel(in));
102         }
103         mEndItems = Collections.unmodifiableList(endItems);
104         boolean hasPrimaryAction = in.readBoolean();
105         if (hasPrimaryAction) {
106             mPrimaryAction = PendingIntent.CREATOR.createFromParcel(in);
107         } else {
108             mPrimaryAction = null;
109         }
110         boolean hasDisabledClickAction = in.readBoolean();
111         if (hasDisabledClickAction) {
112             mDisabledClickAction = PendingIntent.CREATOR.createFromParcel(in);
113         } else {
114             mDisabledClickAction = null;
115         }
116     }
117 
118     @Override
writeToParcel(Parcel dest, int flags)119     public void writeToParcel(Parcel dest, int flags) {
120         super.writeToParcel(dest, flags);
121         dest.writeString(mTitle);
122         dest.writeString(mSubtitle);
123         dest.writeString(mActionText);
124         dest.writeInt(mCategory);
125         boolean hasStartIcon = mStartIcon != null;
126         dest.writeBoolean(hasStartIcon);
127         if (hasStartIcon) {
128             mStartIcon.writeToParcel(dest, flags);
129         }
130         dest.writeBoolean(mIsStartIconTintable);
131         boolean hasSlider = mSlider != null;
132         dest.writeBoolean(hasSlider);
133         if (hasSlider) {
134             mSlider.writeToParcel(dest, flags);
135         }
136         dest.writeInt(mStartItems.size());
137         for (QCActionItem startItem : mStartItems) {
138             startItem.writeToParcel(dest, flags);
139         }
140         dest.writeInt(mEndItems.size());
141         for (QCActionItem endItem : mEndItems) {
142             endItem.writeToParcel(dest, flags);
143         }
144         boolean hasPrimaryAction = mPrimaryAction != null;
145         dest.writeBoolean(hasPrimaryAction);
146         if (hasPrimaryAction) {
147             mPrimaryAction.writeToParcel(dest, flags);
148         }
149         boolean hasDisabledClickAction = mDisabledClickAction != null;
150         dest.writeBoolean(hasDisabledClickAction);
151         if (hasDisabledClickAction) {
152             mDisabledClickAction.writeToParcel(dest, flags);
153         }
154     }
155 
156     @Override
getPrimaryAction()157     public PendingIntent getPrimaryAction() {
158         return mPrimaryAction;
159     }
160 
161     @Override
getDisabledClickAction()162     public PendingIntent getDisabledClickAction() {
163         return mDisabledClickAction;
164     }
165 
166     @Nullable
getTitle()167     public String getTitle() {
168         return mTitle;
169     }
170 
171     @Nullable
getSubtitle()172     public String getSubtitle() {
173         return mSubtitle;
174     }
175 
176     @Nullable
getActionText()177     public String getActionText() {
178         return mActionText;
179     }
180 
181     @QCCategory
getCategory()182     public int getCategory() {
183         return mCategory;
184     }
185 
186     @Nullable
getStartIcon()187     public Icon getStartIcon() {
188         return mStartIcon;
189     }
190 
isStartIconTintable()191     public boolean isStartIconTintable() {
192         return mIsStartIconTintable;
193     }
194 
195     @Nullable
getSlider()196     public QCSlider getSlider() {
197         return mSlider;
198     }
199 
200     @NonNull
getStartItems()201     public List<QCActionItem> getStartItems() {
202         return mStartItems;
203     }
204 
205     @NonNull
getEndItems()206     public List<QCActionItem> getEndItems() {
207         return mEndItems;
208     }
209 
210     public static Creator<QCRow> CREATOR = new Creator<QCRow>() {
211         @Override
212         public QCRow createFromParcel(Parcel source) {
213             return new QCRow(source);
214         }
215 
216         @Override
217         public QCRow[] newArray(int size) {
218             return new QCRow[size];
219         }
220     };
221 
222     /**
223      * Builder for {@link QCRow}.
224      */
225     public static class Builder {
226         private final List<QCActionItem> mStartItems = new ArrayList<>();
227         private final List<QCActionItem> mEndItems = new ArrayList<>();
228         private Icon mStartIcon;
229         private boolean mIsStartIconTintable = true;
230         private String mTitle;
231         private String mSubtitle;
232         private String mActionText;
233         private int mCategory = QCCategory.NORMAL;
234         private boolean mIsEnabled = true;
235         private boolean mIsClickableWhileDisabled = false;
236         private QCSlider mSlider;
237         private PendingIntent mPrimaryAction;
238         private PendingIntent mDisabledClickAction;
239 
240         /**
241          * Sets the row title.
242          */
setTitle(@ullable String title)243         public Builder setTitle(@Nullable String title) {
244             mTitle = title;
245             return this;
246         }
247 
248         /**
249          * Sets the row subtitle.
250          */
setSubtitle(@ullable String subtitle)251         public Builder setSubtitle(@Nullable String subtitle) {
252             mSubtitle = subtitle;
253             return this;
254         }
255 
256         /**
257          * Sets the row action text.
258          */
setActionText(@ullable String actionText)259         public Builder setActionText(@Nullable String actionText) {
260             mActionText = actionText;
261             return this;
262         }
263 
264         /**
265          * Sets the row category.
266          */
setCategory(@CCategory int category)267         public Builder setCategory(@QCCategory int category) {
268             mCategory = category;
269             return this;
270         }
271 
272         /**
273          * Sets whether or not the row is enabled. Note that this only affects the main row area,
274          * not the action items contained within the row.
275          */
setEnabled(boolean enabled)276         public Builder setEnabled(boolean enabled) {
277             mIsEnabled = enabled;
278             return this;
279         }
280 
281         /**
282          * Sets whether or not the row should be clickable while disabled.
283          */
setClickableWhileDisabled(boolean clickable)284         public Builder setClickableWhileDisabled(boolean clickable) {
285             mIsClickableWhileDisabled = clickable;
286             return this;
287         }
288 
289         /**
290          * Sets the row icon.
291          */
setIcon(@ullable Icon icon)292         public Builder setIcon(@Nullable Icon icon) {
293             mStartIcon = icon;
294             return this;
295         }
296 
297         /**
298          * Sets whether or not the row icon is tintable.
299          */
setIconTintable(boolean tintable)300         public Builder setIconTintable(boolean tintable) {
301             mIsStartIconTintable = tintable;
302             return this;
303         }
304 
305         /**
306          * Adds a {@link QCSlider} to the slider area.
307          */
addSlider(@ullable QCSlider slider)308         public Builder addSlider(@Nullable QCSlider slider) {
309             mSlider = slider;
310             return this;
311         }
312 
313         /**
314          * Sets the PendingIntent to be sent when the row is clicked.
315          */
setPrimaryAction(@ullable PendingIntent action)316         public Builder setPrimaryAction(@Nullable PendingIntent action) {
317             mPrimaryAction = action;
318             return this;
319         }
320 
321         /**
322          * Sets the PendingIntent to be sent when the action item is clicked while disabled.
323          */
setDisabledClickAction(@ullable PendingIntent action)324         public Builder setDisabledClickAction(@Nullable PendingIntent action) {
325             mDisabledClickAction = action;
326             return this;
327         }
328 
329         /**
330          * Adds a {@link QCActionItem} to the start items area.
331          */
addStartItem(@onNull QCActionItem item)332         public Builder addStartItem(@NonNull QCActionItem item) {
333             mStartItems.add(item);
334             return this;
335         }
336 
337         /**
338          * Adds a {@link QCActionItem} to the end items area.
339          */
addEndItem(@onNull QCActionItem item)340         public Builder addEndItem(@NonNull QCActionItem item) {
341             mEndItems.add(item);
342             return this;
343         }
344 
345         /**
346          * Builds the final {@link QCRow}.
347          */
build()348         public QCRow build() {
349             return new QCRow(mTitle, mSubtitle, mActionText, mCategory, mIsEnabled,
350                     mIsClickableWhileDisabled, mPrimaryAction, mDisabledClickAction, mStartIcon,
351                     mIsStartIconTintable, mSlider, mStartItems, mEndItems);
352         }
353     }
354 }
355