1 /*
2  * Copyright (C) 2013 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.statusbar.phone;
18 
19 import android.content.Context;
20 import android.graphics.Rect;
21 import android.graphics.drawable.Icon;
22 import android.os.Bundle;
23 import android.os.UserHandle;
24 import android.util.Log;
25 import android.view.Gravity;
26 import android.view.View;
27 import android.view.ViewGroup;
28 import android.widget.LinearLayout;
29 
30 import com.android.internal.statusbar.StatusBarIcon;
31 import com.android.systemui.demomode.DemoMode;
32 import com.android.systemui.plugins.DarkIconDispatcher;
33 import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
34 import com.android.systemui.res.R;
35 import com.android.systemui.statusbar.StatusBarIconView;
36 import com.android.systemui.statusbar.StatusIconDisplayable;
37 import com.android.systemui.statusbar.pipeline.mobile.ui.MobileViewLogger;
38 import com.android.systemui.statusbar.pipeline.mobile.ui.view.ModernStatusBarMobileView;
39 import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel;
40 import com.android.systemui.statusbar.pipeline.shared.ui.view.ModernStatusBarView;
41 import com.android.systemui.statusbar.pipeline.wifi.ui.view.ModernStatusBarWifiView;
42 import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.LocationBasedWifiViewModel;
43 
44 import java.util.ArrayList;
45 import java.util.List;
46 
47 //TODO: This should be a controller, not its own view
48 public class DemoStatusIcons extends StatusIconContainer implements DemoMode, DarkReceiver {
49     private static final String TAG = "DemoStatusIcons";
50 
51     private final LinearLayout mStatusIcons;
52     private final ArrayList<ModernStatusBarMobileView> mModernMobileViews = new ArrayList<>();
53     private final int mIconSize;
54 
55     private ModernStatusBarWifiView mModernWifiView;
56     private boolean mDemoMode;
57     private int mColor;
58     private int mContrastColor;
59 
60     private final MobileIconsViewModel mMobileIconsViewModel;
61     private final StatusBarLocation mLocation;
62 
DemoStatusIcons( LinearLayout statusIcons, MobileIconsViewModel mobileIconsViewModel, StatusBarLocation location, int iconSize )63     public DemoStatusIcons(
64             LinearLayout statusIcons,
65             MobileIconsViewModel mobileIconsViewModel,
66             StatusBarLocation location,
67             int iconSize
68     ) {
69         super(statusIcons.getContext());
70         mStatusIcons = statusIcons;
71         mIconSize = iconSize;
72         mColor = DarkIconDispatcher.DEFAULT_ICON_TINT;
73         mContrastColor = DarkIconDispatcher.DEFAULT_INVERSE_ICON_TINT;
74         mMobileIconsViewModel = mobileIconsViewModel;
75         mLocation = location;
76 
77         if (statusIcons instanceof StatusIconContainer) {
78             setShouldRestrictIcons(((StatusIconContainer) statusIcons).isRestrictingIcons());
79         } else {
80             setShouldRestrictIcons(false);
81         }
82         setLayoutParams(mStatusIcons.getLayoutParams());
83         setPadding(mStatusIcons.getPaddingLeft(), mStatusIcons.getPaddingTop(),
84                 mStatusIcons.getPaddingRight(), mStatusIcons.getPaddingBottom());
85         setOrientation(mStatusIcons.getOrientation());
86         setGravity(Gravity.CENTER_VERTICAL); // no LL.getGravity()
87         ViewGroup p = (ViewGroup) mStatusIcons.getParent();
88         p.addView(this, p.indexOfChild(mStatusIcons));
89     }
90 
remove()91     public void remove() {
92         ((ViewGroup) getParent()).removeView(this);
93     }
94 
95     /** Set the tint colors */
setColor(int color, int contrastColor)96     public void setColor(int color, int contrastColor) {
97         mColor = color;
98         mContrastColor = contrastColor;
99         updateColors();
100     }
101 
updateColors()102     private void updateColors() {
103         for (int i = 0; i < getChildCount(); i++) {
104             StatusIconDisplayable child = (StatusIconDisplayable) getChildAt(i);
105             child.setStaticDrawableColor(mColor, mContrastColor);
106             child.setDecorColor(mColor);
107         }
108     }
109 
110     @Override
demoCommands()111     public List<String> demoCommands() {
112         List<String> commands = new ArrayList<>();
113         commands.add(COMMAND_STATUS);
114         return commands;
115     }
116 
117     @Override
onDemoModeStarted()118     public void onDemoModeStarted() {
119         mDemoMode = true;
120         mStatusIcons.setVisibility(View.GONE);
121         setVisibility(View.VISIBLE);
122     }
123 
124     @Override
onDemoModeFinished()125     public void onDemoModeFinished() {
126         mDemoMode = false;
127         mStatusIcons.setVisibility(View.VISIBLE);
128         mModernMobileViews.clear();
129         setVisibility(View.GONE);
130     }
131 
132     @Override
dispatchDemoCommand(String command, Bundle args)133     public void dispatchDemoCommand(String command, Bundle args) {
134         String volume = args.getString("volume");
135         if (volume != null) {
136             int iconId = volume.equals("vibrate") ? R.drawable.stat_sys_ringer_vibrate
137                     : 0;
138             updateSlot("volume", null, iconId);
139         }
140         String zen = args.getString("zen");
141         if (zen != null) {
142             int iconId = zen.equals("dnd") ? R.drawable.stat_sys_dnd : 0;
143             updateSlot("zen", null, iconId);
144         }
145         String bt = args.getString("bluetooth");
146         if (bt != null) {
147             int iconId = bt.equals("connected")
148                     ? R.drawable.stat_sys_data_bluetooth_connected : 0;
149             updateSlot("bluetooth", null, iconId);
150         }
151         String location = args.getString("location");
152         if (location != null) {
153             int iconId = location.equals("show") ? PhoneStatusBarPolicy.LOCATION_STATUS_ICON_ID
154                     : 0;
155             updateSlot("location", null, iconId);
156         }
157         String alarm = args.getString("alarm");
158         if (alarm != null) {
159             int iconId = alarm.equals("show") ? R.drawable.stat_sys_alarm
160                     : 0;
161             updateSlot("alarm_clock", null, iconId);
162         }
163         String tty = args.getString("tty");
164         if (tty != null) {
165             int iconId = tty.equals("show") ? R.drawable.stat_sys_tty_mode
166                     : 0;
167             updateSlot("tty", null, iconId);
168         }
169         String mute = args.getString("mute");
170         if (mute != null) {
171             int iconId = mute.equals("show") ? android.R.drawable.stat_notify_call_mute
172                     : 0;
173             updateSlot("mute", null, iconId);
174         }
175         String speakerphone = args.getString("speakerphone");
176         if (speakerphone != null) {
177             int iconId = speakerphone.equals("show") ? android.R.drawable.stat_sys_speakerphone
178                     : 0;
179             updateSlot("speakerphone", null, iconId);
180         }
181         String cast = args.getString("cast");
182         if (cast != null) {
183             int iconId = cast.equals("show") ? R.drawable.stat_sys_cast : 0;
184             updateSlot("cast", null, iconId);
185         }
186         String hotspot = args.getString("hotspot");
187         if (hotspot != null) {
188             int iconId = hotspot.equals("show") ? R.drawable.stat_sys_hotspot : 0;
189             updateSlot("hotspot", null, iconId);
190         }
191     }
192 
193     /// Can only be used to update non-signal related slots
updateSlot(String slot, String iconPkg, int iconId)194     private void updateSlot(String slot, String iconPkg, int iconId) {
195         if (!mDemoMode) return;
196         if (iconPkg == null) {
197             iconPkg = mContext.getPackageName();
198         }
199         int removeIndex = -1;
200         for (int i = 0; i < getChildCount(); i++) {
201             View child = getChildAt(i);
202             if (!(child instanceof StatusBarIconView)) {
203                 continue;
204             }
205             StatusBarIconView v = (StatusBarIconView) child;
206             if (slot.equals(v.getTag())) {
207                 if (iconId == 0) {
208                     removeIndex = i;
209                     break;
210                 } else {
211                     StatusBarIcon icon = v.getStatusBarIcon();
212                     icon.visible = true;
213                     icon.icon = Icon.createWithResource(icon.icon.getResPackage(), iconId);
214                     v.set(icon);
215                     v.updateDrawable();
216                     return;
217                 }
218             }
219         }
220         if (iconId == 0) {
221             if (removeIndex != -1) {
222                 removeViewAt(removeIndex);
223             }
224             return;
225         }
226         StatusBarIcon icon = new StatusBarIcon(iconPkg, UserHandle.SYSTEM, iconId, 0, 0, "Demo",
227                 StatusBarIcon.Type.SystemIcon);
228         icon.visible = true;
229         StatusBarIconView v = new StatusBarIconView(getContext(), slot, null, false);
230         v.setTag(slot);
231         v.set(icon);
232         v.setStaticDrawableColor(mColor, mContrastColor);
233         v.setDecorColor(mColor);
234         addView(v, 0, createLayoutParams());
235     }
236 
237     /**
238      * Add a {@link ModernStatusBarMobileView}
239      * @param mobileContext possibly mcc/mnc overridden mobile context
240      * @param subId the subscriptionId for this mobile view
241      */
addModernMobileView( Context mobileContext, MobileViewLogger mobileViewLogger, int subId)242     public void addModernMobileView(
243             Context mobileContext,
244             MobileViewLogger mobileViewLogger,
245             int subId) {
246         Log.d(TAG, "addModernMobileView (subId=" + subId + ")");
247         ModernStatusBarMobileView view = ModernStatusBarMobileView.constructAndBind(
248                 mobileContext,
249                 mobileViewLogger,
250                 "mobile",
251                 mMobileIconsViewModel.viewModelForSub(subId, mLocation)
252         );
253 
254         // mobile always goes at the end
255         mModernMobileViews.add(view);
256         addView(view, getChildCount(), createLayoutParams());
257     }
258 
259     /**
260      * Add a {@link ModernStatusBarWifiView}
261      */
addModernWifiView(LocationBasedWifiViewModel viewModel)262     public void addModernWifiView(LocationBasedWifiViewModel viewModel) {
263         Log.d(TAG, "addModernDemoWifiView: ");
264         ModernStatusBarWifiView view = ModernStatusBarWifiView
265                 .constructAndBind(mContext, "wifi", viewModel);
266 
267         int viewIndex = getChildCount();
268         // If we have mobile views, put wifi before them
269         for (int i = 0; i < getChildCount(); i++) {
270             View child = getChildAt(i);
271             if (child instanceof ModernStatusBarMobileView) {
272                 viewIndex = i;
273                 break;
274             }
275         }
276 
277         mModernWifiView = view;
278         mModernWifiView.setStaticDrawableColor(mColor, mContrastColor);
279         addView(view, viewIndex, createLayoutParams());
280     }
281 
282     /** Adds a bindable icon to the demo mode view. */
addBindableIcon(StatusBarIconHolder.BindableIconHolder holder)283     public void addBindableIcon(StatusBarIconHolder.BindableIconHolder holder) {
284         // This doesn't do any correct ordering, and also doesn't check if we already have an
285         // existing icon for the slot. But since we hope to remove this class soon, we won't spend
286         // the time adding that logic.
287         ModernStatusBarView view = holder.getInitializer().createAndBind(mContext);
288         addView(view, createLayoutParams());
289     }
290 
onRemoveIcon(StatusIconDisplayable view)291     public void onRemoveIcon(StatusIconDisplayable view) {
292         if (view.getSlot().equals("wifi")) {
293             if (view instanceof ModernStatusBarWifiView) {
294                 Log.d(TAG, "onRemoveIcon: removing modern wifi view");
295                 removeView(mModernWifiView);
296                 mModernWifiView = null;
297             }
298         } else if (view instanceof ModernStatusBarMobileView) {
299             ModernStatusBarMobileView mobileView = matchingModernMobileView(
300                     (ModernStatusBarMobileView) view);
301             if (mobileView != null) {
302                 removeView(mobileView);
303                 mModernMobileViews.remove(mobileView);
304             }
305         }
306     }
307 
matchingModernMobileView(ModernStatusBarMobileView other)308     private ModernStatusBarMobileView matchingModernMobileView(ModernStatusBarMobileView other) {
309         for (ModernStatusBarMobileView v : mModernMobileViews) {
310             if (v.getSubId() == other.getSubId()) {
311                 return v;
312             }
313         }
314 
315         return null;
316     }
317 
createLayoutParams()318     private LayoutParams createLayoutParams() {
319         return new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, mIconSize);
320     }
321 
322     @Override
onDarkChangedWithContrast(ArrayList<Rect> areas, int tint, int contrastTint)323     public void onDarkChangedWithContrast(ArrayList<Rect> areas, int tint, int contrastTint) {
324         setColor(tint, contrastTint);
325 
326         if (mModernWifiView != null) {
327             mModernWifiView.onDarkChangedWithContrast(areas, tint, contrastTint);
328         }
329 
330         for (ModernStatusBarMobileView view : mModernMobileViews) {
331             view.onDarkChangedWithContrast(areas, tint, contrastTint);
332         }
333     }
334 
335     @Override
onDarkChanged(ArrayList<Rect> areas, float darkIntensity, int tint)336     public void onDarkChanged(ArrayList<Rect> areas, float darkIntensity, int tint) {
337         // not needed
338     }
339 }
340