1 /*
2  * Copyright (C) 2008 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.app.ActivityManager;
20 import android.app.ActivityTaskManager;
21 import android.app.AlarmManager;
22 import android.app.AlarmManager.AlarmClockInfo;
23 import android.app.SynchronousUserSwitchObserver;
24 import android.content.BroadcastReceiver;
25 import android.content.Context;
26 import android.content.Intent;
27 import android.content.IntentFilter;
28 import android.media.AudioManager;
29 import android.os.Handler;
30 import android.os.RemoteException;
31 import android.os.UserHandle;
32 import android.os.UserManager;
33 import android.provider.Settings.Global;
34 import android.service.notification.ZenModeConfig;
35 import android.telecom.TelecomManager;
36 import android.text.format.DateFormat;
37 import android.util.Log;
38 
39 import com.android.internal.telephony.IccCardConstants;
40 import com.android.internal.telephony.TelephonyIntents;
41 import com.android.systemui.Dependency;
42 import com.android.systemui.R;
43 import com.android.systemui.SysUiServiceProvider;
44 import com.android.systemui.UiOffloadThread;
45 import com.android.systemui.qs.tiles.DndTile;
46 import com.android.systemui.qs.tiles.RotationLockTile;
47 import com.android.systemui.statusbar.CommandQueue;
48 import com.android.systemui.statusbar.policy.BluetoothController;
49 import com.android.systemui.statusbar.policy.CastController;
50 import com.android.systemui.statusbar.policy.CastController.CastDevice;
51 import com.android.systemui.statusbar.policy.DataSaverController;
52 import com.android.systemui.statusbar.policy.DataSaverController.Listener;
53 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
54 import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
55 import com.android.systemui.statusbar.policy.HotspotController;
56 import com.android.systemui.statusbar.policy.KeyguardMonitor;
57 import com.android.systemui.statusbar.policy.LocationController;
58 import com.android.systemui.statusbar.policy.NextAlarmController;
59 import com.android.systemui.statusbar.policy.RotationLockController;
60 import com.android.systemui.statusbar.policy.RotationLockController.RotationLockControllerCallback;
61 import com.android.systemui.statusbar.policy.SensorPrivacyController;
62 import com.android.systemui.statusbar.policy.UserInfoController;
63 import com.android.systemui.statusbar.policy.ZenModeController;
64 
65 import java.util.Locale;
66 
67 /**
68  * This class contains all of the policy about which icons are installed in the status bar at boot
69  * time. It goes through the normal API for icons, even though it probably strictly doesn't need to.
70  */
71 public class PhoneStatusBarPolicy
72         implements BluetoothController.Callback,
73                 CommandQueue.Callbacks,
74                 RotationLockControllerCallback,
75                 Listener,
76                 ZenModeController.Callback,
77                 DeviceProvisionedListener,
78                 KeyguardMonitor.Callback,
79                 LocationController.LocationChangeCallback {
80     private static final String TAG = "PhoneStatusBarPolicy";
81     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
82 
83     public static final int LOCATION_STATUS_ICON_ID =
84             com.android.internal.R.drawable.perm_group_location;
85 
86     private final String mSlotCast;
87     private final String mSlotHotspot;
88     private final String mSlotBluetooth;
89     private final String mSlotTty;
90     private final String mSlotZen;
91     private final String mSlotVolume;
92     private final String mSlotAlarmClock;
93     private final String mSlotManagedProfile;
94     private final String mSlotRotate;
95     private final String mSlotHeadset;
96     private final String mSlotDataSaver;
97     private final String mSlotLocation;
98     private final String mSlotSensorsOff;
99 
100     private final Context mContext;
101     private final Handler mHandler = new Handler();
102     private final CastController mCast;
103     private final HotspotController mHotspot;
104     private final NextAlarmController mNextAlarmController;
105     private final AlarmManager mAlarmManager;
106     private final UserInfoController mUserInfoController;
107     private final UserManager mUserManager;
108     private final StatusBarIconController mIconController;
109     private final RotationLockController mRotationLockController;
110     private final DataSaverController mDataSaver;
111     private final ZenModeController mZenController;
112     private final DeviceProvisionedController mProvisionedController;
113     private final KeyguardMonitor mKeyguardMonitor;
114     private final LocationController mLocationController;
115     private final UiOffloadThread mUiOffloadThread = Dependency.get(UiOffloadThread.class);
116     private final SensorPrivacyController mSensorPrivacyController;
117 
118     // Assume it's all good unless we hear otherwise.  We don't always seem
119     // to get broadcasts that it *is* there.
120     IccCardConstants.State mSimState = IccCardConstants.State.READY;
121 
122     private boolean mZenVisible;
123     private boolean mVolumeVisible;
124     private boolean mCurrentUserSetup;
125 
126     private boolean mManagedProfileIconVisible = false;
127 
128     private BluetoothController mBluetooth;
129     private AlarmManager.AlarmClockInfo mNextAlarm;
130 
PhoneStatusBarPolicy(Context context, StatusBarIconController iconController)131     public PhoneStatusBarPolicy(Context context, StatusBarIconController iconController) {
132         mContext = context;
133         mIconController = iconController;
134         mCast = Dependency.get(CastController.class);
135         mHotspot = Dependency.get(HotspotController.class);
136         mBluetooth = Dependency.get(BluetoothController.class);
137         mNextAlarmController = Dependency.get(NextAlarmController.class);
138         mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
139         mUserInfoController = Dependency.get(UserInfoController.class);
140         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
141         mRotationLockController = Dependency.get(RotationLockController.class);
142         mDataSaver = Dependency.get(DataSaverController.class);
143         mZenController = Dependency.get(ZenModeController.class);
144         mProvisionedController = Dependency.get(DeviceProvisionedController.class);
145         mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
146         mLocationController = Dependency.get(LocationController.class);
147         mSensorPrivacyController = Dependency.get(SensorPrivacyController.class);
148 
149         mSlotCast = context.getString(com.android.internal.R.string.status_bar_cast);
150         mSlotHotspot = context.getString(com.android.internal.R.string.status_bar_hotspot);
151         mSlotBluetooth = context.getString(com.android.internal.R.string.status_bar_bluetooth);
152         mSlotTty = context.getString(com.android.internal.R.string.status_bar_tty);
153         mSlotZen = context.getString(com.android.internal.R.string.status_bar_zen);
154         mSlotVolume = context.getString(com.android.internal.R.string.status_bar_volume);
155         mSlotAlarmClock = context.getString(com.android.internal.R.string.status_bar_alarm_clock);
156         mSlotManagedProfile = context.getString(
157                 com.android.internal.R.string.status_bar_managed_profile);
158         mSlotRotate = context.getString(com.android.internal.R.string.status_bar_rotate);
159         mSlotHeadset = context.getString(com.android.internal.R.string.status_bar_headset);
160         mSlotDataSaver = context.getString(com.android.internal.R.string.status_bar_data_saver);
161         mSlotLocation = context.getString(com.android.internal.R.string.status_bar_location);
162         mSlotSensorsOff = context.getString(com.android.internal.R.string.status_bar_sensors_off);
163 
164         // listen for broadcasts
165         IntentFilter filter = new IntentFilter();
166         filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
167         filter.addAction(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION);
168         filter.addAction(AudioManager.ACTION_HEADSET_PLUG);
169         filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
170         filter.addAction(TelecomManager.ACTION_CURRENT_TTY_MODE_CHANGED);
171         filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
172         filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
173         filter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
174         mContext.registerReceiver(mIntentReceiver, filter, null, mHandler);
175 
176         // listen for user / profile change.
177         try {
178             ActivityManager.getService().registerUserSwitchObserver(mUserSwitchListener, TAG);
179         } catch (RemoteException e) {
180             // Ignore
181         }
182 
183         // TTY status
184         updateTTY();
185 
186         // bluetooth status
187         updateBluetooth();
188 
189         // Alarm clock
190         mIconController.setIcon(mSlotAlarmClock, R.drawable.stat_sys_alarm, null);
191         mIconController.setIconVisibility(mSlotAlarmClock, false);
192 
193         // zen
194         mIconController.setIcon(mSlotZen, R.drawable.stat_sys_dnd, null);
195         mIconController.setIconVisibility(mSlotZen, false);
196 
197         // volume
198         mIconController.setIcon(mSlotVolume, R.drawable.stat_sys_ringer_vibrate, null);
199         mIconController.setIconVisibility(mSlotVolume, false);
200         updateVolumeZen();
201 
202         // cast
203         mIconController.setIcon(mSlotCast, R.drawable.stat_sys_cast, null);
204         mIconController.setIconVisibility(mSlotCast, false);
205 
206         // hotspot
207         mIconController.setIcon(mSlotHotspot, R.drawable.stat_sys_hotspot,
208                 mContext.getString(R.string.accessibility_status_bar_hotspot));
209         mIconController.setIconVisibility(mSlotHotspot, mHotspot.isHotspotEnabled());
210 
211         // managed profile
212         mIconController.setIcon(mSlotManagedProfile, R.drawable.stat_sys_managed_profile_status,
213                 mContext.getString(R.string.accessibility_managed_profile));
214         mIconController.setIconVisibility(mSlotManagedProfile, mManagedProfileIconVisible);
215 
216         // data saver
217         mIconController.setIcon(mSlotDataSaver, R.drawable.stat_sys_data_saver,
218                 context.getString(R.string.accessibility_data_saver_on));
219         mIconController.setIconVisibility(mSlotDataSaver, false);
220 
221         mIconController.setIcon(mSlotLocation, LOCATION_STATUS_ICON_ID,
222                 mContext.getString(R.string.accessibility_location_active));
223         mIconController.setIconVisibility(mSlotLocation, false);
224 
225         // sensors off
226         mIconController.setIcon(mSlotSensorsOff, R.drawable.stat_sys_sensors_off,
227                 mContext.getString(R.string.accessibility_sensors_off_active));
228         mIconController.setIconVisibility(mSlotSensorsOff,
229                 mSensorPrivacyController.isSensorPrivacyEnabled());
230 
231         mRotationLockController.addCallback(this);
232         mBluetooth.addCallback(this);
233         mProvisionedController.addCallback(this);
234         mZenController.addCallback(this);
235         mCast.addCallback(mCastCallback);
236         mHotspot.addCallback(mHotspotCallback);
237         mNextAlarmController.addCallback(mNextAlarmCallback);
238         mDataSaver.addCallback(this);
239         mKeyguardMonitor.addCallback(this);
240         mSensorPrivacyController.addCallback(mSensorPrivacyListener);
241         mLocationController.addCallback(this);
242 
243         SysUiServiceProvider.getComponent(mContext, CommandQueue.class).addCallback(this);
244     }
245 
246     @Override
onZenChanged(int zen)247     public void onZenChanged(int zen) {
248         updateVolumeZen();
249     }
250 
251     @Override
onConfigChanged(ZenModeConfig config)252     public void onConfigChanged(ZenModeConfig config) {
253         updateVolumeZen();
254     }
255 
updateAlarm()256     private void updateAlarm() {
257         final AlarmClockInfo alarm = mAlarmManager.getNextAlarmClock(UserHandle.USER_CURRENT);
258         final boolean hasAlarm = alarm != null && alarm.getTriggerTime() > 0;
259         int zen = mZenController.getZen();
260         final boolean zenNone = zen == Global.ZEN_MODE_NO_INTERRUPTIONS;
261         mIconController.setIcon(mSlotAlarmClock, zenNone ? R.drawable.stat_sys_alarm_dim
262                 : R.drawable.stat_sys_alarm, buildAlarmContentDescription());
263         mIconController.setIconVisibility(mSlotAlarmClock, mCurrentUserSetup && hasAlarm);
264     }
265 
buildAlarmContentDescription()266     private String buildAlarmContentDescription() {
267         if (mNextAlarm == null) {
268             return mContext.getString(R.string.status_bar_alarm);
269         }
270         return formatNextAlarm(mNextAlarm, mContext);
271     }
272 
formatNextAlarm(AlarmManager.AlarmClockInfo info, Context context)273     private static String formatNextAlarm(AlarmManager.AlarmClockInfo info, Context context) {
274         if (info == null) {
275             return "";
276         }
277         String skeleton = DateFormat.is24HourFormat(
278                 context, ActivityManager.getCurrentUser()) ? "EHm" : "Ehma";
279         String pattern = DateFormat.getBestDateTimePattern(Locale.getDefault(), skeleton);
280         String dateString = DateFormat.format(pattern, info.getTriggerTime()).toString();
281 
282         return context.getString(R.string.accessibility_quick_settings_alarm, dateString);
283     }
284 
updateSimState(Intent intent)285     private final void updateSimState(Intent intent) {
286         String stateExtra = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE);
287         if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) {
288             mSimState = IccCardConstants.State.ABSENT;
289         } else if (IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR.equals(stateExtra)) {
290             mSimState = IccCardConstants.State.CARD_IO_ERROR;
291         } else if (IccCardConstants.INTENT_VALUE_ICC_CARD_RESTRICTED.equals(stateExtra)) {
292             mSimState = IccCardConstants.State.CARD_RESTRICTED;
293         } else if (IccCardConstants.INTENT_VALUE_ICC_READY.equals(stateExtra)) {
294             mSimState = IccCardConstants.State.READY;
295         } else if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) {
296             final String lockedReason =
297                     intent.getStringExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON);
298             if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) {
299                 mSimState = IccCardConstants.State.PIN_REQUIRED;
300             } else if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) {
301                 mSimState = IccCardConstants.State.PUK_REQUIRED;
302             } else {
303                 mSimState = IccCardConstants.State.NETWORK_LOCKED;
304             }
305         } else {
306             mSimState = IccCardConstants.State.UNKNOWN;
307         }
308     }
309 
updateVolumeZen()310     private final void updateVolumeZen() {
311         AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
312 
313         boolean zenVisible = false;
314         int zenIconId = 0;
315         String zenDescription = null;
316 
317         boolean volumeVisible = false;
318         int volumeIconId = 0;
319         String volumeDescription = null;
320         int zen = mZenController.getZen();
321 
322         if (DndTile.isVisible(mContext) || DndTile.isCombinedIcon(mContext)) {
323             zenVisible = zen != Global.ZEN_MODE_OFF;
324             zenIconId = R.drawable.stat_sys_dnd;
325             zenDescription = mContext.getString(R.string.quick_settings_dnd_label);
326         } else if (zen == Global.ZEN_MODE_NO_INTERRUPTIONS) {
327             zenVisible = true;
328             zenIconId = R.drawable.stat_sys_dnd;
329             zenDescription = mContext.getString(R.string.interruption_level_none);
330         } else if (zen == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS) {
331             zenVisible = true;
332             zenIconId = R.drawable.stat_sys_dnd;
333             zenDescription = mContext.getString(R.string.interruption_level_priority);
334         }
335 
336         if (!ZenModeConfig.isZenOverridingRinger(zen, mZenController.getConsolidatedPolicy())) {
337             if (audioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_VIBRATE) {
338                 volumeVisible = true;
339                 volumeIconId = R.drawable.stat_sys_ringer_vibrate;
340                 volumeDescription = mContext.getString(R.string.accessibility_ringer_vibrate);
341             } else if (audioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_SILENT) {
342                 volumeVisible = true;
343                 volumeIconId = R.drawable.stat_sys_ringer_silent;
344                 volumeDescription = mContext.getString(R.string.accessibility_ringer_silent);
345             }
346         }
347 
348         if (zenVisible) {
349             mIconController.setIcon(mSlotZen, zenIconId, zenDescription);
350         }
351         if (zenVisible != mZenVisible) {
352             mIconController.setIconVisibility(mSlotZen, zenVisible);
353             mZenVisible = zenVisible;
354         }
355 
356         if (volumeVisible) {
357             mIconController.setIcon(mSlotVolume, volumeIconId, volumeDescription);
358         }
359         if (volumeVisible != mVolumeVisible) {
360             mIconController.setIconVisibility(mSlotVolume, volumeVisible);
361             mVolumeVisible = volumeVisible;
362         }
363         updateAlarm();
364     }
365 
366     @Override
onBluetoothDevicesChanged()367     public void onBluetoothDevicesChanged() {
368         updateBluetooth();
369     }
370 
371     @Override
onBluetoothStateChange(boolean enabled)372     public void onBluetoothStateChange(boolean enabled) {
373         updateBluetooth();
374     }
375 
updateBluetooth()376     private final void updateBluetooth() {
377         int iconId = R.drawable.stat_sys_data_bluetooth_connected;
378         String contentDescription =
379                 mContext.getString(R.string.accessibility_quick_settings_bluetooth_on);
380         boolean bluetoothVisible = false;
381         if (mBluetooth != null) {
382             if (mBluetooth.isBluetoothConnected()
383                     && (mBluetooth.isBluetoothAudioActive()
384                     || !mBluetooth.isBluetoothAudioProfileOnly())) {
385                 contentDescription = mContext.getString(
386                         R.string.accessibility_bluetooth_connected);
387                 bluetoothVisible = mBluetooth.isBluetoothEnabled();
388             }
389         }
390 
391         mIconController.setIcon(mSlotBluetooth, iconId, contentDescription);
392         mIconController.setIconVisibility(mSlotBluetooth, bluetoothVisible);
393     }
394 
updateTTY()395     private final void updateTTY() {
396         TelecomManager telecomManager =
397                 (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
398         if (telecomManager == null) {
399             updateTTY(TelecomManager.TTY_MODE_OFF);
400         } else {
401             updateTTY(telecomManager.getCurrentTtyMode());
402         }
403     }
404 
updateTTY(int currentTtyMode)405     private final void updateTTY(int currentTtyMode) {
406         boolean enabled = currentTtyMode != TelecomManager.TTY_MODE_OFF;
407 
408         if (DEBUG) Log.v(TAG, "updateTTY: enabled: " + enabled);
409 
410         if (enabled) {
411             // TTY is on
412             if (DEBUG) Log.v(TAG, "updateTTY: set TTY on");
413             mIconController.setIcon(mSlotTty, R.drawable.stat_sys_tty_mode,
414                     mContext.getString(R.string.accessibility_tty_enabled));
415             mIconController.setIconVisibility(mSlotTty, true);
416         } else {
417             // TTY is off
418             if (DEBUG) Log.v(TAG, "updateTTY: set TTY off");
419             mIconController.setIconVisibility(mSlotTty, false);
420         }
421     }
422 
updateCast()423     private void updateCast() {
424         boolean isCasting = false;
425         for (CastDevice device : mCast.getCastDevices()) {
426             if (device.state == CastDevice.STATE_CONNECTING
427                     || device.state == CastDevice.STATE_CONNECTED) {
428                 isCasting = true;
429                 break;
430             }
431         }
432         if (DEBUG) Log.v(TAG, "updateCast: isCasting: " + isCasting);
433         mHandler.removeCallbacks(mRemoveCastIconRunnable);
434         if (isCasting) {
435             mIconController.setIcon(mSlotCast, R.drawable.stat_sys_cast,
436                     mContext.getString(R.string.accessibility_casting));
437             mIconController.setIconVisibility(mSlotCast, true);
438         } else {
439             // don't turn off the screen-record icon for a few seconds, just to make sure the user
440             // has seen it
441             if (DEBUG) Log.v(TAG, "updateCast: hiding icon in 3 sec...");
442             mHandler.postDelayed(mRemoveCastIconRunnable, 3000);
443         }
444     }
445 
updateManagedProfile()446     private void updateManagedProfile() {
447         // getLastResumedActivityUserId needds to acquire the AM lock, which may be contended in
448         // some cases. Since it doesn't really matter here whether it's updated in this frame
449         // or in the next one, we call this method from our UI offload thread.
450         mUiOffloadThread.submit(() -> {
451             final int userId;
452             try {
453                 userId = ActivityTaskManager.getService().getLastResumedActivityUserId();
454                 boolean isManagedProfile = mUserManager.isManagedProfile(userId);
455                 mHandler.post(() -> {
456                     final boolean showIcon;
457                     if (isManagedProfile &&
458                             (!mKeyguardMonitor.isShowing() || mKeyguardMonitor.isOccluded())) {
459                         showIcon = true;
460                         mIconController.setIcon(mSlotManagedProfile,
461                                 R.drawable.stat_sys_managed_profile_status,
462                                 mContext.getString(R.string.accessibility_managed_profile));
463                     } else {
464                         showIcon = false;
465                     }
466                     if (mManagedProfileIconVisible != showIcon) {
467                         mIconController.setIconVisibility(mSlotManagedProfile, showIcon);
468                         mManagedProfileIconVisible = showIcon;
469                     }
470                 });
471             } catch (RemoteException e) {
472                 Log.w(TAG, "updateManagedProfile: ", e);
473             }
474         });
475     }
476 
477     private final SynchronousUserSwitchObserver mUserSwitchListener =
478             new SynchronousUserSwitchObserver() {
479                 @Override
480                 public void onUserSwitching(int newUserId) throws RemoteException {
481                     mHandler.post(() -> mUserInfoController.reloadUserInfo());
482                 }
483 
484                 @Override
485                 public void onUserSwitchComplete(int newUserId) throws RemoteException {
486                     mHandler.post(() -> {
487                         updateAlarm();
488                         updateManagedProfile();
489                     });
490                 }
491             };
492 
493     private final HotspotController.Callback mHotspotCallback = new HotspotController.Callback() {
494         @Override
495         public void onHotspotChanged(boolean enabled, int numDevices) {
496             mIconController.setIconVisibility(mSlotHotspot, enabled);
497         }
498     };
499 
500     private final CastController.Callback mCastCallback = new CastController.Callback() {
501         @Override
502         public void onCastDevicesChanged() {
503             updateCast();
504         }
505     };
506 
507     private final NextAlarmController.NextAlarmChangeCallback mNextAlarmCallback =
508             new NextAlarmController.NextAlarmChangeCallback() {
509                 @Override
510                 public void onNextAlarmChanged(AlarmManager.AlarmClockInfo nextAlarm) {
511                     mNextAlarm = nextAlarm;
512                     updateAlarm();
513                 }
514             };
515 
516     private final SensorPrivacyController.OnSensorPrivacyChangedListener mSensorPrivacyListener =
517             new SensorPrivacyController.OnSensorPrivacyChangedListener() {
518                 @Override
519                 public void onSensorPrivacyChanged(boolean enabled) {
520                     mHandler.post(() -> {
521                         mIconController.setIconVisibility(mSlotSensorsOff, enabled);
522                     });
523                 }
524             };
525 
526     @Override
appTransitionStarting(int displayId, long startTime, long duration, boolean forced)527     public void appTransitionStarting(int displayId, long startTime, long duration,
528             boolean forced) {
529         if (mContext.getDisplayId() == displayId) {
530             updateManagedProfile();
531         }
532     }
533 
534     @Override
onKeyguardShowingChanged()535     public void onKeyguardShowingChanged() {
536         updateManagedProfile();
537     }
538 
539     @Override
onUserSetupChanged()540     public void onUserSetupChanged() {
541         boolean userSetup = mProvisionedController.isUserSetup(
542                 mProvisionedController.getCurrentUser());
543         if (mCurrentUserSetup == userSetup) return;
544         mCurrentUserSetup = userSetup;
545         updateAlarm();
546     }
547 
548     @Override
onRotationLockStateChanged(boolean rotationLocked, boolean affordanceVisible)549     public void onRotationLockStateChanged(boolean rotationLocked, boolean affordanceVisible) {
550         boolean portrait = RotationLockTile.isCurrentOrientationLockPortrait(
551                 mRotationLockController, mContext);
552         if (rotationLocked) {
553             if (portrait) {
554                 mIconController.setIcon(mSlotRotate, R.drawable.stat_sys_rotate_portrait,
555                         mContext.getString(R.string.accessibility_rotation_lock_on_portrait));
556             } else {
557                 mIconController.setIcon(mSlotRotate, R.drawable.stat_sys_rotate_landscape,
558                         mContext.getString(R.string.accessibility_rotation_lock_on_landscape));
559             }
560             mIconController.setIconVisibility(mSlotRotate, true);
561         } else {
562             mIconController.setIconVisibility(mSlotRotate, false);
563         }
564     }
565 
updateHeadsetPlug(Intent intent)566     private void updateHeadsetPlug(Intent intent) {
567         boolean connected = intent.getIntExtra("state", 0) != 0;
568         boolean hasMic = intent.getIntExtra("microphone", 0) != 0;
569         if (connected) {
570             String contentDescription = mContext.getString(hasMic
571                     ? R.string.accessibility_status_bar_headset
572                     : R.string.accessibility_status_bar_headphones);
573             mIconController.setIcon(mSlotHeadset, hasMic ? R.drawable.stat_sys_headset_mic
574                     : R.drawable.stat_sys_headset, contentDescription);
575             mIconController.setIconVisibility(mSlotHeadset, true);
576         } else {
577             mIconController.setIconVisibility(mSlotHeadset, false);
578         }
579     }
580 
581     @Override
onDataSaverChanged(boolean isDataSaving)582     public void onDataSaverChanged(boolean isDataSaving) {
583         mIconController.setIconVisibility(mSlotDataSaver, isDataSaving);
584     }
585 
586     @Override
onLocationActiveChanged(boolean active)587     public void onLocationActiveChanged(boolean active) {
588         updateLocation();
589     }
590 
591     // Updates the status view based on the current state of location requests.
updateLocation()592     private void updateLocation() {
593         if (mLocationController.isLocationActive()) {
594             mIconController.setIconVisibility(mSlotLocation, true);
595         } else {
596             mIconController.setIconVisibility(mSlotLocation, false);
597         }
598     }
599 
600     private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
601         @Override
602         public void onReceive(Context context, Intent intent) {
603             String action = intent.getAction();
604             switch (action) {
605                 case AudioManager.RINGER_MODE_CHANGED_ACTION:
606                 case AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION:
607                     updateVolumeZen();
608                     break;
609                 case TelephonyIntents.ACTION_SIM_STATE_CHANGED:
610                     // Avoid rebroadcast because SysUI is direct boot aware.
611                     if (intent.getBooleanExtra(Intent.EXTRA_REBROADCAST_ON_UNLOCK, false)) {
612                         break;
613                     }
614                     updateSimState(intent);
615                     break;
616                 case TelecomManager.ACTION_CURRENT_TTY_MODE_CHANGED:
617                     updateTTY(intent.getIntExtra(TelecomManager.EXTRA_CURRENT_TTY_MODE,
618                             TelecomManager.TTY_MODE_OFF));
619                     break;
620                 case Intent.ACTION_MANAGED_PROFILE_AVAILABLE:
621                 case Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE:
622                 case Intent.ACTION_MANAGED_PROFILE_REMOVED:
623                     updateManagedProfile();
624                     break;
625                 case AudioManager.ACTION_HEADSET_PLUG:
626                     updateHeadsetPlug(intent);
627                     break;
628             }
629         }
630     };
631 
632     private Runnable mRemoveCastIconRunnable = new Runnable() {
633         @Override
634         public void run() {
635             if (DEBUG) Log.v(TAG, "updateCast: hiding icon NOW");
636             mIconController.setIconVisibility(mSlotCast, false);
637         }
638     };
639 }
640