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 static android.app.admin.DevicePolicyResources.Strings.SystemUi.STATUS_BAR_WORK_ICON_ACCESSIBILITY; 20 21 import android.annotation.Nullable; 22 import android.app.ActivityTaskManager; 23 import android.app.AlarmManager; 24 import android.app.AlarmManager.AlarmClockInfo; 25 import android.app.NotificationManager; 26 import android.app.admin.DevicePolicyManager; 27 import android.content.BroadcastReceiver; 28 import android.content.Context; 29 import android.content.Intent; 30 import android.content.IntentFilter; 31 import android.content.SharedPreferences; 32 import android.content.res.Resources; 33 import android.media.AudioManager; 34 import android.os.Handler; 35 import android.os.Looper; 36 import android.os.RemoteException; 37 import android.os.UserManager; 38 import android.provider.Settings.Global; 39 import android.service.notification.ZenModeConfig; 40 import android.telecom.TelecomManager; 41 import android.text.format.DateFormat; 42 import android.util.Log; 43 44 import androidx.lifecycle.Observer; 45 46 import com.android.internal.statusbar.StatusBarIcon; 47 import com.android.systemui.broadcast.BroadcastDispatcher; 48 import com.android.systemui.dagger.qualifiers.DisplayId; 49 import com.android.systemui.dagger.qualifiers.Main; 50 import com.android.systemui.dagger.qualifiers.UiBackground; 51 import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor; 52 import com.android.systemui.modes.shared.ModesUiIcons; 53 import com.android.systemui.privacy.PrivacyItem; 54 import com.android.systemui.privacy.PrivacyItemController; 55 import com.android.systemui.privacy.PrivacyType; 56 import com.android.systemui.privacy.logging.PrivacyLogger; 57 import com.android.systemui.qs.tiles.DndTile; 58 import com.android.systemui.qs.tiles.RotationLockTile; 59 import com.android.systemui.res.R; 60 import com.android.systemui.screenrecord.RecordingController; 61 import com.android.systemui.settings.UserTracker; 62 import com.android.systemui.statusbar.CommandQueue; 63 import com.android.systemui.statusbar.phone.ui.StatusBarIconController; 64 import com.android.systemui.statusbar.policy.BluetoothController; 65 import com.android.systemui.statusbar.policy.DataSaverController; 66 import com.android.systemui.statusbar.policy.DataSaverController.Listener; 67 import com.android.systemui.statusbar.policy.DeviceProvisionedController; 68 import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener; 69 import com.android.systemui.statusbar.policy.HotspotController; 70 import com.android.systemui.statusbar.policy.KeyguardStateController; 71 import com.android.systemui.statusbar.policy.LocationController; 72 import com.android.systemui.statusbar.policy.NextAlarmController; 73 import com.android.systemui.statusbar.policy.RotationLockController; 74 import com.android.systemui.statusbar.policy.RotationLockController.RotationLockControllerCallback; 75 import com.android.systemui.statusbar.policy.SensorPrivacyController; 76 import com.android.systemui.statusbar.policy.UserInfoController; 77 import com.android.systemui.statusbar.policy.ZenModeController; 78 import com.android.systemui.statusbar.policy.domain.interactor.ZenModeInteractor; 79 import com.android.systemui.statusbar.policy.domain.model.ZenModeInfo; 80 import com.android.systemui.util.RingerModeTracker; 81 import com.android.systemui.util.kotlin.JavaAdapter; 82 import com.android.systemui.util.time.DateFormatUtil; 83 84 import java.io.PrintWriter; 85 import java.io.StringWriter; 86 import java.util.List; 87 import java.util.Locale; 88 import java.util.concurrent.Executor; 89 90 import javax.inject.Inject; 91 92 /** 93 * This class contains all of the policy about which icons are installed in the status bar at boot 94 * time. It goes through the normal API for icons, even though it probably strictly doesn't need to. 95 */ 96 public class PhoneStatusBarPolicy 97 implements BluetoothController.Callback, 98 CommandQueue.Callbacks, 99 RotationLockControllerCallback, 100 Listener, 101 DeviceProvisionedListener, 102 KeyguardStateController.Callback, 103 PrivacyItemController.Callback, 104 LocationController.LocationChangeCallback, 105 RecordingController.RecordingStateChangeCallback { 106 private static final String TAG = "PhoneStatusBarPolicy"; 107 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 108 109 static final int LOCATION_STATUS_ICON_ID = PrivacyType.TYPE_LOCATION.getIconId(); 110 111 private final String mSlotCast; 112 private final String mSlotHotspot; 113 private final String mSlotBluetooth; 114 private final String mSlotTty; 115 private final String mSlotZen; 116 private final String mSlotMute; 117 private final String mSlotVibrate; 118 private final String mSlotAlarmClock; 119 private final String mSlotManagedProfile; 120 private final String mSlotRotate; 121 private final String mSlotHeadset; 122 private final String mSlotDataSaver; 123 private final String mSlotLocation; 124 private final String mSlotMicrophone; 125 private final String mSlotCamera; 126 private final String mSlotSensorsOff; 127 private final String mSlotScreenRecord; 128 private final String mSlotConnectedDisplay; 129 private final int mDisplayId; 130 private final SharedPreferences mSharedPreferences; 131 private final DateFormatUtil mDateFormatUtil; 132 private final JavaAdapter mJavaAdapter; 133 private final ConnectedDisplayInteractor mConnectedDisplayInteractor; 134 private final TelecomManager mTelecomManager; 135 136 private final Handler mHandler; 137 private final HotspotController mHotspot; 138 private final NextAlarmController mNextAlarmController; 139 private final AlarmManager mAlarmManager; 140 private final UserInfoController mUserInfoController; 141 private final UserManager mUserManager; 142 private final UserTracker mUserTracker; 143 private final DevicePolicyManager mDevicePolicyManager; 144 private final StatusBarIconController mIconController; 145 private final CommandQueue mCommandQueue; 146 private final BroadcastDispatcher mBroadcastDispatcher; 147 private final Resources mResources; 148 private final RotationLockController mRotationLockController; 149 private final DataSaverController mDataSaver; 150 private final ZenModeController mZenController; 151 private final DeviceProvisionedController mProvisionedController; 152 private final KeyguardStateController mKeyguardStateController; 153 private final LocationController mLocationController; 154 private final PrivacyItemController mPrivacyItemController; 155 private final Executor mMainExecutor; 156 private final Executor mUiBgExecutor; 157 private final SensorPrivacyController mSensorPrivacyController; 158 private final RingerModeTracker mRingerModeTracker; 159 private final PrivacyLogger mPrivacyLogger; 160 private final ZenModeInteractor mZenModeInteractor; 161 162 private boolean mZenVisible; 163 private boolean mVibrateVisible; 164 private boolean mMuteVisible; 165 private boolean mCurrentUserSetup; 166 167 private boolean mProfileIconVisible = false; 168 169 private BluetoothController mBluetooth; 170 private AlarmManager.AlarmClockInfo mNextAlarm; 171 172 @Inject PhoneStatusBarPolicy(StatusBarIconController iconController, CommandQueue commandQueue, BroadcastDispatcher broadcastDispatcher, @Main Executor mainExecutor, @UiBackground Executor uiBgExecutor, @Main Looper looper, @Main Resources resources, HotspotController hotspotController, BluetoothController bluetoothController, NextAlarmController nextAlarmController, UserInfoController userInfoController, RotationLockController rotationLockController, DataSaverController dataSaverController, ZenModeController zenModeController, DeviceProvisionedController deviceProvisionedController, KeyguardStateController keyguardStateController, LocationController locationController, SensorPrivacyController sensorPrivacyController, AlarmManager alarmManager, UserManager userManager, UserTracker userTracker, DevicePolicyManager devicePolicyManager, @Nullable TelecomManager telecomManager, @DisplayId int displayId, @Main SharedPreferences sharedPreferences, DateFormatUtil dateFormatUtil, RingerModeTracker ringerModeTracker, PrivacyItemController privacyItemController, PrivacyLogger privacyLogger, ConnectedDisplayInteractor connectedDisplayInteractor, ZenModeInteractor zenModeInteractor, JavaAdapter javaAdapter )173 public PhoneStatusBarPolicy(StatusBarIconController iconController, 174 CommandQueue commandQueue, BroadcastDispatcher broadcastDispatcher, 175 @Main Executor mainExecutor, @UiBackground Executor uiBgExecutor, @Main Looper looper, 176 @Main Resources resources, 177 HotspotController hotspotController, BluetoothController bluetoothController, 178 NextAlarmController nextAlarmController, UserInfoController userInfoController, 179 RotationLockController rotationLockController, DataSaverController dataSaverController, 180 ZenModeController zenModeController, 181 DeviceProvisionedController deviceProvisionedController, 182 KeyguardStateController keyguardStateController, 183 LocationController locationController, 184 SensorPrivacyController sensorPrivacyController, AlarmManager alarmManager, 185 UserManager userManager, UserTracker userTracker, 186 DevicePolicyManager devicePolicyManager, 187 @Nullable TelecomManager telecomManager, @DisplayId int displayId, 188 @Main SharedPreferences sharedPreferences, DateFormatUtil dateFormatUtil, 189 RingerModeTracker ringerModeTracker, 190 PrivacyItemController privacyItemController, 191 PrivacyLogger privacyLogger, 192 ConnectedDisplayInteractor connectedDisplayInteractor, 193 ZenModeInteractor zenModeInteractor, 194 JavaAdapter javaAdapter 195 ) { 196 mIconController = iconController; 197 mCommandQueue = commandQueue; 198 mConnectedDisplayInteractor = connectedDisplayInteractor; 199 mBroadcastDispatcher = broadcastDispatcher; 200 mHandler = new Handler(looper); 201 mResources = resources; 202 mHotspot = hotspotController; 203 mBluetooth = bluetoothController; 204 mNextAlarmController = nextAlarmController; 205 mAlarmManager = alarmManager; 206 mUserInfoController = userInfoController; 207 mUserManager = userManager; 208 mUserTracker = userTracker; 209 mDevicePolicyManager = devicePolicyManager; 210 mRotationLockController = rotationLockController; 211 mDataSaver = dataSaverController; 212 mZenController = zenModeController; 213 mProvisionedController = deviceProvisionedController; 214 mKeyguardStateController = keyguardStateController; 215 mLocationController = locationController; 216 mPrivacyItemController = privacyItemController; 217 mSensorPrivacyController = sensorPrivacyController; 218 mMainExecutor = mainExecutor; 219 mUiBgExecutor = uiBgExecutor; 220 mTelecomManager = telecomManager; 221 mRingerModeTracker = ringerModeTracker; 222 mPrivacyLogger = privacyLogger; 223 mZenModeInteractor = zenModeInteractor; 224 mJavaAdapter = javaAdapter; 225 226 mSlotCast = resources.getString(com.android.internal.R.string.status_bar_cast); 227 mSlotConnectedDisplay = resources.getString( 228 com.android.internal.R.string.status_bar_connected_display); 229 mSlotHotspot = resources.getString(com.android.internal.R.string.status_bar_hotspot); 230 mSlotBluetooth = resources.getString(com.android.internal.R.string.status_bar_bluetooth); 231 mSlotTty = resources.getString(com.android.internal.R.string.status_bar_tty); 232 mSlotZen = resources.getString(com.android.internal.R.string.status_bar_zen); 233 mSlotMute = resources.getString(com.android.internal.R.string.status_bar_mute); 234 mSlotVibrate = resources.getString(com.android.internal.R.string.status_bar_volume); 235 mSlotAlarmClock = resources.getString(com.android.internal.R.string.status_bar_alarm_clock); 236 mSlotManagedProfile = resources.getString( 237 com.android.internal.R.string.status_bar_managed_profile); 238 mSlotRotate = resources.getString(com.android.internal.R.string.status_bar_rotate); 239 mSlotHeadset = resources.getString(com.android.internal.R.string.status_bar_headset); 240 mSlotDataSaver = resources.getString(com.android.internal.R.string.status_bar_data_saver); 241 mSlotLocation = resources.getString(com.android.internal.R.string.status_bar_location); 242 mSlotMicrophone = resources.getString(com.android.internal.R.string.status_bar_microphone); 243 mSlotCamera = resources.getString(com.android.internal.R.string.status_bar_camera); 244 mSlotSensorsOff = resources.getString(com.android.internal.R.string.status_bar_sensors_off); 245 mSlotScreenRecord = resources.getString( 246 com.android.internal.R.string.status_bar_screen_record); 247 248 mDisplayId = displayId; 249 mSharedPreferences = sharedPreferences; 250 mDateFormatUtil = dateFormatUtil; 251 } 252 253 /** Initialize the object after construction. */ init()254 public void init() { 255 // listen for broadcasts 256 IntentFilter filter = new IntentFilter(); 257 258 filter.addAction(AudioManager.ACTION_HEADSET_PLUG); 259 filter.addAction(Intent.ACTION_SIM_STATE_CHANGED); 260 filter.addAction(TelecomManager.ACTION_CURRENT_TTY_MODE_CHANGED); 261 filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE); 262 filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE); 263 filter.addAction(Intent.ACTION_PROFILE_REMOVED); 264 filter.addAction(Intent.ACTION_PROFILE_ACCESSIBLE); 265 filter.addAction(Intent.ACTION_PROFILE_INACCESSIBLE); 266 mBroadcastDispatcher.registerReceiverWithHandler(mIntentReceiver, filter, mHandler); 267 Observer<Integer> observer = ringer -> mHandler.post(this::updateVolumeZen); 268 269 mRingerModeTracker.getRingerMode().observeForever(observer); 270 mRingerModeTracker.getRingerModeInternal().observeForever(observer); 271 272 // listen for user / profile change. 273 mUserTracker.addCallback(mUserSwitchListener, mMainExecutor); 274 275 // TTY status 276 updateTTY(); 277 278 // bluetooth status 279 updateBluetooth(); 280 281 // Alarm clock 282 mIconController.setIcon(mSlotAlarmClock, R.drawable.stat_sys_alarm, null); 283 mIconController.setIconVisibility(mSlotAlarmClock, false); 284 285 // zen 286 mIconController.setIcon(mSlotZen, R.drawable.stat_sys_dnd, null); 287 mIconController.setIconVisibility(mSlotZen, false); 288 289 // vibrate 290 mIconController.setIcon(mSlotVibrate, R.drawable.stat_sys_ringer_vibrate, 291 mResources.getString(R.string.accessibility_ringer_vibrate)); 292 mIconController.setIconVisibility(mSlotVibrate, false); 293 // mute 294 mIconController.setIcon(mSlotMute, R.drawable.stat_sys_ringer_silent, 295 mResources.getString(R.string.accessibility_ringer_silent)); 296 mIconController.setIconVisibility(mSlotMute, false); 297 updateVolumeZen(); 298 299 // cast 300 mIconController.setIcon(mSlotCast, R.drawable.stat_sys_cast, null); 301 mIconController.setIconVisibility(mSlotCast, false); 302 303 // connected display 304 mIconController.setIcon(mSlotConnectedDisplay, R.drawable.stat_sys_connected_display, 305 mResources.getString(R.string.connected_display_icon_desc)); 306 mIconController.setIconVisibility(mSlotConnectedDisplay, false); 307 308 // hotspot 309 mIconController.setIcon(mSlotHotspot, R.drawable.stat_sys_hotspot, 310 mResources.getString(R.string.accessibility_status_bar_hotspot)); 311 mIconController.setIconVisibility(mSlotHotspot, mHotspot.isHotspotEnabled()); 312 313 // profile 314 updateProfileIcon(); 315 316 // data saver 317 mIconController.setIcon(mSlotDataSaver, R.drawable.stat_sys_data_saver, 318 mResources.getString(R.string.accessibility_data_saver_on)); 319 mIconController.setIconVisibility(mSlotDataSaver, false); 320 321 322 // privacy items 323 String microphoneString = mResources.getString(PrivacyType.TYPE_MICROPHONE.getNameId()); 324 String microphoneDesc = mResources.getString( 325 R.string.ongoing_privacy_chip_content_multiple_apps, microphoneString); 326 mIconController.setIcon(mSlotMicrophone, PrivacyType.TYPE_MICROPHONE.getIconId(), 327 microphoneDesc); 328 mIconController.setIconVisibility(mSlotMicrophone, false); 329 330 String cameraString = mResources.getString(PrivacyType.TYPE_CAMERA.getNameId()); 331 String cameraDesc = mResources.getString( 332 R.string.ongoing_privacy_chip_content_multiple_apps, cameraString); 333 mIconController.setIcon(mSlotCamera, PrivacyType.TYPE_CAMERA.getIconId(), 334 cameraDesc); 335 mIconController.setIconVisibility(mSlotCamera, false); 336 337 mIconController.setIcon(mSlotLocation, LOCATION_STATUS_ICON_ID, 338 mResources.getString(R.string.accessibility_location_active)); 339 mIconController.setIconVisibility(mSlotLocation, false); 340 341 // sensors off 342 mIconController.setIcon(mSlotSensorsOff, R.drawable.stat_sys_sensors_off, 343 mResources.getString(R.string.accessibility_sensors_off_active)); 344 mIconController.setIconVisibility(mSlotSensorsOff, 345 mSensorPrivacyController.isSensorPrivacyEnabled()); 346 347 // screen record 348 mIconController.setIcon(mSlotScreenRecord, R.drawable.stat_sys_screen_record, null); 349 mIconController.setIconVisibility(mSlotScreenRecord, false); 350 351 mRotationLockController.addCallback(this); 352 mBluetooth.addCallback(this); 353 mProvisionedController.addCallback(this); 354 mCurrentUserSetup = mProvisionedController.isCurrentUserSetup(); 355 if (ModesUiIcons.isEnabled()) { 356 // Note that we're not fully replacing ZenModeController with ZenModeInteractor, so 357 // we listen for the extra event here but still add the ZMC callback. 358 mJavaAdapter.alwaysCollectFlow(mZenModeInteractor.getMainActiveMode(), 359 this::onMainActiveModeChanged); 360 } 361 mZenController.addCallback(mZenControllerCallback); 362 mHotspot.addCallback(mHotspotCallback); 363 mNextAlarmController.addCallback(mNextAlarmCallback); 364 mDataSaver.addCallback(this); 365 mKeyguardStateController.addCallback(this); 366 mPrivacyItemController.addCallback(this); 367 mSensorPrivacyController.addCallback(mSensorPrivacyListener); 368 mLocationController.addCallback(this); 369 mJavaAdapter.alwaysCollectFlow(mConnectedDisplayInteractor.getConnectedDisplayState(), 370 this::onConnectedDisplayAvailabilityChanged); 371 372 mCommandQueue.addCallback(this); 373 } 374 getManagedProfileAccessibilityString()375 private String getManagedProfileAccessibilityString() { 376 return mDevicePolicyManager.getResources().getString( 377 STATUS_BAR_WORK_ICON_ACCESSIBILITY, 378 () -> mResources.getString(R.string.accessibility_managed_profile)); 379 } 380 onMainActiveModeChanged(@ullable ZenModeInfo mainActiveMode)381 private void onMainActiveModeChanged(@Nullable ZenModeInfo mainActiveMode) { 382 if (ModesUiIcons.isUnexpectedlyInLegacyMode()) { 383 return; 384 } 385 386 boolean visible = mainActiveMode != null; 387 if (visible) { 388 // Shape=FIXED_SPACE because mode icons can be from 3P packages and may not be square; 389 // we don't want to allow apps to set incredibly wide icons and take up too much space 390 // in the status bar. 391 mIconController.setResourceIcon(mSlotZen, 392 mainActiveMode.getIcon().key().resPackage(), 393 mainActiveMode.getIcon().key().resId(), 394 mainActiveMode.getIcon().drawable(), 395 mResources.getString(R.string.active_mode_content_description, 396 mainActiveMode.getName()), 397 StatusBarIcon.Shape.FIXED_SPACE); 398 } 399 if (visible != mZenVisible) { 400 mIconController.setIconVisibility(mSlotZen, visible); 401 mZenVisible = visible; 402 } 403 } 404 405 // TODO: b/308591859 - Should be removed and use the ZenModeInteractor only. 406 private final ZenModeController.Callback mZenControllerCallback = 407 new ZenModeController.Callback() { 408 @Override 409 public void onZenChanged(int zen) { 410 updateVolumeZen(); 411 } 412 413 @Override 414 public void onConsolidatedPolicyChanged(NotificationManager.Policy policy) { 415 updateVolumeZen(); 416 } 417 }; 418 updateAlarm()419 private void updateAlarm() { 420 final AlarmClockInfo alarm = mAlarmManager.getNextAlarmClock(mUserTracker.getUserId()); 421 final boolean hasAlarm = alarm != null && alarm.getTriggerTime() > 0; 422 int zen = mZenController.getZen(); 423 final boolean zenNone = zen == Global.ZEN_MODE_NO_INTERRUPTIONS; 424 mIconController.setIcon(mSlotAlarmClock, zenNone ? R.drawable.stat_sys_alarm_dim 425 : R.drawable.stat_sys_alarm, buildAlarmContentDescription()); 426 mIconController.setIconVisibility(mSlotAlarmClock, mCurrentUserSetup && hasAlarm); 427 } 428 buildAlarmContentDescription()429 private String buildAlarmContentDescription() { 430 if (mNextAlarm == null) { 431 return mResources.getString(R.string.status_bar_alarm); 432 } 433 434 String skeleton = mDateFormatUtil.is24HourFormat() ? "EHm" : "Ehma"; 435 String pattern = DateFormat.getBestDateTimePattern(Locale.getDefault(), skeleton); 436 String dateString = DateFormat.format(pattern, mNextAlarm.getTriggerTime()).toString(); 437 438 return mResources.getString(R.string.accessibility_quick_settings_alarm, dateString); 439 } 440 updateVolumeZen()441 private void updateVolumeZen() { 442 int zen = mZenController.getZen(); 443 if (!ModesUiIcons.isEnabled()) { 444 updateZenIcon(zen); 445 } 446 updateRingerAndAlarmIcons(zen); 447 } 448 updateZenIcon(int zen)449 private void updateZenIcon(int zen) { 450 if (ModesUiIcons.isEnabled()) { 451 Log.wtf(TAG, "updateZenIcon shouldn't be called if MODES_UI_ICONS is enabled"); 452 return; 453 } 454 455 boolean zenVisible = false; 456 int zenIconId = 0; 457 String zenDescription = null; 458 459 if (DndTile.isVisible(mSharedPreferences) || DndTile.isCombinedIcon(mSharedPreferences)) { 460 zenVisible = zen != Global.ZEN_MODE_OFF; 461 zenIconId = R.drawable.stat_sys_dnd; 462 zenDescription = mResources.getString(R.string.quick_settings_dnd_label); 463 } else if (zen == Global.ZEN_MODE_NO_INTERRUPTIONS) { 464 zenVisible = true; 465 zenIconId = R.drawable.stat_sys_dnd; 466 zenDescription = mResources.getString(R.string.interruption_level_none); 467 } else if (zen == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS) { 468 zenVisible = true; 469 zenIconId = R.drawable.stat_sys_dnd; 470 zenDescription = mResources.getString(R.string.interruption_level_priority); 471 } 472 473 if (zenVisible) { 474 mIconController.setIcon(mSlotZen, zenIconId, zenDescription); 475 } 476 if (zenVisible != mZenVisible) { 477 mIconController.setIconVisibility(mSlotZen, zenVisible); 478 mZenVisible = zenVisible; 479 } 480 } 481 updateRingerAndAlarmIcons(int zen)482 private void updateRingerAndAlarmIcons(int zen) { 483 boolean vibrateVisible = false; 484 boolean muteVisible = false; 485 486 NotificationManager.Policy consolidatedPolicy = mZenController.getConsolidatedPolicy(); 487 if (!ZenModeConfig.isZenOverridingRinger(zen, consolidatedPolicy)) { 488 final Integer ringerModeInternal = 489 mRingerModeTracker.getRingerModeInternal().getValue(); 490 if (ringerModeInternal != null) { 491 if (ringerModeInternal == AudioManager.RINGER_MODE_VIBRATE) { 492 vibrateVisible = true; 493 } else if (ringerModeInternal == AudioManager.RINGER_MODE_SILENT) { 494 muteVisible = true; 495 } 496 } 497 } 498 499 if (vibrateVisible != mVibrateVisible) { 500 mIconController.setIconVisibility(mSlotVibrate, vibrateVisible); 501 mVibrateVisible = vibrateVisible; 502 } 503 504 if (muteVisible != mMuteVisible) { 505 mIconController.setIconVisibility(mSlotMute, muteVisible); 506 mMuteVisible = muteVisible; 507 } 508 509 updateAlarm(); 510 } 511 512 @Override onBluetoothDevicesChanged()513 public void onBluetoothDevicesChanged() { 514 updateBluetooth(); 515 } 516 517 @Override onBluetoothStateChange(boolean enabled)518 public void onBluetoothStateChange(boolean enabled) { 519 updateBluetooth(); 520 } 521 updateBluetooth()522 private final void updateBluetooth() { 523 int iconId = R.drawable.stat_sys_data_bluetooth_connected; 524 String contentDescription = 525 mResources.getString(R.string.accessibility_quick_settings_bluetooth_on); 526 boolean bluetoothVisible = false; 527 if (mBluetooth != null) { 528 if (mBluetooth.isBluetoothConnected() 529 && (mBluetooth.isBluetoothAudioActive() 530 || !mBluetooth.isBluetoothAudioProfileOnly())) { 531 contentDescription = mResources.getString( 532 R.string.accessibility_bluetooth_connected); 533 bluetoothVisible = mBluetooth.isBluetoothEnabled(); 534 } 535 } 536 537 mIconController.setIcon(mSlotBluetooth, iconId, contentDescription); 538 mIconController.setIconVisibility(mSlotBluetooth, bluetoothVisible); 539 } 540 updateTTY()541 private final void updateTTY() { 542 if (mTelecomManager == null) { 543 updateTTY(TelecomManager.TTY_MODE_OFF); 544 } else { 545 updateTTY(mTelecomManager.getCurrentTtyMode()); 546 } 547 } 548 updateTTY(int currentTtyMode)549 private final void updateTTY(int currentTtyMode) { 550 boolean enabled = currentTtyMode != TelecomManager.TTY_MODE_OFF; 551 552 if (DEBUG) Log.v(TAG, "updateTTY: enabled: " + enabled); 553 554 if (enabled) { 555 // TTY is on 556 if (DEBUG) Log.v(TAG, "updateTTY: set TTY on"); 557 mIconController.setIcon(mSlotTty, R.drawable.stat_sys_tty_mode, 558 mResources.getString(R.string.accessibility_tty_enabled)); 559 mIconController.setIconVisibility(mSlotTty, true); 560 } else { 561 // TTY is off 562 if (DEBUG) Log.v(TAG, "updateTTY: set TTY off"); 563 mIconController.setIconVisibility(mSlotTty, false); 564 } 565 } 566 updateProfileIcon()567 private void updateProfileIcon() { 568 // getLastResumedActivityUserId needs to acquire the AM lock, which may be contended in 569 // some cases. Since it doesn't really matter here whether it's updated in this frame 570 // or in the next one, we call this method from our UI offload thread. 571 mUiBgExecutor.execute(() -> { 572 try { 573 final int userId = ActivityTaskManager.getService().getLastResumedActivityUserId(); 574 final int iconResId = mUserManager.isProfile(userId) ? 575 mUserManager.getUserStatusBarIconResId(userId) : Resources.ID_NULL; 576 mMainExecutor.execute(() -> { 577 final boolean showIcon; 578 if (iconResId != Resources.ID_NULL && (!mKeyguardStateController.isShowing() 579 || mKeyguardStateController.isOccluded())) { 580 String accessibilityString = ""; 581 if (android.os.Flags.allowPrivateProfile() 582 && android.multiuser.Flags.enablePrivateSpaceFeatures()) { 583 try { 584 accessibilityString = 585 mUserManager.getProfileAccessibilityString(userId); 586 } catch (Resources.NotFoundException nfe) { 587 Log.e(TAG, "Accessibility string not found for userId:" 588 + userId); 589 } 590 } else { 591 accessibilityString = getManagedProfileAccessibilityString(); 592 } 593 showIcon = true; 594 mIconController.setIcon(mSlotManagedProfile, 595 iconResId, 596 accessibilityString); 597 } else { 598 showIcon = false; 599 } 600 if (mProfileIconVisible != showIcon) { 601 mIconController.setIconVisibility(mSlotManagedProfile, showIcon); 602 mProfileIconVisible = showIcon; 603 } 604 }); 605 } catch (RemoteException e) { 606 Log.w(TAG, "updateProfileIcon: ", e); 607 } 608 }); 609 } 610 611 private final UserTracker.Callback mUserSwitchListener = 612 new UserTracker.Callback() { 613 @Override 614 public void onUserChanging(int newUser, Context userContext) { 615 mHandler.post(() -> mUserInfoController.reloadUserInfo()); 616 } 617 618 @Override 619 public void onUserChanged(int newUser, Context userContext) { 620 mHandler.post(() -> { 621 updateAlarm(); 622 updateProfileIcon(); 623 onUserSetupChanged(); 624 }); 625 } 626 }; 627 628 private final HotspotController.Callback mHotspotCallback = new HotspotController.Callback() { 629 @Override 630 public void onHotspotChanged(boolean enabled, int numDevices) { 631 mIconController.setIconVisibility(mSlotHotspot, enabled); 632 } 633 }; 634 635 private final NextAlarmController.NextAlarmChangeCallback mNextAlarmCallback = 636 new NextAlarmController.NextAlarmChangeCallback() { 637 @Override 638 public void onNextAlarmChanged(AlarmManager.AlarmClockInfo nextAlarm) { 639 mNextAlarm = nextAlarm; 640 updateAlarm(); 641 } 642 }; 643 644 private final SensorPrivacyController.OnSensorPrivacyChangedListener mSensorPrivacyListener = 645 new SensorPrivacyController.OnSensorPrivacyChangedListener() { 646 @Override 647 public void onSensorPrivacyChanged(boolean enabled) { 648 mHandler.post(() -> { 649 mIconController.setIconVisibility(mSlotSensorsOff, enabled); 650 }); 651 } 652 }; 653 654 @Override appTransitionStarting(int displayId, long startTime, long duration, boolean forced)655 public void appTransitionStarting(int displayId, long startTime, long duration, 656 boolean forced) { 657 if (mDisplayId == displayId) { 658 updateProfileIcon(); 659 } 660 } 661 662 @Override appTransitionFinished(int displayId)663 public void appTransitionFinished(int displayId) { 664 if (mDisplayId == displayId) { 665 updateProfileIcon(); 666 } 667 } 668 669 @Override onKeyguardShowingChanged()670 public void onKeyguardShowingChanged() { 671 updateProfileIcon(); 672 } 673 674 @Override onUserSetupChanged()675 public void onUserSetupChanged() { 676 boolean userSetup = mProvisionedController.isCurrentUserSetup(); 677 if (mCurrentUserSetup == userSetup) return; 678 mCurrentUserSetup = userSetup; 679 updateAlarm(); 680 } 681 682 @Override onRotationLockStateChanged(boolean rotationLocked, boolean affordanceVisible)683 public void onRotationLockStateChanged(boolean rotationLocked, boolean affordanceVisible) { 684 boolean portrait = RotationLockTile.isCurrentOrientationLockPortrait( 685 mRotationLockController, mResources); 686 if (rotationLocked) { 687 if (portrait) { 688 mIconController.setIcon(mSlotRotate, R.drawable.stat_sys_rotate_portrait, 689 mResources.getString(R.string.accessibility_rotation_lock_on_portrait)); 690 } else { 691 mIconController.setIcon(mSlotRotate, R.drawable.stat_sys_rotate_landscape, 692 mResources.getString(R.string.accessibility_rotation_lock_on_landscape)); 693 } 694 mIconController.setIconVisibility(mSlotRotate, true); 695 } else { 696 mIconController.setIconVisibility(mSlotRotate, false); 697 } 698 } 699 updateHeadsetPlug(Intent intent)700 private void updateHeadsetPlug(Intent intent) { 701 boolean connected = intent.getIntExtra("state", 0) != 0; 702 boolean hasMic = intent.getIntExtra("microphone", 0) != 0; 703 if (connected) { 704 String contentDescription = mResources.getString(hasMic 705 ? R.string.accessibility_status_bar_headset 706 : R.string.accessibility_status_bar_headphones); 707 mIconController.setIcon(mSlotHeadset, hasMic ? R.drawable.stat_sys_headset_mic 708 : R.drawable.stat_sys_headset, contentDescription); 709 mIconController.setIconVisibility(mSlotHeadset, true); 710 } else { 711 mIconController.setIconVisibility(mSlotHeadset, false); 712 } 713 } 714 715 @Override onDataSaverChanged(boolean isDataSaving)716 public void onDataSaverChanged(boolean isDataSaving) { 717 mIconController.setIconVisibility(mSlotDataSaver, isDataSaving); 718 } 719 720 @Override // PrivacyItemController.Callback onPrivacyItemsChanged(List<PrivacyItem> privacyItems)721 public void onPrivacyItemsChanged(List<PrivacyItem> privacyItems) { 722 updatePrivacyItems(privacyItems); 723 } 724 updatePrivacyItems(List<PrivacyItem> items)725 private void updatePrivacyItems(List<PrivacyItem> items) { 726 boolean showCamera = false; 727 boolean showMicrophone = false; 728 boolean showLocation = false; 729 for (PrivacyItem item : items) { 730 if (item == null /* b/124234367 */) { 731 Log.e(TAG, "updatePrivacyItems - null item found"); 732 StringWriter out = new StringWriter(); 733 mPrivacyItemController.dump(new PrintWriter(out), null); 734 // Throw so we can look into this 735 throw new NullPointerException(out.toString()); 736 } 737 switch (item.getPrivacyType()) { 738 case TYPE_CAMERA: 739 showCamera = true; 740 break; 741 case TYPE_LOCATION: 742 showLocation = true; 743 break; 744 case TYPE_MICROPHONE: 745 showMicrophone = true; 746 break; 747 } 748 } 749 750 // Disabling for now, but keeping the log 751 /* 752 mIconController.setIconVisibility(mSlotCamera, showCamera); 753 mIconController.setIconVisibility(mSlotMicrophone, showMicrophone); 754 if (mPrivacyItemController.getLocationAvailable()) { 755 mIconController.setIconVisibility(mSlotLocation, showLocation); 756 } 757 */ 758 mPrivacyLogger.logStatusBarIconsVisible(showCamera, showMicrophone, showLocation); 759 } 760 761 @Override onLocationActiveChanged(boolean active)762 public void onLocationActiveChanged(boolean active) { 763 if (!mPrivacyItemController.getLocationAvailable()) { 764 updateLocationFromController(); 765 } 766 } 767 768 // Updates the status view based on the current state of location requests. updateLocationFromController()769 private void updateLocationFromController() { 770 if (mLocationController.isLocationActive()) { 771 mIconController.setIconVisibility(mSlotLocation, true); 772 } else { 773 mIconController.setIconVisibility(mSlotLocation, false); 774 } 775 } 776 777 private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { 778 @Override 779 public void onReceive(Context context, Intent intent) { 780 String action = intent.getAction(); 781 switch (action) { 782 case Intent.ACTION_SIM_STATE_CHANGED: 783 // Avoid rebroadcast because SysUI is direct boot aware. 784 if (intent.getBooleanExtra(Intent.EXTRA_REBROADCAST_ON_UNLOCK, false)) { 785 break; 786 } 787 break; 788 case TelecomManager.ACTION_CURRENT_TTY_MODE_CHANGED: 789 updateTTY(intent.getIntExtra(TelecomManager.EXTRA_CURRENT_TTY_MODE, 790 TelecomManager.TTY_MODE_OFF)); 791 break; 792 case Intent.ACTION_MANAGED_PROFILE_AVAILABLE: 793 case Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE: 794 case Intent.ACTION_PROFILE_REMOVED: 795 case Intent.ACTION_PROFILE_ACCESSIBLE: 796 case Intent.ACTION_PROFILE_INACCESSIBLE: 797 updateProfileIcon(); 798 break; 799 case AudioManager.ACTION_HEADSET_PLUG: 800 updateHeadsetPlug(intent); 801 break; 802 } 803 } 804 }; 805 onConnectedDisplayAvailabilityChanged(ConnectedDisplayInteractor.State state)806 private void onConnectedDisplayAvailabilityChanged(ConnectedDisplayInteractor.State state) { 807 boolean visible = state != ConnectedDisplayInteractor.State.DISCONNECTED; 808 809 if (DEBUG) { 810 Log.d(TAG, "connected_display: " + (visible ? "showing" : "hiding") + " icon"); 811 } 812 813 mIconController.setIconVisibility(mSlotConnectedDisplay, visible); 814 } 815 } 816