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.view;
18 
19 import android.content.Context;
20 import android.util.AttributeSet;
21 import android.view.Gravity;
22 import android.widget.FrameLayout;
23 
24 import androidx.annotation.NonNull;
25 import androidx.lifecycle.Observer;
26 
27 import com.android.car.qc.QCItem;
28 
29 /**
30  * Base Quick Controls View - supports {@link QCItem.QC_TYPE_TILE} and {@link QCItem.QC_TYPE_LIST}
31  */
32 public class QCView extends FrameLayout implements Observer<QCItem> {
33     @QCItem.QCItemType
34     private String mType;
35     private Observer<QCItem> mChildObserver;
36     private QCActionListener mActionListener;
37 
QCView(Context context)38     public QCView(Context context) {
39         super(context);
40     }
41 
QCView(Context context, AttributeSet attrs)42     public QCView(Context context, AttributeSet attrs) {
43         super(context, attrs);
44     }
45 
QCView(Context context, AttributeSet attrs, int defStyleAttr)46     public QCView(Context context, AttributeSet attrs, int defStyleAttr) {
47         super(context, attrs, defStyleAttr);
48     }
49 
QCView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)50     public QCView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
51         super(context, attrs, defStyleAttr, defStyleRes);
52     }
53 
54     /**
55      * Set the view's {@link QCActionListener}. This listener will propagate to all sub-views.
56      */
setActionListener(QCActionListener listener)57     public void setActionListener(QCActionListener listener) {
58         mActionListener = listener;
59         if (mChildObserver instanceof QCTileView) {
60             ((QCTileView) mChildObserver).setActionListener(mActionListener);
61         } else if (mChildObserver instanceof QCListView) {
62             ((QCListView) mChildObserver).setActionListener(mActionListener);
63         }
64     }
65 
66     @Override
onChanged(QCItem qcItem)67     public void onChanged(QCItem qcItem) {
68         if (qcItem == null) {
69             removeAllViews();
70             mChildObserver = null;
71             mType = null;
72             return;
73         }
74         if (!isValidQCItemType(qcItem)) {
75             throw new IllegalArgumentException("Expected QCTile or QCList type but got "
76                     + qcItem.getType());
77         }
78         if (qcItem.getType().equals(mType)) {
79             mChildObserver.onChanged(qcItem);
80             return;
81         }
82         removeAllViews();
83         mType = qcItem.getType();
84         if (mType.equals(QCItem.QC_TYPE_TILE)) {
85             QCTileView view = new QCTileView(getContext());
86             FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
87                     LayoutParams.WRAP_CONTENT,
88                     LayoutParams.WRAP_CONTENT,
89                     Gravity.CENTER_HORIZONTAL);
90             view.onChanged(qcItem);
91             view.setActionListener(mActionListener);
92             addView(view, params);
93             mChildObserver = view;
94         } else {
95             QCListView view = new QCListView(getContext());
96             view.onChanged(qcItem);
97             view.setActionListener(mActionListener);
98             addView(view);
99             mChildObserver = view;
100         }
101     }
102 
isValidQCItemType(QCItem qcItem)103     private boolean isValidQCItemType(QCItem qcItem) {
104         String type = qcItem.getType();
105         return type.equals(QCItem.QC_TYPE_TILE) || type.equals(QCItem.QC_TYPE_LIST);
106     }
107 
108     /**
109      * Listener to be called when an action occurs on a QCView.
110      */
111     public interface QCActionListener {
112         /**
113          * Called when an interaction has occurred with an element in this view.
114          * @param item the specific item within the {@link QCItem} that was interacted with.
115          * @param action the action that was executed - is generally either a
116          *               {@link android.app.PendingIntent} or {@link QCItem.ActionHandler}
117          */
onQCAction(@onNull QCItem item, @NonNull Object action)118         void onQCAction(@NonNull QCItem item, @NonNull Object action);
119     }
120 }
121