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.content.res.Configuration; 21 import android.graphics.Rect; 22 import android.graphics.drawable.Icon; 23 import android.os.Bundle; 24 import android.os.UserHandle; 25 import android.util.Log; 26 import android.view.Gravity; 27 import android.view.View; 28 import android.view.ViewGroup; 29 import android.widget.LinearLayout; 30 31 import com.android.internal.statusbar.StatusBarIcon; 32 import com.android.systemui.R; 33 import com.android.systemui.demomode.DemoMode; 34 import com.android.systemui.plugins.DarkIconDispatcher; 35 import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver; 36 import com.android.systemui.statusbar.StatusBarIconView; 37 import com.android.systemui.statusbar.StatusBarMobileView; 38 import com.android.systemui.statusbar.StatusBarWifiView; 39 import com.android.systemui.statusbar.StatusIconDisplayable; 40 import com.android.systemui.statusbar.connectivity.ui.MobileContextProvider; 41 import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState; 42 import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState; 43 import com.android.systemui.statusbar.pipeline.mobile.ui.MobileViewLogger; 44 import com.android.systemui.statusbar.pipeline.mobile.ui.view.ModernStatusBarMobileView; 45 import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel; 46 import com.android.systemui.statusbar.pipeline.wifi.ui.view.ModernStatusBarWifiView; 47 import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.LocationBasedWifiViewModel; 48 49 import java.util.ArrayList; 50 import java.util.List; 51 52 //TODO: This should be a controller, not its own view 53 public class DemoStatusIcons extends StatusIconContainer implements DemoMode, DarkReceiver { 54 private static final String TAG = "DemoStatusIcons"; 55 56 private final LinearLayout mStatusIcons; 57 private final ArrayList<StatusBarMobileView> mMobileViews = new ArrayList<>(); 58 private final ArrayList<ModernStatusBarMobileView> mModernMobileViews = new ArrayList<>(); 59 private final int mIconSize; 60 61 private StatusBarWifiView mWifiView; 62 private ModernStatusBarWifiView mModernWifiView; 63 private boolean mDemoMode; 64 private int mColor; 65 66 private final MobileIconsViewModel mMobileIconsViewModel; 67 private final StatusBarLocation mLocation; 68 DemoStatusIcons( LinearLayout statusIcons, MobileIconsViewModel mobileIconsViewModel, StatusBarLocation location, int iconSize )69 public DemoStatusIcons( 70 LinearLayout statusIcons, 71 MobileIconsViewModel mobileIconsViewModel, 72 StatusBarLocation location, 73 int iconSize 74 ) { 75 super(statusIcons.getContext()); 76 mStatusIcons = statusIcons; 77 mIconSize = iconSize; 78 mColor = DarkIconDispatcher.DEFAULT_ICON_TINT; 79 mMobileIconsViewModel = mobileIconsViewModel; 80 mLocation = location; 81 82 if (statusIcons instanceof StatusIconContainer) { 83 setShouldRestrictIcons(((StatusIconContainer) statusIcons).isRestrictingIcons()); 84 } else { 85 setShouldRestrictIcons(false); 86 } 87 setLayoutParams(mStatusIcons.getLayoutParams()); 88 setPadding(mStatusIcons.getPaddingLeft(), mStatusIcons.getPaddingTop(), 89 mStatusIcons.getPaddingRight(), mStatusIcons.getPaddingBottom()); 90 setOrientation(mStatusIcons.getOrientation()); 91 setGravity(Gravity.CENTER_VERTICAL); // no LL.getGravity() 92 ViewGroup p = (ViewGroup) mStatusIcons.getParent(); 93 p.addView(this, p.indexOfChild(mStatusIcons)); 94 } 95 remove()96 public void remove() { 97 mMobileViews.clear(); 98 ((ViewGroup) getParent()).removeView(this); 99 } 100 setColor(int color)101 public void setColor(int color) { 102 mColor = color; 103 updateColors(); 104 } 105 updateColors()106 private void updateColors() { 107 for (int i = 0; i < getChildCount(); i++) { 108 StatusIconDisplayable child = (StatusIconDisplayable) getChildAt(i); 109 child.setStaticDrawableColor(mColor); 110 child.setDecorColor(mColor); 111 } 112 } 113 114 @Override demoCommands()115 public List<String> demoCommands() { 116 List<String> commands = new ArrayList<>(); 117 commands.add(COMMAND_STATUS); 118 return commands; 119 } 120 121 @Override onDemoModeStarted()122 public void onDemoModeStarted() { 123 mDemoMode = true; 124 mStatusIcons.setVisibility(View.GONE); 125 setVisibility(View.VISIBLE); 126 } 127 128 @Override onDemoModeFinished()129 public void onDemoModeFinished() { 130 mDemoMode = false; 131 mStatusIcons.setVisibility(View.VISIBLE); 132 mModernMobileViews.clear(); 133 mMobileViews.clear(); 134 setVisibility(View.GONE); 135 } 136 137 @Override dispatchDemoCommand(String command, Bundle args)138 public void dispatchDemoCommand(String command, Bundle args) { 139 String volume = args.getString("volume"); 140 if (volume != null) { 141 int iconId = volume.equals("vibrate") ? R.drawable.stat_sys_ringer_vibrate 142 : 0; 143 updateSlot("volume", null, iconId); 144 } 145 String zen = args.getString("zen"); 146 if (zen != null) { 147 int iconId = zen.equals("dnd") ? R.drawable.stat_sys_dnd : 0; 148 updateSlot("zen", null, iconId); 149 } 150 String bt = args.getString("bluetooth"); 151 if (bt != null) { 152 int iconId = bt.equals("connected") 153 ? R.drawable.stat_sys_data_bluetooth_connected : 0; 154 updateSlot("bluetooth", null, iconId); 155 } 156 String location = args.getString("location"); 157 if (location != null) { 158 int iconId = location.equals("show") ? PhoneStatusBarPolicy.LOCATION_STATUS_ICON_ID 159 : 0; 160 updateSlot("location", null, iconId); 161 } 162 String alarm = args.getString("alarm"); 163 if (alarm != null) { 164 int iconId = alarm.equals("show") ? R.drawable.stat_sys_alarm 165 : 0; 166 updateSlot("alarm_clock", null, iconId); 167 } 168 String tty = args.getString("tty"); 169 if (tty != null) { 170 int iconId = tty.equals("show") ? R.drawable.stat_sys_tty_mode 171 : 0; 172 updateSlot("tty", null, iconId); 173 } 174 String mute = args.getString("mute"); 175 if (mute != null) { 176 int iconId = mute.equals("show") ? android.R.drawable.stat_notify_call_mute 177 : 0; 178 updateSlot("mute", null, iconId); 179 } 180 String speakerphone = args.getString("speakerphone"); 181 if (speakerphone != null) { 182 int iconId = speakerphone.equals("show") ? android.R.drawable.stat_sys_speakerphone 183 : 0; 184 updateSlot("speakerphone", null, iconId); 185 } 186 String cast = args.getString("cast"); 187 if (cast != null) { 188 int iconId = cast.equals("show") ? R.drawable.stat_sys_cast : 0; 189 updateSlot("cast", null, iconId); 190 } 191 String hotspot = args.getString("hotspot"); 192 if (hotspot != null) { 193 int iconId = hotspot.equals("show") ? R.drawable.stat_sys_hotspot : 0; 194 updateSlot("hotspot", null, iconId); 195 } 196 } 197 198 /// Can only be used to update non-signal related slots updateSlot(String slot, String iconPkg, int iconId)199 private void updateSlot(String slot, String iconPkg, int iconId) { 200 if (!mDemoMode) return; 201 if (iconPkg == null) { 202 iconPkg = mContext.getPackageName(); 203 } 204 int removeIndex = -1; 205 for (int i = 0; i < getChildCount(); i++) { 206 View child = getChildAt(i); 207 if (!(child instanceof StatusBarIconView)) { 208 continue; 209 } 210 StatusBarIconView v = (StatusBarIconView) child; 211 if (slot.equals(v.getTag())) { 212 if (iconId == 0) { 213 removeIndex = i; 214 break; 215 } else { 216 StatusBarIcon icon = v.getStatusBarIcon(); 217 icon.visible = true; 218 icon.icon = Icon.createWithResource(icon.icon.getResPackage(), iconId); 219 v.set(icon); 220 v.updateDrawable(); 221 return; 222 } 223 } 224 } 225 if (iconId == 0) { 226 if (removeIndex != -1) { 227 removeViewAt(removeIndex); 228 } 229 return; 230 } 231 StatusBarIcon icon = new StatusBarIcon(iconPkg, UserHandle.SYSTEM, iconId, 0, 0, "Demo"); 232 icon.visible = true; 233 StatusBarIconView v = new StatusBarIconView(getContext(), slot, null, false); 234 v.setTag(slot); 235 v.set(icon); 236 v.setStaticDrawableColor(mColor); 237 v.setDecorColor(mColor); 238 addView(v, 0, createLayoutParams()); 239 } 240 addDemoWifiView(WifiIconState state)241 public void addDemoWifiView(WifiIconState state) { 242 Log.d(TAG, "addDemoWifiView: "); 243 StatusBarWifiView view = StatusBarWifiView.fromContext(mContext, state.slot); 244 245 int viewIndex = getChildCount(); 246 // If we have mobile views, put wifi before them 247 for (int i = 0; i < getChildCount(); i++) { 248 View child = getChildAt(i); 249 if (child instanceof StatusBarMobileView 250 || child instanceof ModernStatusBarMobileView) { 251 viewIndex = i; 252 break; 253 } 254 } 255 256 mWifiView = view; 257 mWifiView.applyWifiState(state); 258 mWifiView.setStaticDrawableColor(mColor); 259 addView(view, viewIndex, createLayoutParams()); 260 } 261 updateWifiState(WifiIconState state)262 public void updateWifiState(WifiIconState state) { 263 Log.d(TAG, "updateWifiState: "); 264 if (mWifiView == null) { 265 addDemoWifiView(state); 266 } else { 267 mWifiView.applyWifiState(state); 268 } 269 } 270 271 /** 272 * Add a new mobile icon view 273 */ addMobileView(MobileIconState state, Context mobileContext)274 public void addMobileView(MobileIconState state, Context mobileContext) { 275 Log.d(TAG, "addMobileView: "); 276 StatusBarMobileView view = StatusBarMobileView 277 .fromContext(mobileContext, state.slot); 278 279 view.applyMobileState(state); 280 view.setStaticDrawableColor(mColor); 281 282 // mobile always goes at the end 283 mMobileViews.add(view); 284 addView(view, getChildCount(), createLayoutParams()); 285 } 286 287 /** 288 * Add a {@link ModernStatusBarMobileView} 289 * @param mobileContext possibly mcc/mnc overridden mobile context 290 * @param subId the subscriptionId for this mobile view 291 */ addModernMobileView( Context mobileContext, MobileViewLogger mobileViewLogger, int subId)292 public void addModernMobileView( 293 Context mobileContext, 294 MobileViewLogger mobileViewLogger, 295 int subId) { 296 Log.d(TAG, "addModernMobileView (subId=" + subId + ")"); 297 ModernStatusBarMobileView view = ModernStatusBarMobileView.constructAndBind( 298 mobileContext, 299 mobileViewLogger, 300 "mobile", 301 mMobileIconsViewModel.viewModelForSub(subId, mLocation) 302 ); 303 304 // mobile always goes at the end 305 mModernMobileViews.add(view); 306 addView(view, getChildCount(), createLayoutParams()); 307 } 308 309 /** 310 * Add a {@link ModernStatusBarWifiView} 311 */ addModernWifiView(LocationBasedWifiViewModel viewModel)312 public void addModernWifiView(LocationBasedWifiViewModel viewModel) { 313 Log.d(TAG, "addModernDemoWifiView: "); 314 ModernStatusBarWifiView view = ModernStatusBarWifiView 315 .constructAndBind(mContext, "wifi", viewModel); 316 317 int viewIndex = getChildCount(); 318 // If we have mobile views, put wifi before them 319 for (int i = 0; i < getChildCount(); i++) { 320 View child = getChildAt(i); 321 if (child instanceof StatusBarMobileView 322 || child instanceof ModernStatusBarMobileView) { 323 viewIndex = i; 324 break; 325 } 326 } 327 328 mModernWifiView = view; 329 mModernWifiView.setStaticDrawableColor(mColor); 330 addView(view, viewIndex, createLayoutParams()); 331 } 332 333 /** 334 * Apply an update to a mobile icon view for the given {@link MobileIconState}. For 335 * compatibility with {@link MobileContextProvider}, we have to recreate the view every time we 336 * update it, since the context (and thus the {@link Configuration}) may have changed 337 */ updateMobileState(MobileIconState state, Context mobileContext)338 public void updateMobileState(MobileIconState state, Context mobileContext) { 339 Log.d(TAG, "updateMobileState: " + state); 340 341 // The mobile config provided by MobileContextProvider could have changed; always recreate 342 for (int i = 0; i < mMobileViews.size(); i++) { 343 StatusBarMobileView view = mMobileViews.get(i); 344 if (view.getState().subId == state.subId) { 345 removeView(view); 346 } 347 } 348 349 // Add the replacement or new icon 350 addMobileView(state, mobileContext); 351 } 352 onRemoveIcon(StatusIconDisplayable view)353 public void onRemoveIcon(StatusIconDisplayable view) { 354 if (view.getSlot().equals("wifi")) { 355 if (view instanceof StatusBarWifiView) { 356 removeView(mWifiView); 357 mWifiView = null; 358 } else if (view instanceof ModernStatusBarWifiView) { 359 Log.d(TAG, "onRemoveIcon: removing modern wifi view"); 360 removeView(mModernWifiView); 361 mModernWifiView = null; 362 } 363 } else if (view instanceof StatusBarMobileView) { 364 StatusBarMobileView mobileView = matchingMobileView(view); 365 if (mobileView != null) { 366 removeView(mobileView); 367 mMobileViews.remove(mobileView); 368 } 369 } else if (view instanceof ModernStatusBarMobileView) { 370 ModernStatusBarMobileView mobileView = matchingModernMobileView( 371 (ModernStatusBarMobileView) view); 372 if (mobileView != null) { 373 removeView(mobileView); 374 mModernMobileViews.remove(mobileView); 375 } 376 } 377 } 378 matchingMobileView(StatusIconDisplayable otherView)379 private StatusBarMobileView matchingMobileView(StatusIconDisplayable otherView) { 380 if (!(otherView instanceof StatusBarMobileView)) { 381 return null; 382 } 383 384 StatusBarMobileView v = (StatusBarMobileView) otherView; 385 for (StatusBarMobileView view : mMobileViews) { 386 if (view.getState().subId == v.getState().subId) { 387 return view; 388 } 389 } 390 391 return null; 392 } 393 matchingModernMobileView(ModernStatusBarMobileView other)394 private ModernStatusBarMobileView matchingModernMobileView(ModernStatusBarMobileView other) { 395 for (ModernStatusBarMobileView v : mModernMobileViews) { 396 if (v.getSubId() == other.getSubId()) { 397 return v; 398 } 399 } 400 401 return null; 402 } 403 createLayoutParams()404 private LayoutParams createLayoutParams() { 405 return new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, mIconSize); 406 } 407 408 @Override onDarkChanged(ArrayList<Rect> areas, float darkIntensity, int tint)409 public void onDarkChanged(ArrayList<Rect> areas, float darkIntensity, int tint) { 410 setColor(DarkIconDispatcher.getTint(areas, mStatusIcons, tint)); 411 412 if (mWifiView != null) { 413 mWifiView.onDarkChanged(areas, darkIntensity, tint); 414 } 415 if (mModernWifiView != null) { 416 mModernWifiView.onDarkChanged(areas, darkIntensity, tint); 417 } 418 for (StatusBarMobileView view : mMobileViews) { 419 view.onDarkChanged(areas, darkIntensity, tint); 420 } 421 for (ModernStatusBarMobileView view : mModernMobileViews) { 422 view.onDarkChanged(areas, darkIntensity, tint); 423 } 424 } 425 } 426