• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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.phone;
18 
19 import android.content.Context;
20 import android.os.Handler;
21 import android.telephony.SubscriptionInfo;
22 import android.util.ArraySet;
23 import android.util.Log;
24 
25 import com.android.systemui.Dependency;
26 import com.android.systemui.R;
27 import com.android.systemui.statusbar.policy.NetworkController;
28 import com.android.systemui.statusbar.policy.NetworkController.IconState;
29 import com.android.systemui.statusbar.policy.NetworkControllerImpl;
30 import com.android.systemui.statusbar.policy.SecurityController;
31 import com.android.systemui.tuner.TunerService;
32 import com.android.systemui.tuner.TunerService.Tunable;
33 
34 import java.util.ArrayList;
35 import java.util.List;
36 import java.util.Objects;
37 
38 
39 public class StatusBarSignalPolicy implements NetworkControllerImpl.SignalCallback,
40         SecurityController.SecurityControllerCallback, Tunable {
41     private static final String TAG = "StatusBarSignalPolicy";
42 
43     private final String mSlotAirplane;
44     private final String mSlotMobile;
45     private final String mSlotWifi;
46     private final String mSlotEthernet;
47     private final String mSlotVpn;
48 
49     private final Context mContext;
50     private final StatusBarIconController mIconController;
51     private final NetworkController mNetworkController;
52     private final SecurityController mSecurityController;
53     private final Handler mHandler = Handler.getMain();
54 
55     private boolean mBlockAirplane;
56     private boolean mBlockMobile;
57     private boolean mBlockWifi;
58     private boolean mBlockEthernet;
59     private boolean mActivityEnabled;
60     private boolean mForceBlockWifi;
61 
62     // Track as little state as possible, and only for padding purposes
63     private boolean mIsAirplaneMode = false;
64     private boolean mWifiVisible = false;
65 
66     private ArrayList<MobileIconState> mMobileStates = new ArrayList<MobileIconState>();
67     private WifiIconState mWifiIconState = new WifiIconState();
68 
StatusBarSignalPolicy(Context context, StatusBarIconController iconController)69     public StatusBarSignalPolicy(Context context, StatusBarIconController iconController) {
70         mContext = context;
71 
72         mSlotAirplane = mContext.getString(com.android.internal.R.string.status_bar_airplane);
73         mSlotMobile   = mContext.getString(com.android.internal.R.string.status_bar_mobile);
74         mSlotWifi     = mContext.getString(com.android.internal.R.string.status_bar_wifi);
75         mSlotEthernet = mContext.getString(com.android.internal.R.string.status_bar_ethernet);
76         mSlotVpn      = mContext.getString(com.android.internal.R.string.status_bar_vpn);
77         mActivityEnabled = mContext.getResources().getBoolean(R.bool.config_showActivity);
78 
79         mIconController = iconController;
80         mNetworkController = Dependency.get(NetworkController.class);
81         mSecurityController = Dependency.get(SecurityController.class);
82 
83         Dependency.get(TunerService.class).addTunable(this, StatusBarIconController.ICON_BLACKLIST);
84         mNetworkController.addCallback(this);
85         mSecurityController.addCallback(this);
86     }
87 
destroy()88     public void destroy() {
89         Dependency.get(TunerService.class).removeTunable(this);
90         mNetworkController.removeCallback(this);
91         mSecurityController.removeCallback(this);
92     }
93 
updateVpn()94     private void updateVpn() {
95         boolean vpnVisible = mSecurityController.isVpnEnabled();
96         int vpnIconId = currentVpnIconId(mSecurityController.isVpnBranded());
97 
98         mIconController.setIcon(mSlotVpn, vpnIconId,
99                 mContext.getResources().getString(R.string.accessibility_vpn_on));
100         mIconController.setIconVisibility(mSlotVpn, vpnVisible);
101     }
102 
currentVpnIconId(boolean isBranded)103     private int currentVpnIconId(boolean isBranded) {
104         return isBranded ? R.drawable.stat_sys_branded_vpn : R.drawable.stat_sys_vpn_ic;
105     }
106 
107     /**
108      * From SecurityController
109      */
110     @Override
onStateChanged()111     public void onStateChanged() {
112         mHandler.post(this::updateVpn);
113     }
114 
115     @Override
onTuningChanged(String key, String newValue)116     public void onTuningChanged(String key, String newValue) {
117         if (!StatusBarIconController.ICON_BLACKLIST.equals(key)) {
118             return;
119         }
120         ArraySet<String> blockList = StatusBarIconController.getIconBlacklist(newValue);
121         boolean blockAirplane = blockList.contains(mSlotAirplane);
122         boolean blockMobile = blockList.contains(mSlotMobile);
123         boolean blockWifi = blockList.contains(mSlotWifi);
124         boolean blockEthernet = blockList.contains(mSlotEthernet);
125 
126         if (blockAirplane != mBlockAirplane || blockMobile != mBlockMobile
127                 || blockEthernet != mBlockEthernet || blockWifi != mBlockWifi) {
128             mBlockAirplane = blockAirplane;
129             mBlockMobile = blockMobile;
130             mBlockEthernet = blockEthernet;
131             mBlockWifi = blockWifi || mForceBlockWifi;
132             // Re-register to get new callbacks.
133             mNetworkController.removeCallback(this);
134             mNetworkController.addCallback(this);
135         }
136     }
137 
138     @Override
setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon, boolean activityIn, boolean activityOut, String description, boolean isTransient, String statusLabel)139     public void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon,
140             boolean activityIn, boolean activityOut, String description, boolean isTransient,
141             String statusLabel) {
142 
143         boolean visible = statusIcon.visible && !mBlockWifi;
144         boolean in = activityIn && mActivityEnabled && visible;
145         boolean out = activityOut && mActivityEnabled && visible;
146 
147         WifiIconState newState = mWifiIconState.copy();
148 
149         newState.visible = visible;
150         newState.resId = statusIcon.icon;
151         newState.activityIn = in;
152         newState.activityOut = out;
153         newState.slot = mSlotWifi;
154         newState.airplaneSpacerVisible = mIsAirplaneMode;
155         newState.contentDescription = statusIcon.contentDescription;
156 
157         MobileIconState first = getFirstMobileState();
158         newState.signalSpacerVisible = first != null && first.typeId != 0;
159 
160         updateWifiIconWithState(newState);
161         mWifiIconState = newState;
162     }
163 
updateShowWifiSignalSpacer(WifiIconState state)164     private void updateShowWifiSignalSpacer(WifiIconState state) {
165         MobileIconState first = getFirstMobileState();
166         state.signalSpacerVisible = first != null && first.typeId != 0;
167     }
168 
updateWifiIconWithState(WifiIconState state)169     private void updateWifiIconWithState(WifiIconState state) {
170         if (state.visible && state.resId > 0) {
171             mIconController.setSignalIcon(mSlotWifi, state);
172             mIconController.setIconVisibility(mSlotWifi, true);
173         } else {
174             mIconController.setIconVisibility(mSlotWifi, false);
175         }
176     }
177 
178     @Override
setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType, int qsType, boolean activityIn, boolean activityOut, String typeContentDescription, String description, boolean isWide, int subId, boolean roaming)179     public void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType,
180             int qsType, boolean activityIn, boolean activityOut, String typeContentDescription,
181             String description, boolean isWide, int subId, boolean roaming) {
182         MobileIconState state = getState(subId);
183         if (state == null) {
184             return;
185         }
186 
187         // Visibility of the data type indicator changed
188         boolean typeChanged = statusType != state.typeId && (statusType == 0 || state.typeId == 0);
189 
190         state.visible = statusIcon.visible && !mBlockMobile;
191         state.strengthId = statusIcon.icon;
192         state.typeId = statusType;
193         state.contentDescription = statusIcon.contentDescription;
194         state.typeContentDescription = typeContentDescription;
195         state.roaming = roaming;
196         state.activityIn = activityIn && mActivityEnabled;
197         state.activityOut = activityOut && mActivityEnabled;
198 
199         // Always send a copy to maintain value type semantics
200         mIconController.setMobileIcons(mSlotMobile, MobileIconState.copyStates(mMobileStates));
201 
202         if (typeChanged) {
203             WifiIconState wifiCopy = mWifiIconState.copy();
204             updateShowWifiSignalSpacer(wifiCopy);
205             if (!Objects.equals(wifiCopy, mWifiIconState)) {
206                 updateWifiIconWithState(wifiCopy);
207                 mWifiIconState = wifiCopy;
208             }
209         }
210     }
211 
getState(int subId)212     private MobileIconState getState(int subId) {
213         for (MobileIconState state : mMobileStates) {
214             if (state.subId == subId) {
215                 return state;
216             }
217         }
218         Log.e(TAG, "Unexpected subscription " + subId);
219         return null;
220     }
221 
getFirstMobileState()222     private MobileIconState getFirstMobileState() {
223         if (mMobileStates.size() > 0) {
224             return mMobileStates.get(0);
225         }
226 
227         return null;
228     }
229 
230 
231     /**
232      * It is expected that a call to setSubs will be immediately followed by setMobileDataIndicators
233      * so we don't have to update the icon manager at this point, just remove the old ones
234      * @param subs list of mobile subscriptions, displayed as mobile data indicators (max 8)
235      */
236     @Override
setSubs(List<SubscriptionInfo> subs)237     public void setSubs(List<SubscriptionInfo> subs) {
238         if (hasCorrectSubs(subs)) {
239             return;
240         }
241 
242         mIconController.removeAllIconsForSlot(mSlotMobile);
243         mMobileStates.clear();
244         final int n = subs.size();
245         for (int i = 0; i < n; i++) {
246             mMobileStates.add(new MobileIconState(subs.get(i).getSubscriptionId()));
247         }
248     }
249 
hasCorrectSubs(List<SubscriptionInfo> subs)250     private boolean hasCorrectSubs(List<SubscriptionInfo> subs) {
251         final int N = subs.size();
252         if (N != mMobileStates.size()) {
253             return false;
254         }
255         for (int i = 0; i < N; i++) {
256             if (mMobileStates.get(i).subId != subs.get(i).getSubscriptionId()) {
257                 return false;
258             }
259         }
260         return true;
261     }
262 
263     @Override
setNoSims(boolean show, boolean simDetected)264     public void setNoSims(boolean show, boolean simDetected) {
265         // Noop yay!
266     }
267 
268 
269     @Override
setEthernetIndicators(IconState state)270     public void setEthernetIndicators(IconState state) {
271         boolean visible = state.visible && !mBlockEthernet;
272         int resId = state.icon;
273         String description = state.contentDescription;
274 
275         if (resId > 0) {
276             mIconController.setIcon(mSlotEthernet, resId, description);
277             mIconController.setIconVisibility(mSlotEthernet, true);
278         } else {
279             mIconController.setIconVisibility(mSlotEthernet, false);
280         }
281     }
282 
283     @Override
setIsAirplaneMode(IconState icon)284     public void setIsAirplaneMode(IconState icon) {
285         mIsAirplaneMode = icon.visible && !mBlockAirplane;
286         int resId = icon.icon;
287         String description = icon.contentDescription;
288 
289         if (mIsAirplaneMode && resId > 0) {
290             mIconController.setIcon(mSlotAirplane, resId, description);
291             mIconController.setIconVisibility(mSlotAirplane, true);
292         } else {
293             mIconController.setIconVisibility(mSlotAirplane, false);
294         }
295     }
296 
297     @Override
setMobileDataEnabled(boolean enabled)298     public void setMobileDataEnabled(boolean enabled) {
299         // Don't care.
300     }
301 
302     private static abstract class SignalIconState {
303         public boolean visible;
304         public boolean activityOut;
305         public boolean activityIn;
306         public String slot;
307         public String contentDescription;
308 
309         @Override
equals(Object o)310         public boolean equals(Object o) {
311             // Skipping reference equality bc this should be more of a value type
312             if (o == null || getClass() != o.getClass()) {
313                 return false;
314             }
315             SignalIconState that = (SignalIconState) o;
316             return visible == that.visible &&
317                     activityOut == that.activityOut &&
318                     activityIn == that.activityIn &&
319                     Objects.equals(contentDescription, that.contentDescription) &&
320                     Objects.equals(slot, that.slot);
321         }
322 
323         @Override
hashCode()324         public int hashCode() {
325             return Objects.hash(visible, activityOut, slot);
326         }
327 
copyTo(SignalIconState other)328         protected void copyTo(SignalIconState other) {
329             other.visible = visible;
330             other.activityIn = activityIn;
331             other.activityOut = activityOut;
332             other.slot = slot;
333             other.contentDescription = contentDescription;
334         }
335     }
336 
337     public static class WifiIconState extends SignalIconState{
338         public int resId;
339         public boolean airplaneSpacerVisible;
340         public boolean signalSpacerVisible;
341 
342         @Override
equals(Object o)343         public boolean equals(Object o) {
344             // Skipping reference equality bc this should be more of a value type
345             if (o == null || getClass() != o.getClass()) {
346                 return false;
347             }
348             if (!super.equals(o)) {
349                 return false;
350             }
351             WifiIconState that = (WifiIconState) o;
352             return resId == that.resId &&
353                     airplaneSpacerVisible == that.airplaneSpacerVisible &&
354                     signalSpacerVisible == that.signalSpacerVisible;
355         }
356 
copyTo(WifiIconState other)357         public void copyTo(WifiIconState other) {
358             super.copyTo(other);
359             other.resId = resId;
360             other.airplaneSpacerVisible = airplaneSpacerVisible;
361             other.signalSpacerVisible = signalSpacerVisible;
362         }
363 
copy()364         public WifiIconState copy() {
365             WifiIconState newState = new WifiIconState();
366             copyTo(newState);
367             return newState;
368         }
369 
370         @Override
hashCode()371         public int hashCode() {
372             return Objects.hash(super.hashCode(),
373                     resId, airplaneSpacerVisible, signalSpacerVisible);
374         }
375 
toString()376         @Override public String toString() {
377             return "WifiIconState(resId=" + resId + ", visible=" + visible + ")";
378         }
379     }
380 
381     /**
382      * A little different. This one delegates to SignalDrawable instead of a specific resId
383      */
384     public static class MobileIconState extends SignalIconState {
385         public int subId;
386         public int strengthId;
387         public int typeId;
388         public boolean roaming;
389         public boolean needsLeadingPadding;
390         public String typeContentDescription;
391 
MobileIconState(int subId)392         private MobileIconState(int subId) {
393             super();
394             this.subId = subId;
395         }
396 
397         @Override
equals(Object o)398         public boolean equals(Object o) {
399             if (o == null || getClass() != o.getClass()) {
400                 return false;
401             }
402             if (!super.equals(o)) {
403                 return false;
404             }
405             MobileIconState that = (MobileIconState) o;
406             return subId == that.subId &&
407                     strengthId == that.strengthId &&
408                     typeId == that.typeId &&
409                     roaming == that.roaming &&
410                     needsLeadingPadding == that.needsLeadingPadding &&
411                     Objects.equals(typeContentDescription, that.typeContentDescription);
412         }
413 
414         @Override
hashCode()415         public int hashCode() {
416 
417             return Objects
418                     .hash(super.hashCode(), subId, strengthId, typeId, roaming, needsLeadingPadding,
419                             typeContentDescription);
420         }
421 
copy()422         public MobileIconState copy() {
423             MobileIconState copy = new MobileIconState(this.subId);
424             copyTo(copy);
425             return copy;
426         }
427 
copyTo(MobileIconState other)428         public void copyTo(MobileIconState other) {
429             super.copyTo(other);
430             other.subId = subId;
431             other.strengthId = strengthId;
432             other.typeId = typeId;
433             other.roaming = roaming;
434             other.needsLeadingPadding = needsLeadingPadding;
435             other.typeContentDescription = typeContentDescription;
436         }
437 
copyStates(List<MobileIconState> inStates)438         private static List<MobileIconState> copyStates(List<MobileIconState> inStates) {
439             ArrayList<MobileIconState> outStates = new ArrayList<>();
440             for (MobileIconState state : inStates) {
441                 MobileIconState copy = new MobileIconState(state.subId);
442                 state.copyTo(copy);
443                 outStates.add(copy);
444             }
445 
446             return outStates;
447         }
448 
toString()449         @Override public String toString() {
450             return "MobileIconState(subId=" + subId + ", strengthId=" + strengthId + ", roaming="
451                     + roaming + ", typeId=" + typeId + ", visible=" + visible + ")";
452         }
453     }
454 }
455