blob: 4531fbdf6f296ef2fea32b939850068f73ed043f [file] [log] [blame]
Evan Lairde1d13c92018-03-20 16:58:01 -04001/*
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
17package com.android.systemui.statusbar.phone;
18
19import android.content.Context;
Evan Lairde1d13c92018-03-20 16:58:01 -040020import android.os.Handler;
Evan Lairde1d13c92018-03-20 16:58:01 -040021import android.telephony.SubscriptionInfo;
22import android.util.ArraySet;
23import android.util.Log;
Gus Prevasab336792018-11-14 13:52:20 -050024
Evan Lairde1d13c92018-03-20 16:58:01 -040025import com.android.systemui.Dependency;
26import com.android.systemui.R;
Evan Lairde1d13c92018-03-20 16:58:01 -040027import com.android.systemui.statusbar.policy.NetworkController;
28import com.android.systemui.statusbar.policy.NetworkController.IconState;
29import com.android.systemui.statusbar.policy.NetworkControllerImpl;
30import com.android.systemui.statusbar.policy.SecurityController;
Luca Stefani4e411422018-08-31 22:05:08 +020031import com.android.systemui.tuner.TunerService;
Evan Lairde1d13c92018-03-20 16:58:01 -040032import com.android.systemui.tuner.TunerService.Tunable;
Gus Prevasab336792018-11-14 13:52:20 -050033
Evan Lairde1d13c92018-03-20 16:58:01 -040034import java.util.ArrayList;
35import java.util.List;
36import java.util.Objects;
37
38
39public 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
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);
Evan Laird6fd04172018-04-23 11:37:04 -040077 mActivityEnabled = mContext.getResources().getBoolean(R.bool.config_showActivity);
Evan Lairde1d13c92018-03-20 16:58:01 -040078
79 mIconController = iconController;
80 mNetworkController = Dependency.get(NetworkController.class);
81 mSecurityController = Dependency.get(SecurityController.class);
82
Luca Stefani4e411422018-08-31 22:05:08 +020083 Dependency.get(TunerService.class).addTunable(this, StatusBarIconController.ICON_BLACKLIST);
Evan Lairde1d13c92018-03-20 16:58:01 -040084 mNetworkController.addCallback(this);
85 mSecurityController.addCallback(this);
86 }
87
88 public void destroy() {
Luca Stefani4e411422018-08-31 22:05:08 +020089 Dependency.get(TunerService.class).removeTunable(this);
Evan Lairde1d13c92018-03-20 16:58:01 -040090 mNetworkController.removeCallback(this);
91 mSecurityController.removeCallback(this);
92 }
93
94 private void updateVpn() {
95 boolean vpnVisible = mSecurityController.isVpnEnabled();
96 int vpnIconId = currentVpnIconId(mSecurityController.isVpnBranded());
97
Evan Lairdc5b79d92018-10-29 14:08:14 -040098 mIconController.setIcon(mSlotVpn, vpnIconId,
99 mContext.getResources().getString(R.string.accessibility_vpn_on));
Evan Lairde1d13c92018-03-20 16:58:01 -0400100 mIconController.setIconVisibility(mSlotVpn, vpnVisible);
101 }
102
103 private int currentVpnIconId(boolean isBranded) {
104 return isBranded ? R.drawable.stat_sys_branded_vpn : R.drawable.stat_sys_vpn_ic;
105 }
106
Evan Lairde1d13c92018-03-20 16:58:01 -0400107 /**
108 * From SecurityController
109 */
110 @Override
111 public void onStateChanged() {
112 mHandler.post(this::updateVpn);
113 }
114
115 @Override
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);
Luca Stefani4e411422018-08-31 22:05:08 +0200134 mNetworkController.addCallback(this);
Evan Lairde1d13c92018-03-20 16:58:01 -0400135 }
136 }
137
138 @Override
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
Evan Lairdaf56a332018-05-23 19:52:34 -0400147 WifiIconState newState = mWifiIconState.copy();
Evan Lairde1d13c92018-03-20 16:58:01 -0400148
Evan Lairdaf56a332018-05-23 19:52:34 -0400149 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
164 private void updateShowWifiSignalSpacer(WifiIconState state) {
165 MobileIconState first = getFirstMobileState();
166 state.signalSpacerVisible = first != null && first.typeId != 0;
167 }
168
169 private void updateWifiIconWithState(WifiIconState state) {
170 if (state.visible && state.resId > 0) {
171 mIconController.setSignalIcon(mSlotWifi, state);
Evan Lairde1d13c92018-03-20 16:58:01 -0400172 mIconController.setIconVisibility(mSlotWifi, true);
173 } else {
174 mIconController.setIconVisibility(mSlotWifi, false);
175 }
176 }
177
178 @Override
179 public void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType,
Evan Laird83c87e52019-09-24 19:14:05 -0400180 int qsType, boolean activityIn, boolean activityOut,
181 CharSequence typeContentDescription,
182 CharSequence typeContentDescriptionHtml, CharSequence description,
183 boolean isWide, int subId, boolean roaming) {
Evan Lairde1d13c92018-03-20 16:58:01 -0400184 MobileIconState state = getState(subId);
185 if (state == null) {
186 return;
187 }
188
Evan Lairdaf56a332018-05-23 19:52:34 -0400189 // Visibility of the data type indicator changed
190 boolean typeChanged = statusType != state.typeId && (statusType == 0 || state.typeId == 0);
Amin Shaikh4c53c8a2019-06-06 18:22:07 +0000191
192 state.visible = statusIcon.visible && !mBlockMobile;
Evan Lairde1d13c92018-03-20 16:58:01 -0400193 state.strengthId = statusIcon.icon;
194 state.typeId = statusType;
195 state.contentDescription = statusIcon.contentDescription;
196 state.typeContentDescription = typeContentDescription;
197 state.roaming = roaming;
198 state.activityIn = activityIn && mActivityEnabled;
199 state.activityOut = activityOut && mActivityEnabled;
200
201 // Always send a copy to maintain value type semantics
202 mIconController.setMobileIcons(mSlotMobile, MobileIconState.copyStates(mMobileStates));
Evan Lairdaf56a332018-05-23 19:52:34 -0400203
204 if (typeChanged) {
205 WifiIconState wifiCopy = mWifiIconState.copy();
206 updateShowWifiSignalSpacer(wifiCopy);
207 if (!Objects.equals(wifiCopy, mWifiIconState)) {
208 updateWifiIconWithState(wifiCopy);
209 mWifiIconState = wifiCopy;
210 }
211 }
Evan Lairde1d13c92018-03-20 16:58:01 -0400212 }
213
214 private MobileIconState getState(int subId) {
215 for (MobileIconState state : mMobileStates) {
216 if (state.subId == subId) {
217 return state;
218 }
219 }
220 Log.e(TAG, "Unexpected subscription " + subId);
221 return null;
222 }
223
Evan Lairdaf56a332018-05-23 19:52:34 -0400224 private MobileIconState getFirstMobileState() {
225 if (mMobileStates.size() > 0) {
226 return mMobileStates.get(0);
227 }
228
229 return null;
230 }
231
Evan Lairde1d13c92018-03-20 16:58:01 -0400232
233 /**
234 * It is expected that a call to setSubs will be immediately followed by setMobileDataIndicators
235 * so we don't have to update the icon manager at this point, just remove the old ones
236 * @param subs list of mobile subscriptions, displayed as mobile data indicators (max 8)
237 */
238 @Override
239 public void setSubs(List<SubscriptionInfo> subs) {
240 if (hasCorrectSubs(subs)) {
241 return;
242 }
243
244 mIconController.removeAllIconsForSlot(mSlotMobile);
245 mMobileStates.clear();
246 final int n = subs.size();
247 for (int i = 0; i < n; i++) {
248 mMobileStates.add(new MobileIconState(subs.get(i).getSubscriptionId()));
249 }
250 }
251
252 private boolean hasCorrectSubs(List<SubscriptionInfo> subs) {
253 final int N = subs.size();
254 if (N != mMobileStates.size()) {
255 return false;
256 }
257 for (int i = 0; i < N; i++) {
258 if (mMobileStates.get(i).subId != subs.get(i).getSubscriptionId()) {
259 return false;
260 }
261 }
262 return true;
263 }
264
265 @Override
266 public void setNoSims(boolean show, boolean simDetected) {
267 // Noop yay!
268 }
269
270
271 @Override
272 public void setEthernetIndicators(IconState state) {
273 boolean visible = state.visible && !mBlockEthernet;
274 int resId = state.icon;
275 String description = state.contentDescription;
276
277 if (resId > 0) {
278 mIconController.setIcon(mSlotEthernet, resId, description);
279 mIconController.setIconVisibility(mSlotEthernet, true);
280 } else {
281 mIconController.setIconVisibility(mSlotEthernet, false);
282 }
283 }
284
285 @Override
286 public void setIsAirplaneMode(IconState icon) {
287 mIsAirplaneMode = icon.visible && !mBlockAirplane;
288 int resId = icon.icon;
289 String description = icon.contentDescription;
290
291 if (mIsAirplaneMode && resId > 0) {
292 mIconController.setIcon(mSlotAirplane, resId, description);
293 mIconController.setIconVisibility(mSlotAirplane, true);
294 } else {
295 mIconController.setIconVisibility(mSlotAirplane, false);
296 }
297 }
298
299 @Override
300 public void setMobileDataEnabled(boolean enabled) {
301 // Don't care.
302 }
303
304 private static abstract class SignalIconState {
305 public boolean visible;
306 public boolean activityOut;
307 public boolean activityIn;
308 public String slot;
309 public String contentDescription;
310
311 @Override
312 public boolean equals(Object o) {
313 // Skipping reference equality bc this should be more of a value type
314 if (o == null || getClass() != o.getClass()) {
315 return false;
316 }
317 SignalIconState that = (SignalIconState) o;
318 return visible == that.visible &&
319 activityOut == that.activityOut &&
320 activityIn == that.activityIn &&
321 Objects.equals(contentDescription, that.contentDescription) &&
322 Objects.equals(slot, that.slot);
323 }
324
325 @Override
326 public int hashCode() {
327 return Objects.hash(visible, activityOut, slot);
328 }
329
330 protected void copyTo(SignalIconState other) {
331 other.visible = visible;
332 other.activityIn = activityIn;
333 other.activityOut = activityOut;
334 other.slot = slot;
335 other.contentDescription = contentDescription;
336 }
337 }
338
339 public static class WifiIconState extends SignalIconState{
340 public int resId;
341 public boolean airplaneSpacerVisible;
342 public boolean signalSpacerVisible;
343
344 @Override
345 public boolean equals(Object o) {
346 // Skipping reference equality bc this should be more of a value type
347 if (o == null || getClass() != o.getClass()) {
348 return false;
349 }
350 if (!super.equals(o)) {
351 return false;
352 }
353 WifiIconState that = (WifiIconState) o;
354 return resId == that.resId &&
355 airplaneSpacerVisible == that.airplaneSpacerVisible &&
356 signalSpacerVisible == that.signalSpacerVisible;
357 }
358
359 public void copyTo(WifiIconState other) {
360 super.copyTo(other);
361 other.resId = resId;
362 other.airplaneSpacerVisible = airplaneSpacerVisible;
363 other.signalSpacerVisible = signalSpacerVisible;
364 }
365
366 public WifiIconState copy() {
367 WifiIconState newState = new WifiIconState();
368 copyTo(newState);
369 return newState;
370 }
371
372 @Override
373 public int hashCode() {
374 return Objects.hash(super.hashCode(),
375 resId, airplaneSpacerVisible, signalSpacerVisible);
376 }
377
378 @Override public String toString() {
379 return "WifiIconState(resId=" + resId + ", visible=" + visible + ")";
380 }
381 }
382
383 /**
384 * A little different. This one delegates to SignalDrawable instead of a specific resId
385 */
386 public static class MobileIconState extends SignalIconState {
387 public int subId;
388 public int strengthId;
389 public int typeId;
390 public boolean roaming;
391 public boolean needsLeadingPadding;
Evan Laird83c87e52019-09-24 19:14:05 -0400392 public CharSequence typeContentDescription;
Evan Lairde1d13c92018-03-20 16:58:01 -0400393
394 private MobileIconState(int subId) {
395 super();
396 this.subId = subId;
397 }
398
399 @Override
400 public boolean equals(Object o) {
401 if (o == null || getClass() != o.getClass()) {
402 return false;
403 }
404 if (!super.equals(o)) {
405 return false;
406 }
407 MobileIconState that = (MobileIconState) o;
408 return subId == that.subId &&
409 strengthId == that.strengthId &&
410 typeId == that.typeId &&
411 roaming == that.roaming &&
412 needsLeadingPadding == that.needsLeadingPadding &&
413 Objects.equals(typeContentDescription, that.typeContentDescription);
414 }
415
416 @Override
417 public int hashCode() {
418
419 return Objects
420 .hash(super.hashCode(), subId, strengthId, typeId, roaming, needsLeadingPadding,
421 typeContentDescription);
422 }
423
Evan Laird56fb9f82018-04-24 21:11:15 -0400424 public MobileIconState copy() {
425 MobileIconState copy = new MobileIconState(this.subId);
426 copyTo(copy);
427 return copy;
428 }
429
Evan Lairde1d13c92018-03-20 16:58:01 -0400430 public void copyTo(MobileIconState other) {
431 super.copyTo(other);
432 other.subId = subId;
433 other.strengthId = strengthId;
434 other.typeId = typeId;
435 other.roaming = roaming;
436 other.needsLeadingPadding = needsLeadingPadding;
437 other.typeContentDescription = typeContentDescription;
438 }
439
440 private static List<MobileIconState> copyStates(List<MobileIconState> inStates) {
441 ArrayList<MobileIconState> outStates = new ArrayList<>();
442 for (MobileIconState state : inStates) {
443 MobileIconState copy = new MobileIconState(state.subId);
444 state.copyTo(copy);
445 outStates.add(copy);
446 }
447
448 return outStates;
449 }
450
451 @Override public String toString() {
452 return "MobileIconState(subId=" + subId + ", strengthId=" + strengthId + ", roaming="
Evan Laird6dedbe62018-04-05 16:22:36 -0400453 + roaming + ", typeId=" + typeId + ", visible=" + visible + ")";
Evan Lairde1d13c92018-03-20 16:58:01 -0400454 }
455 }
456}