• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.content.Context;
20 import android.telephony.SubscriptionInfo;
21 import android.util.AttributeSet;
22 import android.util.Log;
23 import android.view.LayoutInflater;
24 import android.view.View;
25 import android.view.ViewGroup;
26 import android.view.accessibility.AccessibilityEvent;
27 import android.widget.ImageView;
28 import android.widget.LinearLayout;
29 
30 import com.android.systemui.R;
31 import com.android.systemui.statusbar.policy.NetworkControllerImpl;
32 import com.android.systemui.statusbar.policy.SecurityController;
33 
34 import java.util.ArrayList;
35 import java.util.List;
36 
37 // Intimately tied to the design of res/layout/signal_cluster_view.xml
38 public class SignalClusterView
39         extends LinearLayout
40         implements NetworkControllerImpl.SignalCluster,
41         SecurityController.SecurityControllerCallback {
42 
43     static final String TAG = "SignalClusterView";
44     static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
45 
46     NetworkControllerImpl mNC;
47     SecurityController mSC;
48 
49     private boolean mNoSimsVisible = false;
50     private boolean mVpnVisible = false;
51     private boolean mWifiVisible = false;
52     private int mWifiStrengthId = 0;
53     private boolean mIsAirplaneMode = false;
54     private int mAirplaneIconId = 0;
55     private int mAirplaneContentDescription;
56     private String mWifiDescription;
57     private ArrayList<PhoneState> mPhoneStates = new ArrayList<PhoneState>();
58 
59     ViewGroup mWifiGroup;
60     ImageView mVpn, mWifi, mAirplane, mNoSims;
61     View mWifiAirplaneSpacer;
62     View mWifiSignalSpacer;
63     LinearLayout mMobileSignalGroup;
64 
65     private int mWideTypeIconStartPadding;
66     private int mSecondaryTelephonyPadding;
67     private int mEndPadding;
68     private int mEndPaddingNothingVisible;
69 
SignalClusterView(Context context)70     public SignalClusterView(Context context) {
71         this(context, null);
72     }
73 
SignalClusterView(Context context, AttributeSet attrs)74     public SignalClusterView(Context context, AttributeSet attrs) {
75         this(context, attrs, 0);
76     }
77 
SignalClusterView(Context context, AttributeSet attrs, int defStyle)78     public SignalClusterView(Context context, AttributeSet attrs, int defStyle) {
79         super(context, attrs, defStyle);
80     }
81 
setNetworkController(NetworkControllerImpl nc)82     public void setNetworkController(NetworkControllerImpl nc) {
83         if (DEBUG) Log.d(TAG, "NetworkController=" + nc);
84         mNC = nc;
85     }
86 
setSecurityController(SecurityController sc)87     public void setSecurityController(SecurityController sc) {
88         if (DEBUG) Log.d(TAG, "SecurityController=" + sc);
89         mSC = sc;
90         mSC.addCallback(this);
91         mVpnVisible = mSC.isVpnEnabled();
92     }
93 
94     @Override
onFinishInflate()95     protected void onFinishInflate() {
96         super.onFinishInflate();
97         mWideTypeIconStartPadding = getContext().getResources().getDimensionPixelSize(
98                 R.dimen.wide_type_icon_start_padding);
99         mSecondaryTelephonyPadding = getContext().getResources().getDimensionPixelSize(
100                 R.dimen.secondary_telephony_padding);
101         mEndPadding = getContext().getResources().getDimensionPixelSize(
102                 R.dimen.signal_cluster_battery_padding);
103         mEndPaddingNothingVisible = getContext().getResources().getDimensionPixelSize(
104                 R.dimen.no_signal_cluster_battery_padding);
105     }
106 
107     @Override
onAttachedToWindow()108     protected void onAttachedToWindow() {
109         super.onAttachedToWindow();
110 
111         mVpn            = (ImageView) findViewById(R.id.vpn);
112         mWifiGroup      = (ViewGroup) findViewById(R.id.wifi_combo);
113         mWifi           = (ImageView) findViewById(R.id.wifi_signal);
114         mAirplane       = (ImageView) findViewById(R.id.airplane);
115         mNoSims         = (ImageView) findViewById(R.id.no_sims);
116         mWifiAirplaneSpacer =         findViewById(R.id.wifi_airplane_spacer);
117         mWifiSignalSpacer =           findViewById(R.id.wifi_signal_spacer);
118         mMobileSignalGroup = (LinearLayout) findViewById(R.id.mobile_signal_group);
119         for (PhoneState state : mPhoneStates) {
120             mMobileSignalGroup.addView(state.mMobileGroup);
121         }
122 
123         apply();
124     }
125 
126     @Override
onDetachedFromWindow()127     protected void onDetachedFromWindow() {
128         mVpn            = null;
129         mWifiGroup      = null;
130         mWifi           = null;
131         mAirplane       = null;
132         mMobileSignalGroup.removeAllViews();
133         mMobileSignalGroup = null;
134 
135         super.onDetachedFromWindow();
136     }
137 
138     // From SecurityController.
139     @Override
onStateChanged()140     public void onStateChanged() {
141         post(new Runnable() {
142             @Override
143             public void run() {
144                 mVpnVisible = mSC.isVpnEnabled();
145                 apply();
146             }
147         });
148     }
149 
150     @Override
setWifiIndicators(boolean visible, int strengthIcon, String contentDescription)151     public void setWifiIndicators(boolean visible, int strengthIcon, String contentDescription) {
152         mWifiVisible = visible;
153         mWifiStrengthId = strengthIcon;
154         mWifiDescription = contentDescription;
155 
156         apply();
157     }
158 
159     @Override
setMobileDataIndicators(boolean visible, int strengthIcon, int typeIcon, String contentDescription, String typeContentDescription, boolean isTypeIconWide, int subId)160     public void setMobileDataIndicators(boolean visible, int strengthIcon, int typeIcon,
161             String contentDescription, String typeContentDescription, boolean isTypeIconWide,
162             int subId) {
163         PhoneState state = getOrInflateState(subId);
164         state.mMobileVisible = visible;
165         state.mMobileStrengthId = strengthIcon;
166         state.mMobileTypeId = typeIcon;
167         state.mMobileDescription = contentDescription;
168         state.mMobileTypeDescription = typeContentDescription;
169         state.mIsMobileTypeIconWide = isTypeIconWide;
170 
171         apply();
172     }
173 
174     @Override
setNoSims(boolean show)175     public void setNoSims(boolean show) {
176         mNoSimsVisible = show;
177     }
178 
179     @Override
setSubs(List<SubscriptionInfo> subs)180     public void setSubs(List<SubscriptionInfo> subs) {
181         // Clear out all old subIds.
182         mPhoneStates.clear();
183         if (mMobileSignalGroup != null) {
184             mMobileSignalGroup.removeAllViews();
185         }
186         final int n = subs.size();
187         for (int i = 0; i < n; i++) {
188             inflatePhoneState(subs.get(i).getSubscriptionId());
189         }
190     }
191 
getOrInflateState(int subId)192     private PhoneState getOrInflateState(int subId) {
193         for (PhoneState state : mPhoneStates) {
194             if (state.mSubId == subId) {
195                 return state;
196             }
197         }
198         return inflatePhoneState(subId);
199     }
200 
inflatePhoneState(int subId)201     private PhoneState inflatePhoneState(int subId) {
202         PhoneState state = new PhoneState(subId, mContext);
203         if (mMobileSignalGroup != null) {
204             mMobileSignalGroup.addView(state.mMobileGroup);
205         }
206         mPhoneStates.add(state);
207         return state;
208     }
209 
210     @Override
setIsAirplaneMode(boolean is, int airplaneIconId, int contentDescription)211     public void setIsAirplaneMode(boolean is, int airplaneIconId, int contentDescription) {
212         mIsAirplaneMode = is;
213         mAirplaneIconId = airplaneIconId;
214         mAirplaneContentDescription = contentDescription;
215 
216         apply();
217     }
218 
219     @Override
dispatchPopulateAccessibilityEvent(AccessibilityEvent event)220     public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
221         // Standard group layout onPopulateAccessibilityEvent() implementations
222         // ignore content description, so populate manually
223         if (mWifiVisible && mWifiGroup != null && mWifiGroup.getContentDescription() != null)
224             event.getText().add(mWifiGroup.getContentDescription());
225         for (PhoneState state : mPhoneStates) {
226             state.populateAccessibilityEvent(event);
227         }
228         return super.dispatchPopulateAccessibilityEvent(event);
229     }
230 
231     @Override
onRtlPropertiesChanged(int layoutDirection)232     public void onRtlPropertiesChanged(int layoutDirection) {
233         super.onRtlPropertiesChanged(layoutDirection);
234 
235         if (mWifi != null) {
236             mWifi.setImageDrawable(null);
237         }
238 
239         for (PhoneState state : mPhoneStates) {
240             if (state.mMobile != null) {
241                 state.mMobile.setImageDrawable(null);
242             }
243             if (state.mMobileType != null) {
244                 state.mMobileType.setImageDrawable(null);
245             }
246         }
247 
248         if(mAirplane != null) {
249             mAirplane.setImageDrawable(null);
250         }
251 
252         apply();
253     }
254 
255     @Override
hasOverlappingRendering()256     public boolean hasOverlappingRendering() {
257         return false;
258     }
259 
260     // Run after each indicator change.
apply()261     private void apply() {
262         if (mWifiGroup == null) return;
263 
264         mVpn.setVisibility(mVpnVisible ? View.VISIBLE : View.GONE);
265         if (DEBUG) Log.d(TAG, String.format("vpn: %s", mVpnVisible ? "VISIBLE" : "GONE"));
266         if (mWifiVisible) {
267             mWifi.setImageResource(mWifiStrengthId);
268             mWifiGroup.setContentDescription(mWifiDescription);
269             mWifiGroup.setVisibility(View.VISIBLE);
270         } else {
271             mWifiGroup.setVisibility(View.GONE);
272         }
273 
274         if (DEBUG) Log.d(TAG,
275                 String.format("wifi: %s sig=%d",
276                     (mWifiVisible ? "VISIBLE" : "GONE"),
277                     mWifiStrengthId));
278 
279         boolean anyMobileVisible = false;
280         int firstMobileTypeId = 0;
281         for (PhoneState state : mPhoneStates) {
282             if (state.apply(anyMobileVisible)) {
283                 if (!anyMobileVisible) {
284                     firstMobileTypeId = state.mMobileTypeId;
285                     anyMobileVisible = true;
286                 }
287             }
288         }
289 
290         if (mIsAirplaneMode) {
291             mAirplane.setImageResource(mAirplaneIconId);
292             mAirplane.setContentDescription(mAirplaneContentDescription != 0 ?
293                     mContext.getString(mAirplaneContentDescription) : null);
294             mAirplane.setVisibility(View.VISIBLE);
295         } else {
296             mAirplane.setVisibility(View.GONE);
297         }
298 
299         if (mIsAirplaneMode && mWifiVisible) {
300             mWifiAirplaneSpacer.setVisibility(View.VISIBLE);
301         } else {
302             mWifiAirplaneSpacer.setVisibility(View.GONE);
303         }
304 
305         if (((anyMobileVisible && firstMobileTypeId != 0) || mNoSimsVisible) && mWifiVisible) {
306             mWifiSignalSpacer.setVisibility(View.VISIBLE);
307         } else {
308             mWifiSignalSpacer.setVisibility(View.GONE);
309         }
310 
311         mNoSims.setVisibility(mNoSimsVisible ? View.VISIBLE : View.GONE);
312 
313         boolean anythingVisible = mNoSimsVisible || mWifiVisible || mIsAirplaneMode
314                 || anyMobileVisible || mVpnVisible;
315         setPaddingRelative(0, 0, anythingVisible ? mEndPadding : mEndPaddingNothingVisible, 0);
316     }
317 
318     private class PhoneState {
319         private final int mSubId;
320         private boolean mMobileVisible = false;
321         private int mMobileStrengthId = 0, mMobileTypeId = 0;
322         private boolean mIsMobileTypeIconWide;
323         private String mMobileDescription, mMobileTypeDescription;
324 
325         private ViewGroup mMobileGroup;
326         private ImageView mMobile, mMobileType;
327 
PhoneState(int subId, Context context)328         public PhoneState(int subId, Context context) {
329             ViewGroup root = (ViewGroup) LayoutInflater.from(context)
330                     .inflate(R.layout.mobile_signal_group, null);
331             setViews(root);
332             mSubId = subId;
333         }
334 
setViews(ViewGroup root)335         public void setViews(ViewGroup root) {
336             mMobileGroup    = root;
337             mMobile         = (ImageView) root.findViewById(R.id.mobile_signal);
338             mMobileType     = (ImageView) root.findViewById(R.id.mobile_type);
339         }
340 
apply(boolean isSecondaryIcon)341         public boolean apply(boolean isSecondaryIcon) {
342             if (mMobileVisible && !mIsAirplaneMode) {
343                 mMobile.setImageResource(mMobileStrengthId);
344                 mMobileType.setImageResource(mMobileTypeId);
345                 mMobileGroup.setContentDescription(mMobileTypeDescription
346                         + " " + mMobileDescription);
347                 mMobileGroup.setVisibility(View.VISIBLE);
348             } else {
349                 mMobileGroup.setVisibility(View.GONE);
350             }
351 
352             // When this isn't next to wifi, give it some extra padding between the signals.
353             mMobileGroup.setPaddingRelative(isSecondaryIcon ? mSecondaryTelephonyPadding : 0,
354                     0, 0, 0);
355             mMobile.setPaddingRelative(mIsMobileTypeIconWide ? mWideTypeIconStartPadding : 0,
356                     0, 0, 0);
357 
358             if (DEBUG) Log.d(TAG, String.format("mobile: %s sig=%d typ=%d",
359                         (mMobileVisible ? "VISIBLE" : "GONE"), mMobileStrengthId, mMobileTypeId));
360 
361             mMobileType.setVisibility(mMobileTypeId != 0 ? View.VISIBLE : View.GONE);
362 
363             return mMobileVisible;
364         }
365 
populateAccessibilityEvent(AccessibilityEvent event)366         public void populateAccessibilityEvent(AccessibilityEvent event) {
367             if (mMobileVisible && mMobileGroup != null
368                     && mMobileGroup.getContentDescription() != null) {
369                 event.getText().add(mMobileGroup.getContentDescription());
370             }
371         }
372     }
373 }
374 
375