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 17package com.android.systemui.statusbar; 18 19import android.annotation.DrawableRes; 20import android.content.Context; 21import android.content.res.ColorStateList; 22import android.content.res.Resources; 23import android.graphics.Color; 24import android.graphics.Rect; 25import android.graphics.drawable.Animatable; 26import android.graphics.drawable.AnimatedVectorDrawable; 27import android.graphics.drawable.Drawable; 28import android.telephony.SubscriptionInfo; 29import android.util.ArraySet; 30import android.util.AttributeSet; 31import android.util.Log; 32import android.util.TypedValue; 33import android.view.LayoutInflater; 34import android.view.View; 35import android.view.ViewGroup; 36import android.view.accessibility.AccessibilityEvent; 37import android.widget.ImageView; 38import android.widget.LinearLayout; 39 40import com.android.systemui.R; 41import com.android.systemui.statusbar.phone.StatusBarIconController; 42import com.android.systemui.statusbar.policy.NetworkController.IconState; 43import com.android.systemui.statusbar.policy.NetworkControllerImpl; 44import com.android.systemui.statusbar.policy.SecurityController; 45import com.android.systemui.tuner.TunerService; 46import com.android.systemui.tuner.TunerService.Tunable; 47 48import java.util.ArrayList; 49import java.util.List; 50 51// Intimately tied to the design of res/layout/signal_cluster_view.xml 52public 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 107 public SignalClusterView(Context context) { 108 this(context, null); 109 } 110 111 public SignalClusterView(Context context, AttributeSet attrs) { 112 this(context, attrs, 0); 113 } 114 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 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 157 public void setNetworkController(NetworkControllerImpl nc) { 158 if (DEBUG) Log.d(TAG, "NetworkController=" + nc); 159 mNC = nc; 160 } 161 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 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 */ 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 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 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 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 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 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 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 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 295 public void setNoSims(boolean show) { 296 mNoSimsVisible = show && !mBlockMobile; 297 apply(); 298 } 299 300 @Override 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 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 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 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 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 369 public void setMobileDataEnabled(boolean enabled) { 370 // Don't care. 371 } 372 373 @Override 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 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 430 public boolean hasOverlappingRendering() { 431 return false; 432 } 433 434 // Run after each indicator change. 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 */ 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 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 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 558 private void applyDarkIntensity(float darkIntensity, View lightIcon, View darkIcon) { 559 lightIcon.setAlpha(1 - darkIntensity); 560 darkIcon.setAlpha(darkIntensity); 561 } 562 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 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 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 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 630 private void updateAnimatableIcon(ImageView view, int resId) { 631 maybeStopAnimatableDrawable(view); 632 setIconForView(view, resId); 633 maybeStartAnimatableDrawable(view); 634 } 635 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 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 673 public void populateAccessibilityEvent(AccessibilityEvent event) { 674 if (mMobileVisible && mMobileGroup != null 675 && mMobileGroup.getContentDescription() != null) { 676 event.getText().add(mMobileGroup.getContentDescription()); 677 } 678 } 679 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