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