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.systemui.car.statusicon;
18 
19 import android.annotation.DimenRes;
20 import android.annotation.LayoutRes;
21 import android.graphics.drawable.Drawable;
22 import android.view.View;
23 import android.widget.ImageView;
24 
25 import androidx.annotation.VisibleForTesting;
26 import androidx.lifecycle.MutableLiveData;
27 import androidx.lifecycle.Observer;
28 
29 import com.android.systemui.R;
30 
31 import java.util.HashMap;
32 import java.util.Map;
33 
34 /**
35  * Abstract class to extend to control views that display a certain status icon.
36  */
37 public abstract class StatusIconController {
38     public static final int PANEL_CONTENT_LAYOUT_NONE = -1;
39 
40     private final StatusIconData mStatusIconData = new StatusIconData();
41     private final MutableLiveData<StatusIconData> mStatusIconLiveData =
42             new MutableLiveData<>(mStatusIconData);
43     private final Map<ImageView, Observer<StatusIconData>> mObserverMap = new HashMap<>();
44 
45     /**
46      * Registers an {@link ImageView} to contain the icon that this controller controls.
47      */
registerIconView(ImageView view)48     public final void registerIconView(ImageView view) {
49         if (mObserverMap.containsKey(view)) return;
50 
51         Observer<StatusIconData> observer = statusIconData -> updateIconView(view, statusIconData);
52         mObserverMap.put(view, observer);
53         mStatusIconLiveData.observeForever(observer);
54     }
55 
56     /**
57      * Unregisters the observer for an {@link ImageView}.
58      */
unregisterIconView(ImageView view)59     public final void unregisterIconView(ImageView view) {
60         Observer<StatusIconData> observer = mObserverMap.remove(view);
61         if (observer != null) {
62             mStatusIconLiveData.removeObserver(observer);
63         }
64     }
65 
66     /**
67      * Returns the {@link Drawable} set to be displayed as the icon.
68      */
getIconDrawableToDisplay()69     public Drawable getIconDrawableToDisplay() {
70         return mStatusIconData.getIconDrawable();
71     }
72 
73     /**
74      * Sets the icon drawable to display.
75      */
setIconDrawableToDisplay(Drawable drawable)76     protected final void setIconDrawableToDisplay(Drawable drawable) {
77         mStatusIconData.setIconDrawable(drawable);
78     }
79 
80     /**
81      * Sets the icon visibility.
82      *
83      * NOTE: Icons are visible by default.
84      */
setIconVisibility(boolean isVisible)85     protected final void setIconVisibility(boolean isVisible) {
86         mStatusIconData.setIsIconVisible(isVisible);
87     }
88 
89     /**
90      * Provides observing views with the {@link StatusIconData} and causes them to update
91      * themselves accordingly through {@link #updateIconView}.
92      */
onStatusUpdated()93     protected void onStatusUpdated() {
94         mStatusIconLiveData.setValue(mStatusIconData);
95     }
96 
97     /**
98      * Updates the icon view based on the current {@link StatusIconData}.
99      */
updateIconView(ImageView view, StatusIconData data)100     protected void updateIconView(ImageView view, StatusIconData data) {
101         view.setImageDrawable(data.getIconDrawable());
102         view.setVisibility(data.getIsIconVisible() ? View.VISIBLE : View.GONE);
103     }
104 
105     /**
106      * Returns the resource id of the layout to be drawn inside the panel associated with this
107      * status icon.
108      *
109      * By default, {@link #PANEL_CONTENT_LAYOUT_NONE} is returned and no panel will be attached to
110      * the status icon.
111      */
112     @LayoutRes
getPanelContentLayout()113     protected int getPanelContentLayout() {
114         return PANEL_CONTENT_LAYOUT_NONE;
115     }
116 
117     /**
118      * Returns the resource id of the width for the panel associated with this status icon.
119      */
120     @DimenRes
getPanelWidth()121     protected int getPanelWidth() {
122         return R.dimen.car_status_icon_panel_default_width;
123     }
124 
125     /**
126      * Determines the icon to display via {@link #setIconDrawableToDisplay} and notifies observing
127      * views by calling {@link #onStatusUpdated} at the end.
128      */
updateStatus()129     protected abstract void updateStatus();
130 
131     @VisibleForTesting
isViewRegistered(ImageView view)132     boolean isViewRegistered(ImageView view) {
133         return mObserverMap.containsKey(view);
134     }
135 }
136