1 /* 2 * Copyright (C) 2015 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.volume; 18 19 import static android.media.AudioManager.RINGER_MODE_NORMAL; 20 21 import android.app.ActivityManager; 22 import android.app.KeyguardManager; 23 import android.app.NotificationManager; 24 import android.content.BroadcastReceiver; 25 import android.content.ComponentName; 26 import android.content.Context; 27 import android.content.Intent; 28 import android.content.IntentFilter; 29 import android.content.pm.ApplicationInfo; 30 import android.content.pm.PackageManager; 31 import android.content.pm.PackageManager.NameNotFoundException; 32 import android.database.ContentObserver; 33 import android.media.AudioAttributes; 34 import android.media.AudioManager; 35 import android.media.AudioSystem; 36 import android.media.IAudioService; 37 import android.media.IVolumeController; 38 import android.media.MediaRoute2Info; 39 import android.media.MediaRouter2Manager; 40 import android.media.RoutingSessionInfo; 41 import android.media.VolumePolicy; 42 import android.media.session.MediaController; 43 import android.media.session.MediaController.PlaybackInfo; 44 import android.media.session.MediaSession.Token; 45 import android.net.Uri; 46 import android.os.Handler; 47 import android.os.HandlerExecutor; 48 import android.os.Looper; 49 import android.os.Message; 50 import android.os.RemoteException; 51 import android.os.VibrationEffect; 52 import android.provider.Settings; 53 import android.service.notification.Condition; 54 import android.service.notification.ZenModeConfig; 55 import android.util.ArrayMap; 56 import android.util.Log; 57 import android.util.Slog; 58 import android.view.accessibility.AccessibilityManager; 59 import android.view.accessibility.CaptioningManager; 60 61 import androidx.annotation.NonNull; 62 import androidx.lifecycle.Observer; 63 64 import com.android.internal.annotations.GuardedBy; 65 import com.android.settingslib.volume.MediaSessions; 66 import com.android.systemui.Dumpable; 67 import com.android.systemui.broadcast.BroadcastDispatcher; 68 import com.android.systemui.dagger.SysUISingleton; 69 import com.android.systemui.dump.DumpManager; 70 import com.android.systemui.keyguard.WakefulnessLifecycle; 71 import com.android.systemui.plugins.VolumeDialogController; 72 import com.android.systemui.qs.tiles.DndTile; 73 import com.android.systemui.res.R; 74 import com.android.systemui.settings.UserTracker; 75 import com.android.systemui.statusbar.VibratorHelper; 76 import com.android.systemui.util.RingerModeLiveData; 77 import com.android.systemui.util.RingerModeTracker; 78 import com.android.systemui.util.concurrency.ThreadFactory; 79 80 import dalvik.annotation.optimization.NeverCompile; 81 82 import java.io.PrintWriter; 83 import java.util.HashMap; 84 import java.util.List; 85 import java.util.Map; 86 import java.util.Objects; 87 import java.util.concurrent.ConcurrentHashMap; 88 import java.util.concurrent.atomic.AtomicReference; 89 90 import javax.inject.Inject; 91 92 /** 93 * Source of truth for all state / events related to the volume dialog. No presentation. 94 * 95 * All work done on a dedicated background worker thread & associated worker. 96 * 97 * Methods ending in "W" must be called on the worker thread. 98 */ 99 @SysUISingleton 100 public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpable { 101 private static final String TAG = Util.logTag(VolumeDialogControllerImpl.class); 102 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 103 104 private static final int TOUCH_FEEDBACK_TIMEOUT_MS = 1000; 105 private static final int DYNAMIC_STREAM_START_INDEX = 100; 106 private static final AudioAttributes SONIFICIATION_VIBRATION_ATTRIBUTES = 107 new AudioAttributes.Builder() 108 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) 109 .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION) 110 .build(); 111 112 static final ArrayMap<Integer, Integer> STREAMS = new ArrayMap<>(); 113 static { STREAMS.put(AudioSystem.STREAM_ALARM, R.string.stream_alarm)114 STREAMS.put(AudioSystem.STREAM_ALARM, R.string.stream_alarm); STREAMS.put(AudioSystem.STREAM_BLUETOOTH_SCO, R.string.stream_bluetooth_sco)115 STREAMS.put(AudioSystem.STREAM_BLUETOOTH_SCO, R.string.stream_bluetooth_sco); STREAMS.put(AudioSystem.STREAM_DTMF, R.string.stream_dtmf)116 STREAMS.put(AudioSystem.STREAM_DTMF, R.string.stream_dtmf); STREAMS.put(AudioSystem.STREAM_MUSIC, R.string.stream_music)117 STREAMS.put(AudioSystem.STREAM_MUSIC, R.string.stream_music); STREAMS.put(AudioSystem.STREAM_ACCESSIBILITY, R.string.stream_accessibility)118 STREAMS.put(AudioSystem.STREAM_ACCESSIBILITY, R.string.stream_accessibility); STREAMS.put(AudioSystem.STREAM_NOTIFICATION, R.string.stream_notification)119 STREAMS.put(AudioSystem.STREAM_NOTIFICATION, R.string.stream_notification); STREAMS.put(AudioSystem.STREAM_RING, R.string.stream_ring)120 STREAMS.put(AudioSystem.STREAM_RING, R.string.stream_ring); STREAMS.put(AudioSystem.STREAM_SYSTEM, R.string.stream_system)121 STREAMS.put(AudioSystem.STREAM_SYSTEM, R.string.stream_system); STREAMS.put(AudioSystem.STREAM_SYSTEM_ENFORCED, R.string.stream_system_enforced)122 STREAMS.put(AudioSystem.STREAM_SYSTEM_ENFORCED, R.string.stream_system_enforced); STREAMS.put(AudioSystem.STREAM_TTS, R.string.stream_tts)123 STREAMS.put(AudioSystem.STREAM_TTS, R.string.stream_tts); STREAMS.put(AudioSystem.STREAM_VOICE_CALL, R.string.stream_voice_call)124 STREAMS.put(AudioSystem.STREAM_VOICE_CALL, R.string.stream_voice_call); 125 } 126 127 private final W mWorker; 128 private final Context mContext; 129 private final Looper mWorkerLooper; 130 private final PackageManager mPackageManager; 131 private final MediaRouter2Manager mRouter2Manager; 132 private final WakefulnessLifecycle mWakefulnessLifecycle; 133 private final AudioManager mAudio; 134 private final IAudioService mAudioService; 135 private final NotificationManager mNoMan; 136 private final SettingObserver mObserver; 137 private final Receiver mReceiver = new Receiver(); 138 private final RingerModeObservers mRingerModeObservers; 139 private final MediaSessions mMediaSessions; 140 private final AtomicReference<CaptioningManager> mCaptioningManager = new AtomicReference<>(); 141 private final KeyguardManager mKeyguardManager; 142 private final ActivityManager mActivityManager; 143 private final UserTracker mUserTracker; 144 protected C mCallbacks = new C(); 145 private final State mState = new State(); 146 protected final MediaSessionsCallbacks mMediaSessionsCallbacksW; 147 private final VibratorHelper mVibrator; 148 private final boolean mHasVibrator; 149 private boolean mShowA11yStream; 150 private boolean mShowVolumeDialog; 151 private boolean mShowSafetyWarning; 152 private long mLastToggledRingerOn; 153 private boolean mDeviceInteractive = true; 154 155 private VolumePolicy mVolumePolicy; 156 @GuardedBy("this") 157 private UserActivityListener mUserActivityListener; 158 159 protected final VC mVolumeController = new VC(); 160 protected final BroadcastDispatcher mBroadcastDispatcher; 161 162 private final WakefulnessLifecycle.Observer mWakefullnessLifecycleObserver = 163 new WakefulnessLifecycle.Observer() { 164 @Override 165 public void onStartedWakingUp() { 166 mDeviceInteractive = true; 167 } 168 169 @Override 170 public void onFinishedGoingToSleep() { 171 mDeviceInteractive = false; 172 } 173 }; 174 175 @Inject VolumeDialogControllerImpl( Context context, BroadcastDispatcher broadcastDispatcher, RingerModeTracker ringerModeTracker, ThreadFactory theadFactory, AudioManager audioManager, NotificationManager notificationManager, VibratorHelper vibrator, IAudioService iAudioService, AccessibilityManager accessibilityManager, PackageManager packageManager, WakefulnessLifecycle wakefulnessLifecycle, KeyguardManager keyguardManager, ActivityManager activityManager, UserTracker userTracker, DumpManager dumpManager )176 public VolumeDialogControllerImpl( 177 Context context, 178 BroadcastDispatcher broadcastDispatcher, 179 RingerModeTracker ringerModeTracker, 180 ThreadFactory theadFactory, 181 AudioManager audioManager, 182 NotificationManager notificationManager, 183 VibratorHelper vibrator, 184 IAudioService iAudioService, 185 AccessibilityManager accessibilityManager, 186 PackageManager packageManager, 187 WakefulnessLifecycle wakefulnessLifecycle, 188 KeyguardManager keyguardManager, 189 ActivityManager activityManager, 190 UserTracker userTracker, 191 DumpManager dumpManager 192 ) { 193 mContext = context.getApplicationContext(); 194 mPackageManager = packageManager; 195 mWakefulnessLifecycle = wakefulnessLifecycle; 196 Events.writeEvent(Events.EVENT_COLLECTION_STARTED); 197 mWorkerLooper = theadFactory.buildLooperOnNewThread( 198 VolumeDialogControllerImpl.class.getSimpleName()); 199 mWorker = new W(mWorkerLooper); 200 mRouter2Manager = MediaRouter2Manager.getInstance(mContext); 201 mMediaSessionsCallbacksW = new MediaSessionsCallbacks(mContext); 202 mMediaSessions = createMediaSessions(mContext, mWorkerLooper, mMediaSessionsCallbacksW); 203 mAudio = audioManager; 204 mNoMan = notificationManager; 205 mObserver = new SettingObserver(mWorker); 206 mRingerModeObservers = new RingerModeObservers( 207 (RingerModeLiveData) ringerModeTracker.getRingerMode(), 208 (RingerModeLiveData) ringerModeTracker.getRingerModeInternal() 209 ); 210 mRingerModeObservers.init(); 211 mBroadcastDispatcher = broadcastDispatcher; 212 mObserver.init(); 213 mReceiver.init(); 214 mVibrator = vibrator; 215 mHasVibrator = mVibrator.hasVibrator(); 216 mAudioService = iAudioService; 217 mKeyguardManager = keyguardManager; 218 mActivityManager = activityManager; 219 mUserTracker = userTracker; 220 mUserTracker.addCallback(mUserChangedCallback, new HandlerExecutor(mWorker)); 221 createCaptioningManagerServiceByUserContext(mUserTracker.getUserContext()); 222 223 dumpManager.registerDumpable("VolumeDialogControllerImpl", this); 224 225 boolean accessibilityVolumeStreamActive = accessibilityManager 226 .isAccessibilityVolumeStreamActive(); 227 mVolumeController.setA11yMode(accessibilityVolumeStreamActive ? 228 VolumePolicy.A11Y_MODE_INDEPENDENT_A11Y_VOLUME : 229 VolumePolicy.A11Y_MODE_MEDIA_A11Y_VOLUME); 230 231 mWakefulnessLifecycle.addObserver(mWakefullnessLifecycleObserver); 232 } 233 getAudioManager()234 public AudioManager getAudioManager() { 235 return mAudio; 236 } 237 dismiss()238 public void dismiss() { 239 mCallbacks.onDismissRequested(Events.DISMISS_REASON_VOLUME_CONTROLLER); 240 } 241 setVolumeController()242 protected void setVolumeController() { 243 try { 244 mAudio.setVolumeController(mVolumeController); 245 } catch (SecurityException e) { 246 Log.w(TAG, "Unable to set the volume controller", e); 247 } 248 } 249 setAudioManagerStreamVolume(int stream, int level, int flag)250 protected void setAudioManagerStreamVolume(int stream, int level, int flag) { 251 mAudio.setStreamVolume(stream, level, flag); 252 } 253 getAudioManagerStreamVolume(int stream)254 protected int getAudioManagerStreamVolume(int stream) { 255 return mAudio.getLastAudibleStreamVolume(stream); 256 } 257 getAudioManagerStreamMaxVolume(int stream)258 protected int getAudioManagerStreamMaxVolume(int stream) { 259 return mAudio.getStreamMaxVolume(stream); 260 } 261 getAudioManagerStreamMinVolume(int stream)262 protected int getAudioManagerStreamMinVolume(int stream) { 263 return mAudio.getStreamMinVolumeInt(stream); 264 } 265 register()266 public void register() { 267 setVolumeController(); 268 setVolumePolicy(mVolumePolicy); 269 showDndTile(); 270 try { 271 mMediaSessions.init(); 272 } catch (SecurityException e) { 273 Log.w(TAG, "No access to media sessions", e); 274 } 275 } 276 setVolumePolicy(VolumePolicy policy)277 public void setVolumePolicy(VolumePolicy policy) { 278 mVolumePolicy = policy; 279 if (mVolumePolicy == null) return; 280 try { 281 mAudio.setVolumePolicy(mVolumePolicy); 282 } catch (NoSuchMethodError e) { 283 Log.w(TAG, "No volume policy api"); 284 } 285 } 286 createMediaSessions(Context context, Looper looper, MediaSessions.Callbacks callbacks)287 protected MediaSessions createMediaSessions(Context context, Looper looper, 288 MediaSessions.Callbacks callbacks) { 289 return new MediaSessions(context, looper, callbacks); 290 } 291 292 @NeverCompile dump(PrintWriter pw, String[] args)293 public void dump(PrintWriter pw, String[] args) { 294 pw.println(VolumeDialogControllerImpl.class.getSimpleName() + " state:"); 295 pw.print(" mVolumePolicy: "); pw.println(mVolumePolicy); 296 pw.print(" mState: "); pw.println(mState.toString(4)); 297 pw.print(" mHasVibrator: "); pw.println(mHasVibrator); 298 synchronized (mMediaSessionsCallbacksW.mRemoteStreams) { 299 pw.print(" mRemoteStreams: "); 300 pw.println(mMediaSessionsCallbacksW.mRemoteStreams 301 .values()); 302 } 303 pw.print(" mShowA11yStream: "); pw.println(mShowA11yStream); 304 pw.println(); 305 mMediaSessions.dump(pw); 306 } 307 addCallback(Callbacks callback, Handler handler)308 public void addCallback(Callbacks callback, Handler handler) { 309 mCallbacks.add(callback, handler); 310 callback.onAccessibilityModeChanged(mShowA11yStream); 311 } 312 setUserActivityListener(UserActivityListener listener)313 public void setUserActivityListener(UserActivityListener listener) { 314 synchronized (this) { 315 mUserActivityListener = listener; 316 } 317 } 318 removeCallback(Callbacks callback)319 public void removeCallback(Callbacks callback) { 320 mCallbacks.remove(callback); 321 } 322 getState()323 public void getState() { 324 mWorker.sendEmptyMessage(W.GET_STATE); 325 } 326 327 /** 328 * We met issues about the wrong state of System Caption in multi-user mode. 329 * It happened in the usage of CaptioningManager Service from SysUI process 330 * that is a global system process of User 0. 331 * Therefore, we have to add callback on UserTracker that allows us to get the Context of 332 * active User and then get the corresponding CaptioningManager Service for further usages. 333 */ 334 private final UserTracker.Callback mUserChangedCallback = 335 new UserTracker.Callback() { 336 @Override 337 public void onUserChanged(int newUser, @NonNull Context userContext) { 338 createCaptioningManagerServiceByUserContext(userContext); 339 } 340 }; 341 createCaptioningManagerServiceByUserContext(@onNull Context userContext)342 private void createCaptioningManagerServiceByUserContext(@NonNull Context userContext) { 343 mCaptioningManager.set(userContext.getSystemService(CaptioningManager.class)); 344 } 345 getCaptionsEnabledState(boolean checkForSwitchState)346 public void getCaptionsEnabledState(boolean checkForSwitchState) { 347 mWorker.obtainMessage(W.GET_CAPTIONS_ENABLED_STATE, checkForSwitchState).sendToTarget(); 348 } 349 setCaptionsEnabledState(boolean enabled)350 public void setCaptionsEnabledState(boolean enabled) { 351 mWorker.obtainMessage(W.SET_CAPTIONS_ENABLED_STATE, enabled).sendToTarget(); 352 } 353 getCaptionsComponentState(boolean fromTooltip)354 public void getCaptionsComponentState(boolean fromTooltip) { 355 mWorker.obtainMessage(W.GET_CAPTIONS_COMPONENT_STATE, fromTooltip).sendToTarget(); 356 } 357 notifyVisible(boolean visible)358 public void notifyVisible(boolean visible) { 359 mWorker.obtainMessage(W.NOTIFY_VISIBLE, visible ? 1 : 0, 0).sendToTarget(); 360 } 361 userActivity()362 public void userActivity() { 363 mWorker.removeMessages(W.USER_ACTIVITY); 364 mWorker.sendEmptyMessage(W.USER_ACTIVITY); 365 } 366 setRingerMode(int value, boolean external)367 public void setRingerMode(int value, boolean external) { 368 mWorker.obtainMessage(W.SET_RINGER_MODE, value, external ? 1 : 0).sendToTarget(); 369 } 370 setZenMode(int value)371 public void setZenMode(int value) { 372 mWorker.obtainMessage(W.SET_ZEN_MODE, value, 0).sendToTarget(); 373 } 374 setExitCondition(Condition condition)375 public void setExitCondition(Condition condition) { 376 mWorker.obtainMessage(W.SET_EXIT_CONDITION, condition).sendToTarget(); 377 } 378 setStreamMute(int stream, boolean mute)379 public void setStreamMute(int stream, boolean mute) { 380 mWorker.obtainMessage(W.SET_STREAM_MUTE, stream, mute ? 1 : 0).sendToTarget(); 381 } 382 setStreamVolume(int stream, int level)383 public void setStreamVolume(int stream, int level) { 384 mWorker.obtainMessage(W.SET_STREAM_VOLUME, stream, level).sendToTarget(); 385 } 386 setActiveStream(int stream)387 public void setActiveStream(int stream) { 388 mWorker.obtainMessage(W.SET_ACTIVE_STREAM, stream, 0).sendToTarget(); 389 } 390 setEnableDialogs(boolean volumeUi, boolean safetyWarning)391 public void setEnableDialogs(boolean volumeUi, boolean safetyWarning) { 392 mShowVolumeDialog = volumeUi; 393 mShowSafetyWarning = safetyWarning; 394 } 395 396 @Override scheduleTouchFeedback()397 public void scheduleTouchFeedback() { 398 mLastToggledRingerOn = System.currentTimeMillis(); 399 } 400 playTouchFeedback()401 private void playTouchFeedback() { 402 if (System.currentTimeMillis() - mLastToggledRingerOn < TOUCH_FEEDBACK_TIMEOUT_MS) { 403 try { 404 mAudioService.playSoundEffect(AudioManager.FX_KEYPRESS_STANDARD, 405 mUserTracker.getUserId()); 406 } catch (RemoteException e) { 407 // ignore 408 } 409 } 410 } 411 vibrate(VibrationEffect effect)412 public void vibrate(VibrationEffect effect) { 413 mVibrator.vibrate(effect, SONIFICIATION_VIBRATION_ATTRIBUTES); 414 } 415 hasVibrator()416 public boolean hasVibrator() { 417 return mHasVibrator; 418 } 419 onNotifyVisibleW(boolean visible)420 private void onNotifyVisibleW(boolean visible) { 421 mAudio.notifyVolumeControllerVisible(mVolumeController, visible); 422 if (!visible) { 423 if (updateActiveStreamW(-1)) { 424 mCallbacks.onStateChanged(mState); 425 } 426 } 427 } 428 onUserActivityW()429 private void onUserActivityW() { 430 synchronized (this) { 431 if (mUserActivityListener != null) { 432 mUserActivityListener.onUserActivity(); 433 } 434 } 435 } 436 onShowSafetyWarningW(int flags)437 private void onShowSafetyWarningW(int flags) { 438 if (mShowSafetyWarning) { 439 mCallbacks.onShowSafetyWarning(flags); 440 } 441 } 442 onShowCsdWarningW(@udioManager.CsdWarning int csdWarning, int durationMs)443 private void onShowCsdWarningW(@AudioManager.CsdWarning int csdWarning, int durationMs) { 444 mCallbacks.onShowCsdWarning(csdWarning, durationMs); 445 } 446 onGetCaptionsComponentStateW(boolean fromTooltip)447 private void onGetCaptionsComponentStateW(boolean fromTooltip) { 448 CaptioningManager captioningManager = mCaptioningManager.get(); 449 if (null != captioningManager) { 450 mCallbacks.onCaptionComponentStateChanged( 451 captioningManager.isSystemAudioCaptioningUiEnabled(), fromTooltip); 452 } else { 453 Log.e(TAG, "onGetCaptionsComponentStateW(), null captioningManager"); 454 } 455 } 456 onGetCaptionsEnabledStateW(boolean checkForSwitchState)457 private void onGetCaptionsEnabledStateW(boolean checkForSwitchState) { 458 CaptioningManager captioningManager = mCaptioningManager.get(); 459 if (null != captioningManager) { 460 mCallbacks.onCaptionEnabledStateChanged( 461 captioningManager.isSystemAudioCaptioningEnabled(), checkForSwitchState); 462 } else { 463 Log.e(TAG, "onGetCaptionsEnabledStateW(), null captioningManager"); 464 } 465 } 466 onSetCaptionsEnabledStateW(boolean enabled)467 private void onSetCaptionsEnabledStateW(boolean enabled) { 468 CaptioningManager captioningManager = mCaptioningManager.get(); 469 if (null != captioningManager) { 470 captioningManager.setSystemAudioCaptioningEnabled(enabled); 471 mCallbacks.onCaptionEnabledStateChanged( 472 captioningManager.isSystemAudioCaptioningEnabled(), false); 473 } else { 474 Log.e(TAG, "onGetCaptionsEnabledStateW(), null captioningManager"); 475 } 476 } 477 onAccessibilityModeChanged(Boolean showA11yStream)478 private void onAccessibilityModeChanged(Boolean showA11yStream) { 479 mCallbacks.onAccessibilityModeChanged(showA11yStream); 480 } 481 checkRoutedToBluetoothW(int stream)482 private boolean checkRoutedToBluetoothW(int stream) { 483 boolean changed = false; 484 if (stream == AudioManager.STREAM_MUSIC) { 485 // Note: Here we didn't use DEVICE_OUT_BLE_SPEAKER and DEVICE_OUT_BLE_BROADCAST 486 // Since their values overlap with DEVICE_OUT_EARPIECE and DEVICE_OUT_SPEAKER. 487 // Anyway, we can check BLE devices by using just DEVICE_OUT_BLE_HEADSET. 488 final boolean routedToBluetooth = 489 (mAudio.getDevicesForStream(AudioManager.STREAM_MUSIC) & 490 (AudioManager.DEVICE_OUT_BLUETOOTH_A2DP | 491 AudioManager.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES | 492 AudioManager.DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER | 493 AudioManager.DEVICE_OUT_BLE_HEADSET)) != 0; 494 changed |= updateStreamRoutedToBluetoothW(stream, routedToBluetooth); 495 } else if (stream == AudioManager.STREAM_VOICE_CALL) { 496 final boolean routedToBluetooth = 497 (mAudio.getDevicesForStream(AudioManager.STREAM_VOICE_CALL) 498 & AudioManager.DEVICE_OUT_BLE_HEADSET) != 0; 499 changed |= updateStreamRoutedToBluetoothW(stream, routedToBluetooth); 500 } 501 return changed; 502 } 503 shouldShowUI(int flags)504 private boolean shouldShowUI(int flags) { 505 int wakefulness = mWakefulnessLifecycle.getWakefulness(); 506 return wakefulness != WakefulnessLifecycle.WAKEFULNESS_ASLEEP 507 && wakefulness != WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP 508 && mDeviceInteractive && (flags & AudioManager.FLAG_SHOW_UI) != 0 509 && mShowVolumeDialog; 510 } 511 onVolumeChangedW(int stream, int flags)512 boolean onVolumeChangedW(int stream, int flags) { 513 final boolean showUI = shouldShowUI(flags); 514 final boolean fromKey = (flags & AudioManager.FLAG_FROM_KEY) != 0; 515 final boolean showVibrateHint = (flags & AudioManager.FLAG_SHOW_VIBRATE_HINT) != 0; 516 final boolean showSilentHint = (flags & AudioManager.FLAG_SHOW_SILENT_HINT) != 0; 517 boolean changed = false; 518 if (showUI) { 519 changed |= updateActiveStreamW(stream); 520 } 521 int lastAudibleStreamVolume = getAudioManagerStreamVolume(stream); 522 changed |= updateStreamLevelW(stream, lastAudibleStreamVolume); 523 changed |= checkRoutedToBluetoothW(showUI ? AudioManager.STREAM_MUSIC : stream); 524 if (changed) { 525 mCallbacks.onStateChanged(mState); 526 } 527 if (showUI) { 528 onShowRequestedW(Events.SHOW_REASON_VOLUME_CHANGED); 529 } 530 if (showVibrateHint) { 531 mCallbacks.onShowVibrateHint(); 532 } 533 if (showSilentHint) { 534 mCallbacks.onShowSilentHint(); 535 } 536 if (changed && fromKey) { 537 Events.writeEvent(Events.EVENT_KEY, stream, lastAudibleStreamVolume); 538 mCallbacks.onVolumeChangedFromKey(); 539 } 540 return changed; 541 } 542 updateActiveStreamW(int activeStream)543 private boolean updateActiveStreamW(int activeStream) { 544 if (activeStream == mState.activeStream) return false; 545 mState.activeStream = activeStream; 546 Events.writeEvent(Events.EVENT_ACTIVE_STREAM_CHANGED, activeStream); 547 if (D.BUG) Log.d(TAG, "updateActiveStreamW " + activeStream); 548 final int s = activeStream < DYNAMIC_STREAM_START_INDEX ? activeStream : -1; 549 if (D.BUG) Log.d(TAG, "forceVolumeControlStream " + s); 550 mAudio.forceVolumeControlStream(s); 551 return true; 552 } 553 554 private StreamState streamStateW(int stream) { 555 StreamState ss = mState.states.get(stream); 556 if (ss == null) { 557 ss = new StreamState(); 558 mState.states.put(stream, ss); 559 } 560 return ss; 561 } 562 563 private void onGetStateW() { 564 for (int stream : STREAMS.keySet()) { 565 updateStreamLevelW(stream, getAudioManagerStreamVolume(stream)); 566 streamStateW(stream).levelMin = getAudioManagerStreamMinVolume(stream); 567 streamStateW(stream).levelMax = Math.max(1, getAudioManagerStreamMaxVolume(stream)); 568 updateStreamMuteW(stream, mAudio.isStreamMute(stream)); 569 final StreamState ss = streamStateW(stream); 570 ss.muteSupported = mAudio.isStreamMutableByUi(stream); 571 ss.name = STREAMS.get(stream); 572 checkRoutedToBluetoothW(stream); 573 } 574 // We are not destroyed so this is listening and has updated information 575 updateRingerModeExternalW(mRingerModeObservers.mRingerMode.getValue()); 576 updateZenModeW(); 577 updateZenConfig(); 578 updateEffectsSuppressorW(mNoMan.getEffectsSuppressor()); 579 mCallbacks.onStateChanged(mState); 580 } 581 582 private boolean updateStreamRoutedToBluetoothW(int stream, boolean routedToBluetooth) { 583 final StreamState ss = streamStateW(stream); 584 if (ss.routedToBluetooth == routedToBluetooth) return false; 585 ss.routedToBluetooth = routedToBluetooth; 586 if (D.BUG) Log.d(TAG, "updateStreamRoutedToBluetoothW stream=" + stream 587 + " routedToBluetooth=" + routedToBluetooth); 588 return true; 589 } 590 591 private boolean updateStreamLevelW(int stream, int level) { 592 final StreamState ss = streamStateW(stream); 593 if (ss.level == level) return false; 594 ss.level = level; 595 if (isLogWorthy(stream)) { 596 Events.writeEvent(Events.EVENT_LEVEL_CHANGED, stream, level); 597 } 598 return true; 599 } 600 601 private static boolean isLogWorthy(int stream) { 602 switch (stream) { 603 case AudioSystem.STREAM_ALARM: 604 case AudioSystem.STREAM_BLUETOOTH_SCO: 605 case AudioSystem.STREAM_MUSIC: 606 case AudioSystem.STREAM_RING: 607 case AudioSystem.STREAM_SYSTEM: 608 case AudioSystem.STREAM_VOICE_CALL: 609 return true; 610 } 611 return false; 612 } 613 614 private boolean updateStreamMuteW(int stream, boolean muted) { 615 final StreamState ss = streamStateW(stream); 616 if (ss.muted == muted) return false; 617 ss.muted = muted; 618 if (isLogWorthy(stream)) { 619 Events.writeEvent(Events.EVENT_MUTE_CHANGED, stream, muted); 620 } 621 if (muted && isRinger(stream)) { 622 updateRingerModeInternalW(mRingerModeObservers.mRingerModeInternal.getValue()); 623 } 624 return true; 625 } 626 627 private static boolean isRinger(int stream) { 628 return stream == AudioManager.STREAM_RING || stream == AudioManager.STREAM_NOTIFICATION; 629 } 630 631 private boolean updateEffectsSuppressorW(ComponentName effectsSuppressor) { 632 if (Objects.equals(mState.effectsSuppressor, effectsSuppressor)) return false; 633 mState.effectsSuppressor = effectsSuppressor; 634 mState.effectsSuppressorName = 635 getApplicationName(mPackageManager, mState.effectsSuppressor); 636 Events.writeEvent(Events.EVENT_SUPPRESSOR_CHANGED, mState.effectsSuppressor, 637 mState.effectsSuppressorName); 638 return true; 639 } 640 641 private static String getApplicationName(PackageManager pm, ComponentName component) { 642 if (component == null) return null; 643 final String pkg = component.getPackageName(); 644 try { 645 final ApplicationInfo ai = pm.getApplicationInfo(pkg, 0); 646 final String rt = Objects.toString(ai.loadLabel(pm), "").trim(); 647 if (rt.length() > 0) { 648 return rt; 649 } 650 } catch (NameNotFoundException e) {} 651 return pkg; 652 } 653 updateZenModeW()654 private boolean updateZenModeW() { 655 final int zen = Settings.Global.getInt(mContext.getContentResolver(), 656 Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF); 657 if (mState.zenMode == zen) return false; 658 mState.zenMode = zen; 659 Events.writeEvent(Events.EVENT_ZEN_MODE_CHANGED, zen); 660 return true; 661 } 662 updateZenConfig()663 private boolean updateZenConfig() { 664 final NotificationManager.Policy policy = mNoMan.getConsolidatedNotificationPolicy(); 665 boolean disallowAlarms = (policy.priorityCategories & NotificationManager.Policy 666 .PRIORITY_CATEGORY_ALARMS) == 0; 667 boolean disallowMedia = (policy.priorityCategories & NotificationManager.Policy 668 .PRIORITY_CATEGORY_MEDIA) == 0; 669 boolean disallowSystem = (policy.priorityCategories & NotificationManager.Policy 670 .PRIORITY_CATEGORY_SYSTEM) == 0; 671 // ringer controls notifications, ringer and system sounds, so only disallow ringer changes 672 // if all relevant (notifications + ringer + system) sounds are not allowed to bypass DND 673 boolean disallowRinger = ZenModeConfig.areAllPriorityOnlyRingerSoundsMuted(policy); 674 if (mState.disallowAlarms == disallowAlarms 675 && mState.disallowMedia == disallowMedia 676 && mState.disallowRinger == disallowRinger 677 && mState.disallowSystem == disallowSystem) { 678 return false; 679 } 680 mState.disallowAlarms = disallowAlarms; 681 mState.disallowMedia = disallowMedia; 682 mState.disallowSystem = disallowSystem; 683 mState.disallowRinger = disallowRinger; 684 Events.writeEvent(Events.EVENT_ZEN_CONFIG_CHANGED, "disallowAlarms=" 685 + disallowAlarms + " disallowMedia=" + disallowMedia + " disallowSystem=" 686 + disallowSystem + " disallowRinger=" + disallowRinger); 687 return true; 688 } 689 updateRingerModeExternalW(int rm)690 private boolean updateRingerModeExternalW(int rm) { 691 if (rm == mState.ringerModeExternal) return false; 692 mState.ringerModeExternal = rm; 693 Events.writeEvent(Events.EVENT_EXTERNAL_RINGER_MODE_CHANGED, rm); 694 return true; 695 } 696 updateRingerModeInternalW(int rm)697 private boolean updateRingerModeInternalW(int rm) { 698 if (rm == mState.ringerModeInternal) return false; 699 mState.ringerModeInternal = rm; 700 Events.writeEvent(Events.EVENT_INTERNAL_RINGER_MODE_CHANGED, rm); 701 702 if (mState.ringerModeInternal == RINGER_MODE_NORMAL) { 703 playTouchFeedback(); 704 } 705 706 return true; 707 } 708 onShowRequestedW(int reason)709 private void onShowRequestedW(int reason) { 710 mCallbacks.onShowRequested(reason, mKeyguardManager.isKeyguardLocked(), 711 mActivityManager.getLockTaskModeState()); 712 } 713 onSetRingerModeW(int mode, boolean external)714 private void onSetRingerModeW(int mode, boolean external) { 715 if (external) { 716 mAudio.setRingerMode(mode); 717 } else { 718 mAudio.setRingerModeInternal(mode); 719 } 720 } 721 onSetStreamMuteW(int stream, boolean mute)722 private void onSetStreamMuteW(int stream, boolean mute) { 723 mAudio.adjustStreamVolume(stream, mute ? AudioManager.ADJUST_MUTE 724 : AudioManager.ADJUST_UNMUTE, 0); 725 } 726 onSetStreamVolumeW(int stream, int level)727 private void onSetStreamVolumeW(int stream, int level) { 728 if (D.BUG) Log.d(TAG, "onSetStreamVolume " + stream + " level=" + level); 729 if (stream >= DYNAMIC_STREAM_START_INDEX) { 730 mMediaSessionsCallbacksW.setStreamVolume(stream, level); 731 return; 732 } 733 setAudioManagerStreamVolume(stream, level, 0); 734 } 735 onSetActiveStreamW(int stream)736 private void onSetActiveStreamW(int stream) { 737 boolean changed = updateActiveStreamW(stream); 738 if (changed) { 739 mCallbacks.onStateChanged(mState); 740 } 741 } 742 onSetExitConditionW(Condition condition)743 private void onSetExitConditionW(Condition condition) { 744 mNoMan.setZenMode(mState.zenMode, condition != null ? condition.id : null, TAG); 745 } 746 onSetZenModeW(int mode)747 private void onSetZenModeW(int mode) { 748 if (D.BUG) Log.d(TAG, "onSetZenModeW " + mode); 749 mNoMan.setZenMode(mode, null, TAG); 750 } 751 onDismissRequestedW(int reason)752 private void onDismissRequestedW(int reason) { 753 mCallbacks.onDismissRequested(reason); 754 } 755 showDndTile()756 public void showDndTile() { 757 if (D.BUG) Log.d(TAG, "showDndTile"); 758 DndTile.setVisible(mContext, true); 759 } 760 761 private final class VC extends IVolumeController.Stub { 762 private final String TAG = VolumeDialogControllerImpl.TAG + ".VC"; 763 764 @Override displaySafeVolumeWarning(int flags)765 public void displaySafeVolumeWarning(int flags) throws RemoteException { 766 if (D.BUG) Log.d(TAG, "displaySafeVolumeWarning " 767 + Util.audioManagerFlagsToString(flags)); 768 mWorker.obtainMessage(W.SHOW_SAFETY_WARNING, flags, 0).sendToTarget(); 769 } 770 771 /** 772 * Display a sound-dose related warning. 773 * This method will never be called if the CSD (Computed Sound Dose) feature is 774 * not enabled. See com.android.android.server.audio.SoundDoseHelper for the state of 775 * the feature. 776 * @param csdWarning the type of warning to display, values are one of 777 * {@link android.media.AudioManager#CSD_WARNING_DOSE_REACHED_1X}, 778 * {@link android.media.AudioManager#CSD_WARNING_DOSE_REPEATED_5X}, 779 * {@link android.media.AudioManager#CSD_WARNING_MOMENTARY_EXPOSURE}, 780 * {@link android.media.AudioManager#CSD_WARNING_ACCUMULATION_START}. 781 * @param displayDurationMs the time expressed in milliseconds after which the dialog will be 782 * automatically dismissed, or -1 if there is no automatic timeout. 783 */ 784 @Override displayCsdWarning(int csdWarning, int displayDurationMs)785 public void displayCsdWarning(int csdWarning, int displayDurationMs) throws RemoteException 786 { 787 if (D.BUG) Log.d(TAG, "displayCsdWarning durMs=" + displayDurationMs); 788 mWorker.obtainMessage(W.SHOW_CSD_WARNING, csdWarning, displayDurationMs) 789 .sendToTarget(); 790 } 791 792 @Override volumeChanged(int streamType, int flags)793 public void volumeChanged(int streamType, int flags) throws RemoteException { 794 if (D.BUG) Log.d(TAG, "volumeChanged " + AudioSystem.streamToString(streamType) 795 + " " + Util.audioManagerFlagsToString(flags)); 796 mWorker.obtainMessage(W.VOLUME_CHANGED, streamType, flags).sendToTarget(); 797 } 798 799 @Override masterMuteChanged(int flags)800 public void masterMuteChanged(int flags) throws RemoteException { 801 if (D.BUG) Log.d(TAG, "masterMuteChanged"); 802 } 803 804 @Override setLayoutDirection(int layoutDirection)805 public void setLayoutDirection(int layoutDirection) throws RemoteException { 806 if (D.BUG) Log.d(TAG, "setLayoutDirection"); 807 mWorker.obtainMessage(W.LAYOUT_DIRECTION_CHANGED, layoutDirection, 0).sendToTarget(); 808 } 809 810 @Override dismiss()811 public void dismiss() throws RemoteException { 812 if (D.BUG) Log.d(TAG, "dismiss requested"); 813 mWorker.obtainMessage(W.DISMISS_REQUESTED, Events.DISMISS_REASON_VOLUME_CONTROLLER, 0) 814 .sendToTarget(); 815 mWorker.sendEmptyMessage(W.DISMISS_REQUESTED); 816 } 817 818 @Override setA11yMode(int mode)819 public void setA11yMode(int mode) { 820 if (D.BUG) Log.d(TAG, "setA11yMode to " + mode); 821 switch (mode) { 822 case VolumePolicy.A11Y_MODE_MEDIA_A11Y_VOLUME: 823 // "legacy" mode 824 mShowA11yStream = false; 825 break; 826 case VolumePolicy.A11Y_MODE_INDEPENDENT_A11Y_VOLUME: 827 mShowA11yStream = true; 828 break; 829 default: 830 Log.e(TAG, "Invalid accessibility mode " + mode); 831 break; 832 } 833 mWorker.obtainMessage(W.ACCESSIBILITY_MODE_CHANGED, mShowA11yStream).sendToTarget(); 834 } 835 } 836 837 private final class W extends Handler { 838 private static final int VOLUME_CHANGED = 1; 839 private static final int DISMISS_REQUESTED = 2; 840 private static final int GET_STATE = 3; 841 private static final int SET_RINGER_MODE = 4; 842 private static final int SET_ZEN_MODE = 5; 843 private static final int SET_EXIT_CONDITION = 6; 844 private static final int SET_STREAM_MUTE = 7; 845 private static final int LAYOUT_DIRECTION_CHANGED = 8; 846 private static final int CONFIGURATION_CHANGED = 9; 847 private static final int SET_STREAM_VOLUME = 10; 848 private static final int SET_ACTIVE_STREAM = 11; 849 private static final int NOTIFY_VISIBLE = 12; 850 private static final int USER_ACTIVITY = 13; 851 private static final int SHOW_SAFETY_WARNING = 14; 852 private static final int ACCESSIBILITY_MODE_CHANGED = 15; 853 private static final int GET_CAPTIONS_COMPONENT_STATE = 16; 854 private static final int SHOW_CSD_WARNING = 17; 855 private static final int GET_CAPTIONS_ENABLED_STATE = 18; 856 private static final int SET_CAPTIONS_ENABLED_STATE = 19; 857 W(Looper looper)858 W(Looper looper) { 859 super(looper); 860 } 861 862 @Override handleMessage(Message msg)863 public void handleMessage(Message msg) { 864 switch (msg.what) { 865 case VOLUME_CHANGED: onVolumeChangedW(msg.arg1, msg.arg2); break; 866 case DISMISS_REQUESTED: onDismissRequestedW(msg.arg1); break; 867 case GET_STATE: onGetStateW(); break; 868 case SET_RINGER_MODE: onSetRingerModeW(msg.arg1, msg.arg2 != 0); break; 869 case SET_ZEN_MODE: onSetZenModeW(msg.arg1); break; 870 case SET_EXIT_CONDITION: onSetExitConditionW((Condition) msg.obj); break; 871 case SET_STREAM_MUTE: onSetStreamMuteW(msg.arg1, msg.arg2 != 0); break; 872 case LAYOUT_DIRECTION_CHANGED: mCallbacks.onLayoutDirectionChanged(msg.arg1); break; 873 case CONFIGURATION_CHANGED: mCallbacks.onConfigurationChanged(); break; 874 case SET_STREAM_VOLUME: onSetStreamVolumeW(msg.arg1, msg.arg2); break; 875 case SET_ACTIVE_STREAM: onSetActiveStreamW(msg.arg1); break; 876 case NOTIFY_VISIBLE: onNotifyVisibleW(msg.arg1 != 0); break; 877 case USER_ACTIVITY: onUserActivityW(); break; 878 case SHOW_SAFETY_WARNING: onShowSafetyWarningW(msg.arg1); break; 879 case GET_CAPTIONS_COMPONENT_STATE: 880 onGetCaptionsComponentStateW((Boolean) msg.obj); break; 881 case ACCESSIBILITY_MODE_CHANGED: onAccessibilityModeChanged((Boolean) msg.obj); 882 break; 883 case SHOW_CSD_WARNING: onShowCsdWarningW(msg.arg1, msg.arg2); break; 884 case GET_CAPTIONS_ENABLED_STATE: 885 onGetCaptionsEnabledStateW((Boolean) msg.obj); break; 886 case SET_CAPTIONS_ENABLED_STATE: 887 onSetCaptionsEnabledStateW((Boolean) msg.obj); break; 888 } 889 } 890 } 891 892 static class C implements Callbacks { 893 private final Map<Callbacks, Handler> mCallbackMap = new ConcurrentHashMap<>(); 894 add(Callbacks callback, Handler handler)895 public void add(Callbacks callback, Handler handler) { 896 if (callback == null || handler == null) throw new IllegalArgumentException(); 897 mCallbackMap.put(callback, handler); 898 } 899 remove(Callbacks callback)900 public void remove(Callbacks callback) { 901 mCallbackMap.remove(callback); 902 } 903 904 @Override onShowRequested( final int reason, final boolean keyguardLocked, final int lockTaskModeState)905 public void onShowRequested( 906 final int reason, 907 final boolean keyguardLocked, 908 final int lockTaskModeState) { 909 for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) { 910 entry.getValue().post(new Runnable() { 911 @Override 912 public void run() { 913 entry.getKey().onShowRequested(reason, keyguardLocked, lockTaskModeState); 914 } 915 }); 916 } 917 } 918 919 @Override onDismissRequested(final int reason)920 public void onDismissRequested(final int reason) { 921 for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) { 922 entry.getValue().post(new Runnable() { 923 @Override 924 public void run() { 925 entry.getKey().onDismissRequested(reason); 926 } 927 }); 928 } 929 } 930 931 @Override onStateChanged(final State state)932 public void onStateChanged(final State state) { 933 final long time = System.currentTimeMillis(); 934 final State copy = state.copy(); 935 for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) { 936 entry.getValue().post(new Runnable() { 937 @Override 938 public void run() { 939 entry.getKey().onStateChanged(copy); 940 } 941 }); 942 } 943 Events.writeState(time, copy); 944 } 945 946 @Override onLayoutDirectionChanged(final int layoutDirection)947 public void onLayoutDirectionChanged(final int layoutDirection) { 948 for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) { 949 entry.getValue().post(new Runnable() { 950 @Override 951 public void run() { 952 entry.getKey().onLayoutDirectionChanged(layoutDirection); 953 } 954 }); 955 } 956 } 957 958 @Override onConfigurationChanged()959 public void onConfigurationChanged() { 960 for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) { 961 entry.getValue().post(new Runnable() { 962 @Override 963 public void run() { 964 entry.getKey().onConfigurationChanged(); 965 } 966 }); 967 } 968 } 969 970 @Override onShowVibrateHint()971 public void onShowVibrateHint() { 972 for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) { 973 entry.getValue().post(new Runnable() { 974 @Override 975 public void run() { 976 entry.getKey().onShowVibrateHint(); 977 } 978 }); 979 } 980 } 981 982 @Override onShowSilentHint()983 public void onShowSilentHint() { 984 for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) { 985 entry.getValue().post(new Runnable() { 986 @Override 987 public void run() { 988 entry.getKey().onShowSilentHint(); 989 } 990 }); 991 } 992 } 993 994 @Override onScreenOff()995 public void onScreenOff() { 996 for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) { 997 entry.getValue().post(new Runnable() { 998 @Override 999 public void run() { 1000 entry.getKey().onScreenOff(); 1001 } 1002 }); 1003 } 1004 } 1005 1006 @Override onShowSafetyWarning(final int flags)1007 public void onShowSafetyWarning(final int flags) { 1008 for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) { 1009 entry.getValue().post(new Runnable() { 1010 @Override 1011 public void run() { 1012 entry.getKey().onShowSafetyWarning(flags); 1013 } 1014 }); 1015 } 1016 } 1017 1018 @Override onShowCsdWarning(int csdWarning, int durationMs)1019 public void onShowCsdWarning(int csdWarning, int durationMs) { 1020 if (Callbacks.VERSION < 2) { 1021 return; 1022 } 1023 for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) { 1024 entry.getValue().post(new Runnable() { 1025 @Override 1026 public void run() { 1027 entry.getKey().onShowCsdWarning(csdWarning, durationMs); 1028 } 1029 }); 1030 } 1031 } 1032 1033 @Override onVolumeChangedFromKey()1034 public void onVolumeChangedFromKey() { 1035 for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) { 1036 entry.getValue().post(new Runnable() { 1037 @Override 1038 public void run() { 1039 entry.getKey().onVolumeChangedFromKey(); 1040 } 1041 }); 1042 } 1043 } 1044 1045 @Override onAccessibilityModeChanged(Boolean showA11yStream)1046 public void onAccessibilityModeChanged(Boolean showA11yStream) { 1047 boolean show = showA11yStream != null && showA11yStream; 1048 for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) { 1049 entry.getValue().post(new Runnable() { 1050 @Override 1051 public void run() { 1052 entry.getKey().onAccessibilityModeChanged(show); 1053 } 1054 }); 1055 } 1056 } 1057 1058 @Override onCaptionComponentStateChanged( Boolean isComponentEnabled, Boolean fromTooltip)1059 public void onCaptionComponentStateChanged( 1060 Boolean isComponentEnabled, Boolean fromTooltip) { 1061 boolean componentEnabled = isComponentEnabled != null && isComponentEnabled; 1062 for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) { 1063 entry.getValue().post( 1064 () -> entry.getKey().onCaptionComponentStateChanged( 1065 componentEnabled, fromTooltip)); 1066 } 1067 } 1068 1069 @Override onCaptionEnabledStateChanged(Boolean isEnabled, Boolean checkBeforeSwitch)1070 public void onCaptionEnabledStateChanged(Boolean isEnabled, Boolean checkBeforeSwitch) { 1071 boolean captionsEnabled = isEnabled != null && isEnabled; 1072 for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) { 1073 entry.getValue().post( 1074 () -> entry.getKey().onCaptionEnabledStateChanged( 1075 captionsEnabled, checkBeforeSwitch)); 1076 } 1077 } 1078 1079 } 1080 1081 private final class RingerModeObservers { 1082 1083 private final RingerModeLiveData mRingerMode; 1084 private final RingerModeLiveData mRingerModeInternal; 1085 1086 private final Observer<Integer> mRingerModeObserver = new Observer<Integer>() { 1087 @Override 1088 public void onChanged(Integer value) { 1089 mWorker.post(() -> { 1090 final int rm = value; 1091 if (mRingerMode.getInitialSticky()) { 1092 mState.ringerModeExternal = rm; 1093 } 1094 if (D.BUG) { 1095 Log.d(TAG, "onChange ringer_mode rm=" 1096 + Util.ringerModeToString(rm)); 1097 } 1098 if (updateRingerModeExternalW(rm)) { 1099 mCallbacks.onStateChanged(mState); 1100 } 1101 } 1102 ); 1103 } 1104 }; 1105 1106 private final Observer<Integer> mRingerModeInternalObserver = new Observer<Integer>() { 1107 @Override 1108 public void onChanged(Integer value) { 1109 mWorker.post(() -> { 1110 final int rm = value; 1111 if (mRingerModeInternal.getInitialSticky()) { 1112 mState.ringerModeInternal = rm; 1113 } 1114 if (D.BUG) { 1115 Log.d(TAG, "onChange internal_ringer_mode rm=" 1116 + Util.ringerModeToString(rm)); 1117 } 1118 if (updateRingerModeInternalW(rm)) { 1119 mCallbacks.onStateChanged(mState); 1120 } 1121 } 1122 ); 1123 } 1124 }; 1125 RingerModeObservers(RingerModeLiveData ringerMode, RingerModeLiveData ringerModeInternal)1126 RingerModeObservers(RingerModeLiveData ringerMode, 1127 RingerModeLiveData ringerModeInternal) { 1128 mRingerMode = ringerMode; 1129 mRingerModeInternal = ringerModeInternal; 1130 } 1131 init()1132 public void init() { 1133 int initialValue = mRingerMode.getValue(); 1134 if (initialValue != -1) { 1135 // If it's not -1, set it to the initial value, if it's -1, it means that the 1136 // tracker is not listening already and will obtain the sticky value. 1137 mState.ringerModeExternal = initialValue; 1138 } 1139 mRingerMode.observeForever(mRingerModeObserver); 1140 initialValue = mRingerModeInternal.getValue(); 1141 if (initialValue != -1) { 1142 // If it's not -1, set it to the initial value, if it's -1, it means that the 1143 // tracker is not listening already and will obtain the sticky value. 1144 mState.ringerModeInternal = initialValue; 1145 } 1146 mRingerModeInternal.observeForever(mRingerModeInternalObserver); 1147 } 1148 destroy()1149 public void destroy() { 1150 mRingerMode.removeObserver(mRingerModeObserver); 1151 mRingerModeInternal.removeObserver(mRingerModeInternalObserver); 1152 } 1153 } 1154 1155 private final class SettingObserver extends ContentObserver { 1156 private final Uri ZEN_MODE_URI = 1157 Settings.Global.getUriFor(Settings.Global.ZEN_MODE); 1158 private final Uri ZEN_MODE_CONFIG_URI = 1159 Settings.Global.getUriFor(Settings.Global.ZEN_MODE_CONFIG_ETAG); 1160 SettingObserver(Handler handler)1161 public SettingObserver(Handler handler) { 1162 super(handler); 1163 } 1164 init()1165 public void init() { 1166 mContext.getContentResolver().registerContentObserver(ZEN_MODE_URI, false, this); 1167 mContext.getContentResolver().registerContentObserver(ZEN_MODE_CONFIG_URI, false, this); 1168 } 1169 destroy()1170 public void destroy() { 1171 mContext.getContentResolver().unregisterContentObserver(this); 1172 } 1173 1174 @Override onChange(boolean selfChange, Uri uri)1175 public void onChange(boolean selfChange, Uri uri) { 1176 boolean changed = false; 1177 if (ZEN_MODE_URI.equals(uri)) { 1178 changed = updateZenModeW(); 1179 } 1180 if (ZEN_MODE_CONFIG_URI.equals(uri)) { 1181 changed |= updateZenConfig(); 1182 } 1183 1184 if (changed) { 1185 mCallbacks.onStateChanged(mState); 1186 } 1187 } 1188 } 1189 1190 private final class Receiver extends BroadcastReceiver { 1191 init()1192 public void init() { 1193 final IntentFilter filter = new IntentFilter(); 1194 filter.addAction(AudioManager.VOLUME_CHANGED_ACTION); 1195 filter.addAction(AudioManager.STREAM_DEVICES_CHANGED_ACTION); 1196 filter.addAction(AudioManager.STREAM_MUTE_CHANGED_ACTION); 1197 filter.addAction(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED); 1198 filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); 1199 filter.addAction(Intent.ACTION_SCREEN_OFF); 1200 filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); 1201 mBroadcastDispatcher.registerReceiverWithHandler(this, filter, mWorker); 1202 } 1203 destroy()1204 public void destroy() { 1205 mBroadcastDispatcher.unregisterReceiver(this); 1206 } 1207 1208 @Override onReceive(Context context, Intent intent)1209 public void onReceive(Context context, Intent intent) { 1210 final String action = intent.getAction(); 1211 boolean changed = false; 1212 if (action.equals(AudioManager.VOLUME_CHANGED_ACTION)) { 1213 final int stream = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1); 1214 final int level = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, -1); 1215 final int oldLevel = intent 1216 .getIntExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, -1); 1217 if (D.BUG) Log.d(TAG, "onReceive VOLUME_CHANGED_ACTION stream=" + stream 1218 + " level=" + level + " oldLevel=" + oldLevel); 1219 changed = updateStreamLevelW(stream, level); 1220 } else if (action.equals(AudioManager.STREAM_DEVICES_CHANGED_ACTION)) { 1221 final int stream = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1); 1222 final int devices = intent 1223 .getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_DEVICES, -1); 1224 final int oldDevices = intent 1225 .getIntExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_DEVICES, -1); 1226 if (D.BUG) Log.d(TAG, "onReceive STREAM_DEVICES_CHANGED_ACTION stream=" 1227 + stream + " devices=" + devices + " oldDevices=" + oldDevices); 1228 changed = checkRoutedToBluetoothW(stream); 1229 changed |= onVolumeChangedW(stream, 0); 1230 } else if (action.equals(AudioManager.STREAM_MUTE_CHANGED_ACTION)) { 1231 final int stream = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1); 1232 final boolean muted = intent 1233 .getBooleanExtra(AudioManager.EXTRA_STREAM_VOLUME_MUTED, false); 1234 if (D.BUG) Log.d(TAG, "onReceive STREAM_MUTE_CHANGED_ACTION stream=" + stream 1235 + " muted=" + muted); 1236 changed = updateStreamMuteW(stream, muted); 1237 } else if (action.equals(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED)) { 1238 if (D.BUG) Log.d(TAG, "onReceive ACTION_EFFECTS_SUPPRESSOR_CHANGED"); 1239 changed = updateEffectsSuppressorW(mNoMan.getEffectsSuppressor()); 1240 } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) { 1241 if (D.BUG) Log.d(TAG, "onReceive ACTION_CONFIGURATION_CHANGED"); 1242 mCallbacks.onConfigurationChanged(); 1243 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { 1244 if (D.BUG) Log.d(TAG, "onReceive ACTION_SCREEN_OFF"); 1245 mCallbacks.onScreenOff(); 1246 } else if (action.equals(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) { 1247 if (D.BUG) Log.d(TAG, "onReceive ACTION_CLOSE_SYSTEM_DIALOGS"); 1248 dismiss(); 1249 } 1250 if (changed) { 1251 mCallbacks.onStateChanged(mState); 1252 } 1253 } 1254 } 1255 1256 protected final class MediaSessionsCallbacks implements MediaSessions.Callbacks { 1257 private final HashMap<Token, Integer> mRemoteStreams = new HashMap<>(); 1258 1259 private int mNextStream = DYNAMIC_STREAM_START_INDEX; 1260 private final boolean mVolumeAdjustmentForRemoteGroupSessions; 1261 MediaSessionsCallbacks(Context context)1262 public MediaSessionsCallbacks(Context context) { 1263 mVolumeAdjustmentForRemoteGroupSessions = context.getResources().getBoolean( 1264 com.android.internal.R.bool.config_volumeAdjustmentForRemoteGroupSessions); 1265 } 1266 1267 @Override onRemoteUpdate(Token token, String name, PlaybackInfo pi)1268 public void onRemoteUpdate(Token token, String name, PlaybackInfo pi) { 1269 if (showForSession(token)) { 1270 addStream(token, "onRemoteUpdate"); 1271 1272 int stream = 0; 1273 synchronized (mRemoteStreams) { 1274 stream = mRemoteStreams.get(token); 1275 } 1276 Slog.d(TAG, 1277 "onRemoteUpdate: stream: " + stream + " volume: " + pi.getCurrentVolume()); 1278 boolean changed = mState.states.indexOfKey(stream) < 0; 1279 final StreamState ss = streamStateW(stream); 1280 ss.dynamic = true; 1281 ss.levelMin = 0; 1282 ss.levelMax = pi.getMaxVolume(); 1283 if (ss.level != pi.getCurrentVolume()) { 1284 ss.level = pi.getCurrentVolume(); 1285 changed = true; 1286 } 1287 if (!Objects.equals(ss.remoteLabel, name)) { 1288 ss.name = -1; 1289 ss.remoteLabel = name; 1290 changed = true; 1291 } 1292 if (changed) { 1293 Log.d(TAG, "onRemoteUpdate: " + name + ": " + ss.level + " of " + ss.levelMax); 1294 mCallbacks.onStateChanged(mState); 1295 } 1296 } 1297 } 1298 1299 @Override 1300 public void onRemoteVolumeChanged(Token token, int flags) { 1301 if (showForSession(token)) { 1302 addStream(token, "onRemoteVolumeChanged"); 1303 int stream = 0; 1304 synchronized (mRemoteStreams) { 1305 stream = mRemoteStreams.get(token); 1306 } 1307 final boolean showUI = shouldShowUI(flags); 1308 Slog.d(TAG, "onRemoteVolumeChanged: stream: " + stream + " showui? " + showUI); 1309 boolean changed = updateActiveStreamW(stream); 1310 if (showUI) { 1311 changed |= checkRoutedToBluetoothW(AudioManager.STREAM_MUSIC); 1312 } 1313 if (changed) { 1314 Slog.d(TAG, "onRemoteChanged: updatingState"); 1315 mCallbacks.onStateChanged(mState); 1316 } 1317 if (showUI) { 1318 onShowRequestedW(Events.SHOW_REASON_REMOTE_VOLUME_CHANGED); 1319 } 1320 } 1321 } 1322 1323 @Override 1324 public void onRemoteRemoved(Token token) { 1325 if (showForSession(token)) { 1326 int stream = 0; 1327 synchronized (mRemoteStreams) { 1328 if (!mRemoteStreams.containsKey(token)) { 1329 Log.d(TAG, "onRemoteRemoved: stream doesn't exist, " 1330 + "aborting remote removed for token:" + token.toString()); 1331 return; 1332 } 1333 stream = mRemoteStreams.get(token); 1334 } 1335 mState.states.remove(stream); 1336 if (mState.activeStream == stream) { 1337 updateActiveStreamW(-1); 1338 } 1339 mCallbacks.onStateChanged(mState); 1340 } 1341 } 1342 1343 public void setStreamVolume(int stream, int level) { 1344 final Token token = findToken(stream); 1345 if (token == null) { 1346 Log.w(TAG, "setStreamVolume: No token found for stream: " + stream); 1347 return; 1348 } 1349 if (showForSession(token)) { 1350 mMediaSessions.setVolume(token, level); 1351 } 1352 } 1353 1354 private boolean showForSession(Token token) { 1355 if (mVolumeAdjustmentForRemoteGroupSessions) { 1356 if (DEBUG) { 1357 Log.d(TAG, "Volume adjustment for remote group sessions allowed," 1358 + " showForSession: true"); 1359 } 1360 return true; 1361 } 1362 MediaController ctr = new MediaController(mContext, token); 1363 String packageName = ctr.getPackageName(); 1364 List<RoutingSessionInfo> sessions = 1365 mRouter2Manager.getRoutingSessions(packageName); 1366 if (DEBUG) { 1367 Log.d(TAG, "Found " + sessions.size() + " routing sessions for package name " 1368 + packageName); 1369 } 1370 for (RoutingSessionInfo session : sessions) { 1371 if (DEBUG) { 1372 Log.d(TAG, "Found routingSessionInfo: " + session); 1373 } 1374 if (!session.isSystemSession() 1375 && session.getVolumeHandling() != MediaRoute2Info.PLAYBACK_VOLUME_FIXED) { 1376 return true; 1377 } 1378 } 1379 1380 Log.d(TAG, "No routing session for " + packageName); 1381 return false; 1382 } 1383 1384 private Token findToken(int stream) { 1385 synchronized (mRemoteStreams) { 1386 for (Map.Entry<Token, Integer> entry : mRemoteStreams.entrySet()) { 1387 if (entry.getValue().equals(stream)) { 1388 return entry.getKey(); 1389 } 1390 } 1391 } 1392 return null; 1393 } 1394 1395 private void addStream(Token token, String triggeringMethod) { 1396 synchronized (mRemoteStreams) { 1397 if (!mRemoteStreams.containsKey(token)) { 1398 mRemoteStreams.put(token, mNextStream); 1399 Log.d(TAG, triggeringMethod + ": added stream " + mNextStream 1400 + " from token + " + token.toString()); 1401 mNextStream++; 1402 } 1403 } 1404 } 1405 } 1406 1407 public interface UserActivityListener { 1408 void onUserActivity(); 1409 } 1410 } 1411