1 /* 2 * Copyright (C) 2011 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; 18 19 import android.annotation.DrawableRes; 20 import android.content.Context; 21 import android.content.res.ColorStateList; 22 import android.content.res.Resources; 23 import android.graphics.Color; 24 import android.graphics.Rect; 25 import android.graphics.drawable.Animatable; 26 import android.graphics.drawable.AnimatedVectorDrawable; 27 import android.graphics.drawable.Drawable; 28 import android.telephony.SubscriptionInfo; 29 import android.util.ArraySet; 30 import android.util.AttributeSet; 31 import android.util.Log; 32 import android.util.TypedValue; 33 import android.view.LayoutInflater; 34 import android.view.View; 35 import android.view.ViewGroup; 36 import android.view.accessibility.AccessibilityEvent; 37 import android.widget.ImageView; 38 import android.widget.LinearLayout; 39 40 import com.android.systemui.R; 41 import com.android.systemui.statusbar.phone.StatusBarIconController; 42 import com.android.systemui.statusbar.policy.NetworkController.IconState; 43 import com.android.systemui.statusbar.policy.NetworkControllerImpl; 44 import com.android.systemui.statusbar.policy.SecurityController; 45 import com.android.systemui.tuner.TunerService; 46 import com.android.systemui.tuner.TunerService.Tunable; 47 48 import java.util.ArrayList; 49 import java.util.List; 50 51 // Intimately tied to the design of res/layout/signal_cluster_view.xml 52 public class SignalClusterView 53 extends LinearLayout 54 implements NetworkControllerImpl.SignalCallback, 55 SecurityController.SecurityControllerCallback, Tunable { 56 57 static final String TAG = "SignalClusterView"; 58 static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 59 60 private static final String SLOT_AIRPLANE = "airplane"; 61 private static final String SLOT_MOBILE = "mobile"; 62 private static final String SLOT_WIFI = "wifi"; 63 private static final String SLOT_ETHERNET = "ethernet"; 64 65 NetworkControllerImpl mNC; 66 SecurityController mSC; 67 68 private boolean mNoSimsVisible = false; 69 private boolean mVpnVisible = false; 70 private boolean mEthernetVisible = false; 71 private int mEthernetIconId = 0; 72 private int mLastEthernetIconId = -1; 73 private boolean mWifiVisible = false; 74 private int mWifiStrengthId = 0; 75 private int mLastWifiStrengthId = -1; 76 private boolean mIsAirplaneMode = false; 77 private int mAirplaneIconId = 0; 78 private int mLastAirplaneIconId = -1; 79 private String mAirplaneContentDescription; 80 private String mWifiDescription; 81 private String mEthernetDescription; 82 private ArrayList<PhoneState> mPhoneStates = new ArrayList<PhoneState>(); 83 private int mIconTint = Color.WHITE; 84 private float mDarkIntensity; 85 private final Rect mTintArea = new Rect(); 86 87 ViewGroup mEthernetGroup, mWifiGroup; 88 View mNoSimsCombo; 89 ImageView mVpn, mEthernet, mWifi, mAirplane, mNoSims, mEthernetDark, mWifiDark, mNoSimsDark; 90 View mWifiAirplaneSpacer; 91 View mWifiSignalSpacer; 92 LinearLayout mMobileSignalGroup; 93 94 private final int mMobileSignalGroupEndPadding; 95 private final int mMobileDataIconStartPadding; 96 private final int mWideTypeIconStartPadding; 97 private final int mSecondaryTelephonyPadding; 98 private final int mEndPadding; 99 private final int mEndPaddingNothingVisible; 100 private final float mIconScaleFactor; 101 102 private boolean mBlockAirplane; 103 private boolean mBlockMobile; 104 private boolean mBlockWifi; 105 private boolean mBlockEthernet; 106 SignalClusterView(Context context)107 public SignalClusterView(Context context) { 108 this(context, null); 109 } 110 SignalClusterView(Context context, AttributeSet attrs)111 public SignalClusterView(Context context, AttributeSet attrs) { 112 this(context, attrs, 0); 113 } 114 SignalClusterView(Context context, AttributeSet attrs, int defStyle)115 public SignalClusterView(Context context, AttributeSet attrs, int defStyle) { 116 super(context, attrs, defStyle); 117 118 Resources res = getResources(); 119 mMobileSignalGroupEndPadding = 120 res.getDimensionPixelSize(R.dimen.mobile_signal_group_end_padding); 121 mMobileDataIconStartPadding = 122 res.getDimensionPixelSize(R.dimen.mobile_data_icon_start_padding); 123 mWideTypeIconStartPadding = res.getDimensionPixelSize(R.dimen.wide_type_icon_start_padding); 124 mSecondaryTelephonyPadding = res.getDimensionPixelSize(R.dimen.secondary_telephony_padding); 125 mEndPadding = res.getDimensionPixelSize(R.dimen.signal_cluster_battery_padding); 126 mEndPaddingNothingVisible = res.getDimensionPixelSize( 127 R.dimen.no_signal_cluster_battery_padding); 128 129 TypedValue typedValue = new TypedValue(); 130 res.getValue(R.dimen.status_bar_icon_scale_factor, typedValue, true); 131 mIconScaleFactor = typedValue.getFloat(); 132 } 133 134 @Override onTuningChanged(String key, String newValue)135 public void onTuningChanged(String key, String newValue) { 136 if (!StatusBarIconController.ICON_BLACKLIST.equals(key)) { 137 return; 138 } 139 ArraySet<String> blockList = StatusBarIconController.getIconBlacklist(newValue); 140 boolean blockAirplane = blockList.contains(SLOT_AIRPLANE); 141 boolean blockMobile = blockList.contains(SLOT_MOBILE); 142 boolean blockWifi = blockList.contains(SLOT_WIFI); 143 boolean blockEthernet = blockList.contains(SLOT_ETHERNET); 144 145 if (blockAirplane != mBlockAirplane || blockMobile != mBlockMobile 146 || blockEthernet != mBlockEthernet || blockWifi != mBlockWifi) { 147 mBlockAirplane = blockAirplane; 148 mBlockMobile = blockMobile; 149 mBlockEthernet = blockEthernet; 150 mBlockWifi = blockWifi; 151 // Re-register to get new callbacks. 152 mNC.removeSignalCallback(this); 153 mNC.addSignalCallback(this); 154 } 155 } 156 setNetworkController(NetworkControllerImpl nc)157 public void setNetworkController(NetworkControllerImpl nc) { 158 if (DEBUG) Log.d(TAG, "NetworkController=" + nc); 159 mNC = nc; 160 } 161 setSecurityController(SecurityController sc)162 public void setSecurityController(SecurityController sc) { 163 if (DEBUG) Log.d(TAG, "SecurityController=" + sc); 164 mSC = sc; 165 mSC.addCallback(this); 166 mVpnVisible = mSC.isVpnEnabled(); 167 } 168 169 @Override onFinishInflate()170 protected void onFinishInflate() { 171 super.onFinishInflate(); 172 173 mVpn = (ImageView) findViewById(R.id.vpn); 174 mEthernetGroup = (ViewGroup) findViewById(R.id.ethernet_combo); 175 mEthernet = (ImageView) findViewById(R.id.ethernet); 176 mEthernetDark = (ImageView) findViewById(R.id.ethernet_dark); 177 mWifiGroup = (ViewGroup) findViewById(R.id.wifi_combo); 178 mWifi = (ImageView) findViewById(R.id.wifi_signal); 179 mWifiDark = (ImageView) findViewById(R.id.wifi_signal_dark); 180 mAirplane = (ImageView) findViewById(R.id.airplane); 181 mNoSims = (ImageView) findViewById(R.id.no_sims); 182 mNoSimsDark = (ImageView) findViewById(R.id.no_sims_dark); 183 mNoSimsCombo = findViewById(R.id.no_sims_combo); 184 mWifiAirplaneSpacer = findViewById(R.id.wifi_airplane_spacer); 185 mWifiSignalSpacer = findViewById(R.id.wifi_signal_spacer); 186 mMobileSignalGroup = (LinearLayout) findViewById(R.id.mobile_signal_group); 187 188 maybeScaleVpnAndNoSimsIcons(); 189 } 190 191 /** 192 * Extracts the icon off of the VPN and no sims views and maybe scale them by 193 * {@link #mIconScaleFactor}. Note that the other icons are not scaled here because they are 194 * dynamic. As such, they need to be scaled each time the icon changes in {@link #apply()}. 195 */ maybeScaleVpnAndNoSimsIcons()196 private void maybeScaleVpnAndNoSimsIcons() { 197 if (mIconScaleFactor == 1.f) { 198 return; 199 } 200 201 mVpn.setImageDrawable(new ScalingDrawableWrapper(mVpn.getDrawable(), mIconScaleFactor)); 202 203 mNoSims.setImageDrawable( 204 new ScalingDrawableWrapper(mNoSims.getDrawable(), mIconScaleFactor)); 205 mNoSimsDark.setImageDrawable( 206 new ScalingDrawableWrapper(mNoSimsDark.getDrawable(), mIconScaleFactor)); 207 } 208 209 @Override onAttachedToWindow()210 protected void onAttachedToWindow() { 211 super.onAttachedToWindow(); 212 213 for (PhoneState state : mPhoneStates) { 214 mMobileSignalGroup.addView(state.mMobileGroup); 215 } 216 217 int endPadding = mMobileSignalGroup.getChildCount() > 0 ? mMobileSignalGroupEndPadding : 0; 218 mMobileSignalGroup.setPaddingRelative(0, 0, endPadding, 0); 219 220 TunerService.get(mContext).addTunable(this, StatusBarIconController.ICON_BLACKLIST); 221 222 apply(); 223 applyIconTint(); 224 mNC.addSignalCallback(this); 225 } 226 227 @Override onDetachedFromWindow()228 protected void onDetachedFromWindow() { 229 mMobileSignalGroup.removeAllViews(); 230 TunerService.get(mContext).removeTunable(this); 231 mSC.removeCallback(this); 232 mNC.removeSignalCallback(this); 233 234 super.onDetachedFromWindow(); 235 } 236 237 @Override onLayout(boolean changed, int l, int t, int r, int b)238 protected void onLayout(boolean changed, int l, int t, int r, int b) { 239 super.onLayout(changed, l, t, r, b); 240 241 // Re-run all checks against the tint area for all icons 242 applyIconTint(); 243 } 244 245 // From SecurityController. 246 @Override onStateChanged()247 public void onStateChanged() { 248 post(new Runnable() { 249 @Override 250 public void run() { 251 mVpnVisible = mSC.isVpnEnabled(); 252 apply(); 253 } 254 }); 255 } 256 257 @Override setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon, boolean activityIn, boolean activityOut, String description)258 public void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon, 259 boolean activityIn, boolean activityOut, String description) { 260 mWifiVisible = statusIcon.visible && !mBlockWifi; 261 mWifiStrengthId = statusIcon.icon; 262 mWifiDescription = statusIcon.contentDescription; 263 264 apply(); 265 } 266 267 @Override setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType, int qsType, boolean activityIn, boolean activityOut, String typeContentDescription, String description, boolean isWide, int subId)268 public void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType, 269 int qsType, boolean activityIn, boolean activityOut, String typeContentDescription, 270 String description, boolean isWide, int subId) { 271 PhoneState state = getState(subId); 272 if (state == null) { 273 return; 274 } 275 state.mMobileVisible = statusIcon.visible && !mBlockMobile; 276 state.mMobileStrengthId = statusIcon.icon; 277 state.mMobileTypeId = statusType; 278 state.mMobileDescription = statusIcon.contentDescription; 279 state.mMobileTypeDescription = typeContentDescription; 280 state.mIsMobileTypeIconWide = statusType != 0 && isWide; 281 282 apply(); 283 } 284 285 @Override setEthernetIndicators(IconState state)286 public void setEthernetIndicators(IconState state) { 287 mEthernetVisible = state.visible && !mBlockEthernet; 288 mEthernetIconId = state.icon; 289 mEthernetDescription = state.contentDescription; 290 291 apply(); 292 } 293 294 @Override setNoSims(boolean show)295 public void setNoSims(boolean show) { 296 mNoSimsVisible = show && !mBlockMobile; 297 apply(); 298 } 299 300 @Override setSubs(List<SubscriptionInfo> subs)301 public void setSubs(List<SubscriptionInfo> subs) { 302 if (hasCorrectSubs(subs)) { 303 return; 304 } 305 // Clear out all old subIds. 306 for (PhoneState state : mPhoneStates) { 307 if (state.mMobile != null) { 308 state.maybeStopAnimatableDrawable(state.mMobile); 309 } 310 if (state.mMobileDark != null) { 311 state.maybeStopAnimatableDrawable(state.mMobileDark); 312 } 313 } 314 mPhoneStates.clear(); 315 if (mMobileSignalGroup != null) { 316 mMobileSignalGroup.removeAllViews(); 317 } 318 final int n = subs.size(); 319 for (int i = 0; i < n; i++) { 320 inflatePhoneState(subs.get(i).getSubscriptionId()); 321 } 322 if (isAttachedToWindow()) { 323 applyIconTint(); 324 } 325 } 326 hasCorrectSubs(List<SubscriptionInfo> subs)327 private boolean hasCorrectSubs(List<SubscriptionInfo> subs) { 328 final int N = subs.size(); 329 if (N != mPhoneStates.size()) { 330 return false; 331 } 332 for (int i = 0; i < N; i++) { 333 if (mPhoneStates.get(i).mSubId != subs.get(i).getSubscriptionId()) { 334 return false; 335 } 336 } 337 return true; 338 } 339 getState(int subId)340 private PhoneState getState(int subId) { 341 for (PhoneState state : mPhoneStates) { 342 if (state.mSubId == subId) { 343 return state; 344 } 345 } 346 Log.e(TAG, "Unexpected subscription " + subId); 347 return null; 348 } 349 inflatePhoneState(int subId)350 private PhoneState inflatePhoneState(int subId) { 351 PhoneState state = new PhoneState(subId, mContext); 352 if (mMobileSignalGroup != null) { 353 mMobileSignalGroup.addView(state.mMobileGroup); 354 } 355 mPhoneStates.add(state); 356 return state; 357 } 358 359 @Override setIsAirplaneMode(IconState icon)360 public void setIsAirplaneMode(IconState icon) { 361 mIsAirplaneMode = icon.visible && !mBlockAirplane; 362 mAirplaneIconId = icon.icon; 363 mAirplaneContentDescription = icon.contentDescription; 364 365 apply(); 366 } 367 368 @Override setMobileDataEnabled(boolean enabled)369 public void setMobileDataEnabled(boolean enabled) { 370 // Don't care. 371 } 372 373 @Override dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event)374 public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) { 375 // Standard group layout onPopulateAccessibilityEvent() implementations 376 // ignore content description, so populate manually 377 if (mEthernetVisible && mEthernetGroup != null && 378 mEthernetGroup.getContentDescription() != null) 379 event.getText().add(mEthernetGroup.getContentDescription()); 380 if (mWifiVisible && mWifiGroup != null && mWifiGroup.getContentDescription() != null) 381 event.getText().add(mWifiGroup.getContentDescription()); 382 for (PhoneState state : mPhoneStates) { 383 state.populateAccessibilityEvent(event); 384 } 385 return super.dispatchPopulateAccessibilityEventInternal(event); 386 } 387 388 @Override onRtlPropertiesChanged(int layoutDirection)389 public void onRtlPropertiesChanged(int layoutDirection) { 390 super.onRtlPropertiesChanged(layoutDirection); 391 392 if (mEthernet != null) { 393 mEthernet.setImageDrawable(null); 394 mEthernetDark.setImageDrawable(null); 395 mLastEthernetIconId = -1; 396 } 397 398 if (mWifi != null) { 399 mWifi.setImageDrawable(null); 400 mWifiDark.setImageDrawable(null); 401 mLastWifiStrengthId = -1; 402 } 403 404 for (PhoneState state : mPhoneStates) { 405 if (state.mMobile != null) { 406 state.maybeStopAnimatableDrawable(state.mMobile); 407 state.mMobile.setImageDrawable(null); 408 state.mLastMobileStrengthId = -1; 409 } 410 if (state.mMobileDark != null) { 411 state.maybeStopAnimatableDrawable(state.mMobileDark); 412 state.mMobileDark.setImageDrawable(null); 413 state.mLastMobileStrengthId = -1; 414 } 415 if (state.mMobileType != null) { 416 state.mMobileType.setImageDrawable(null); 417 state.mLastMobileTypeId = -1; 418 } 419 } 420 421 if (mAirplane != null) { 422 mAirplane.setImageDrawable(null); 423 mLastAirplaneIconId = -1; 424 } 425 426 apply(); 427 } 428 429 @Override hasOverlappingRendering()430 public boolean hasOverlappingRendering() { 431 return false; 432 } 433 434 // Run after each indicator change. apply()435 private void apply() { 436 if (mWifiGroup == null) return; 437 438 mVpn.setVisibility(mVpnVisible ? View.VISIBLE : View.GONE); 439 if (DEBUG) Log.d(TAG, String.format("vpn: %s", mVpnVisible ? "VISIBLE" : "GONE")); 440 441 if (mEthernetVisible) { 442 if (mLastEthernetIconId != mEthernetIconId) { 443 setIconForView(mEthernet, mEthernetIconId); 444 setIconForView(mEthernetDark, mEthernetIconId); 445 mLastEthernetIconId = mEthernetIconId; 446 } 447 mEthernetGroup.setContentDescription(mEthernetDescription); 448 mEthernetGroup.setVisibility(View.VISIBLE); 449 } else { 450 mEthernetGroup.setVisibility(View.GONE); 451 } 452 453 if (DEBUG) Log.d(TAG, 454 String.format("ethernet: %s", 455 (mEthernetVisible ? "VISIBLE" : "GONE"))); 456 457 if (mWifiVisible) { 458 if (mWifiStrengthId != mLastWifiStrengthId) { 459 setIconForView(mWifi, mWifiStrengthId); 460 setIconForView(mWifiDark, mWifiStrengthId); 461 mLastWifiStrengthId = mWifiStrengthId; 462 } 463 mWifiGroup.setContentDescription(mWifiDescription); 464 mWifiGroup.setVisibility(View.VISIBLE); 465 } else { 466 mWifiGroup.setVisibility(View.GONE); 467 } 468 469 if (DEBUG) Log.d(TAG, 470 String.format("wifi: %s sig=%d", 471 (mWifiVisible ? "VISIBLE" : "GONE"), 472 mWifiStrengthId)); 473 474 boolean anyMobileVisible = false; 475 int firstMobileTypeId = 0; 476 for (PhoneState state : mPhoneStates) { 477 if (state.apply(anyMobileVisible)) { 478 if (!anyMobileVisible) { 479 firstMobileTypeId = state.mMobileTypeId; 480 anyMobileVisible = true; 481 } 482 } 483 } 484 485 if (mIsAirplaneMode) { 486 if (mLastAirplaneIconId != mAirplaneIconId) { 487 setIconForView(mAirplane, mAirplaneIconId); 488 mLastAirplaneIconId = mAirplaneIconId; 489 } 490 mAirplane.setContentDescription(mAirplaneContentDescription); 491 mAirplane.setVisibility(View.VISIBLE); 492 } else { 493 mAirplane.setVisibility(View.GONE); 494 } 495 496 if (mIsAirplaneMode && mWifiVisible) { 497 mWifiAirplaneSpacer.setVisibility(View.VISIBLE); 498 } else { 499 mWifiAirplaneSpacer.setVisibility(View.GONE); 500 } 501 502 if (((anyMobileVisible && firstMobileTypeId != 0) || mNoSimsVisible) && mWifiVisible) { 503 mWifiSignalSpacer.setVisibility(View.VISIBLE); 504 } else { 505 mWifiSignalSpacer.setVisibility(View.GONE); 506 } 507 508 mNoSimsCombo.setVisibility(mNoSimsVisible ? View.VISIBLE : View.GONE); 509 510 boolean anythingVisible = mNoSimsVisible || mWifiVisible || mIsAirplaneMode 511 || anyMobileVisible || mVpnVisible || mEthernetVisible; 512 setPaddingRelative(0, 0, anythingVisible ? mEndPadding : mEndPaddingNothingVisible, 0); 513 } 514 515 /** 516 * Sets the given drawable id on the view. This method will also scale the icon by 517 * {@link #mIconScaleFactor} if appropriate. 518 */ setIconForView(ImageView imageView, @DrawableRes int iconId)519 private void setIconForView(ImageView imageView, @DrawableRes int iconId) { 520 // Using the imageView's context to retrieve the Drawable so that theme is preserved. 521 Drawable icon = imageView.getContext().getDrawable(iconId); 522 523 if (mIconScaleFactor == 1.f) { 524 imageView.setImageDrawable(icon); 525 } else { 526 imageView.setImageDrawable(new ScalingDrawableWrapper(icon, mIconScaleFactor)); 527 } 528 } 529 setIconTint(int tint, float darkIntensity, Rect tintArea)530 public void setIconTint(int tint, float darkIntensity, Rect tintArea) { 531 boolean changed = tint != mIconTint || darkIntensity != mDarkIntensity 532 || !mTintArea.equals(tintArea); 533 mIconTint = tint; 534 mDarkIntensity = darkIntensity; 535 mTintArea.set(tintArea); 536 if (changed && isAttachedToWindow()) { 537 applyIconTint(); 538 } 539 } 540 applyIconTint()541 private void applyIconTint() { 542 setTint(mVpn, StatusBarIconController.getTint(mTintArea, mVpn, mIconTint)); 543 setTint(mAirplane, StatusBarIconController.getTint(mTintArea, mAirplane, mIconTint)); 544 applyDarkIntensity( 545 StatusBarIconController.getDarkIntensity(mTintArea, mNoSims, mDarkIntensity), 546 mNoSims, mNoSimsDark); 547 applyDarkIntensity( 548 StatusBarIconController.getDarkIntensity(mTintArea, mWifi, mDarkIntensity), 549 mWifi, mWifiDark); 550 applyDarkIntensity( 551 StatusBarIconController.getDarkIntensity(mTintArea, mEthernet, mDarkIntensity), 552 mEthernet, mEthernetDark); 553 for (int i = 0; i < mPhoneStates.size(); i++) { 554 mPhoneStates.get(i).setIconTint(mIconTint, mDarkIntensity, mTintArea); 555 } 556 } 557 applyDarkIntensity(float darkIntensity, View lightIcon, View darkIcon)558 private void applyDarkIntensity(float darkIntensity, View lightIcon, View darkIcon) { 559 lightIcon.setAlpha(1 - darkIntensity); 560 darkIcon.setAlpha(darkIntensity); 561 } 562 setTint(ImageView v, int tint)563 private void setTint(ImageView v, int tint) { 564 v.setImageTintList(ColorStateList.valueOf(tint)); 565 } 566 567 private class PhoneState { 568 private final int mSubId; 569 private boolean mMobileVisible = false; 570 private int mMobileStrengthId = 0, mMobileTypeId = 0; 571 private int mLastMobileStrengthId = -1; 572 private int mLastMobileTypeId = -1; 573 private boolean mIsMobileTypeIconWide; 574 private String mMobileDescription, mMobileTypeDescription; 575 576 private ViewGroup mMobileGroup; 577 private ImageView mMobile, mMobileDark, mMobileType; 578 PhoneState(int subId, Context context)579 public PhoneState(int subId, Context context) { 580 ViewGroup root = (ViewGroup) LayoutInflater.from(context) 581 .inflate(R.layout.mobile_signal_group, null); 582 setViews(root); 583 mSubId = subId; 584 } 585 setViews(ViewGroup root)586 public void setViews(ViewGroup root) { 587 mMobileGroup = root; 588 mMobile = (ImageView) root.findViewById(R.id.mobile_signal); 589 mMobileDark = (ImageView) root.findViewById(R.id.mobile_signal_dark); 590 mMobileType = (ImageView) root.findViewById(R.id.mobile_type); 591 } 592 apply(boolean isSecondaryIcon)593 public boolean apply(boolean isSecondaryIcon) { 594 if (mMobileVisible && !mIsAirplaneMode) { 595 if (mLastMobileStrengthId != mMobileStrengthId) { 596 updateAnimatableIcon(mMobile, mMobileStrengthId); 597 updateAnimatableIcon(mMobileDark, mMobileStrengthId); 598 mLastMobileStrengthId = mMobileStrengthId; 599 } 600 601 if (mLastMobileTypeId != mMobileTypeId) { 602 mMobileType.setImageResource(mMobileTypeId); 603 mLastMobileTypeId = mMobileTypeId; 604 } 605 mMobileGroup.setContentDescription(mMobileTypeDescription 606 + " " + mMobileDescription); 607 mMobileGroup.setVisibility(View.VISIBLE); 608 } else { 609 mMobileGroup.setVisibility(View.GONE); 610 } 611 612 // When this isn't next to wifi, give it some extra padding between the signals. 613 mMobileGroup.setPaddingRelative(isSecondaryIcon ? mSecondaryTelephonyPadding : 0, 614 0, 0, 0); 615 mMobile.setPaddingRelative( 616 mIsMobileTypeIconWide ? mWideTypeIconStartPadding : mMobileDataIconStartPadding, 617 0, 0, 0); 618 mMobileDark.setPaddingRelative( 619 mIsMobileTypeIconWide ? mWideTypeIconStartPadding : mMobileDataIconStartPadding, 620 0, 0, 0); 621 622 if (DEBUG) Log.d(TAG, String.format("mobile: %s sig=%d typ=%d", 623 (mMobileVisible ? "VISIBLE" : "GONE"), mMobileStrengthId, mMobileTypeId)); 624 625 mMobileType.setVisibility(mMobileTypeId != 0 ? View.VISIBLE : View.GONE); 626 627 return mMobileVisible; 628 } 629 updateAnimatableIcon(ImageView view, int resId)630 private void updateAnimatableIcon(ImageView view, int resId) { 631 maybeStopAnimatableDrawable(view); 632 setIconForView(view, resId); 633 maybeStartAnimatableDrawable(view); 634 } 635 maybeStopAnimatableDrawable(ImageView view)636 private void maybeStopAnimatableDrawable(ImageView view) { 637 Drawable drawable = view.getDrawable(); 638 639 // Check if the icon has been scaled. If it has retrieve the actual drawable out of the 640 // wrapper. 641 if (drawable instanceof ScalingDrawableWrapper) { 642 drawable = ((ScalingDrawableWrapper) drawable).getDrawable(); 643 } 644 645 if (drawable instanceof Animatable) { 646 Animatable ad = (Animatable) drawable; 647 if (ad.isRunning()) { 648 ad.stop(); 649 } 650 } 651 } 652 maybeStartAnimatableDrawable(ImageView view)653 private void maybeStartAnimatableDrawable(ImageView view) { 654 Drawable drawable = view.getDrawable(); 655 656 // Check if the icon has been scaled. If it has retrieve the actual drawable out of the 657 // wrapper. 658 if (drawable instanceof ScalingDrawableWrapper) { 659 drawable = ((ScalingDrawableWrapper) drawable).getDrawable(); 660 } 661 662 if (drawable instanceof Animatable) { 663 Animatable ad = (Animatable) drawable; 664 if (ad instanceof AnimatedVectorDrawable) { 665 ((AnimatedVectorDrawable) ad).forceAnimationOnUI(); 666 } 667 if (!ad.isRunning()) { 668 ad.start(); 669 } 670 } 671 } 672 populateAccessibilityEvent(AccessibilityEvent event)673 public void populateAccessibilityEvent(AccessibilityEvent event) { 674 if (mMobileVisible && mMobileGroup != null 675 && mMobileGroup.getContentDescription() != null) { 676 event.getText().add(mMobileGroup.getContentDescription()); 677 } 678 } 679 setIconTint(int tint, float darkIntensity, Rect tintArea)680 public void setIconTint(int tint, float darkIntensity, Rect tintArea) { 681 applyDarkIntensity( 682 StatusBarIconController.getDarkIntensity(tintArea, mMobile, darkIntensity), 683 mMobile, mMobileDark); 684 setTint(mMobileType, StatusBarIconController.getTint(tintArea, mMobileType, tint)); 685 } 686 } 687 } 688 689