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