OSDN Git Service

DO NOT MERGE. Grant MMS Uri permissions as the calling UID.
[android-x86/frameworks-base.git] / packages / SystemUI / src / com / android / systemui / statusbar / SignalClusterView.java
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 }