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