blob: 4464f75bf9ec67f669c5b55ceca129e8d9af7bdc [file] [log] [blame]
John Spurlockf88d8082015-03-25 18:09:51 -04001/*
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
17package com.android.systemui.volume;
18
19import android.app.NotificationManager;
20import android.content.BroadcastReceiver;
21import android.content.ComponentName;
22import android.content.Context;
23import android.content.Intent;
24import android.content.IntentFilter;
25import android.content.pm.ApplicationInfo;
26import android.content.pm.PackageManager;
27import android.content.pm.PackageManager.NameNotFoundException;
28import android.database.ContentObserver;
29import android.media.AudioManager;
30import android.media.AudioSystem;
31import android.media.IVolumeController;
32import android.media.VolumePolicy;
33import android.media.session.MediaController.PlaybackInfo;
34import android.media.session.MediaSession.Token;
35import android.net.Uri;
36import android.os.Handler;
37import android.os.HandlerThread;
38import android.os.Looper;
39import android.os.Message;
40import android.os.RemoteException;
41import android.os.Vibrator;
42import android.provider.Settings;
43import android.service.notification.Condition;
Julia Reynolds03c548f2016-12-14 15:02:38 -050044import android.util.ArrayMap;
John Spurlockf88d8082015-03-25 18:09:51 -040045import android.util.Log;
Jason Monkae305972017-06-27 14:46:03 -040046import android.view.accessibility.AccessibilityManager;
John Spurlockf88d8082015-03-25 18:09:51 -040047
Yao Chen634acb92016-04-13 16:17:47 -070048import com.android.internal.annotations.GuardedBy;
Jason Monk782cd672017-03-22 12:50:57 -040049import com.android.systemui.Dumpable;
John Spurlockf88d8082015-03-25 18:09:51 -040050import com.android.systemui.R;
Beverly8ebef842017-07-12 10:58:22 -040051import com.android.systemui.SysUiServiceProvider;
Beverly85e05eb2017-07-21 14:49:27 -040052import com.android.systemui.keyguard.WakefulnessLifecycle;
Jason Monk782cd672017-03-22 12:50:57 -040053import com.android.systemui.plugins.VolumeDialogController;
John Spurlockcd863ad2015-04-07 14:01:28 -040054import com.android.systemui.qs.tiles.DndTile;
Beverly8ebef842017-07-12 10:58:22 -040055import com.android.systemui.statusbar.phone.StatusBar;
John Spurlockf88d8082015-03-25 18:09:51 -040056
57import java.io.FileDescriptor;
58import java.io.PrintWriter;
59import java.util.HashMap;
60import java.util.Map;
61import java.util.Objects;
62
63/**
64 * Source of truth for all state / events related to the volume dialog. No presentation.
65 *
66 * All work done on a dedicated background worker thread & associated worker.
67 *
68 * Methods ending in "W" must be called on the worker thread.
69 */
Jason Monk782cd672017-03-22 12:50:57 -040070public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpable {
71 private static final String TAG = Util.logTag(VolumeDialogControllerImpl.class);
John Spurlockf88d8082015-03-25 18:09:51 -040072
73 private static final int DYNAMIC_STREAM_START_INDEX = 100;
74 private static final int VIBRATE_HINT_DURATION = 50;
75
Julia Reynolds03c548f2016-12-14 15:02:38 -050076 private static final ArrayMap<Integer, Integer> STREAMS = new ArrayMap<>();
77 static {
78 STREAMS.put(AudioSystem.STREAM_ALARM, R.string.stream_alarm);
79 STREAMS.put(AudioSystem.STREAM_BLUETOOTH_SCO, R.string.stream_bluetooth_sco);
80 STREAMS.put(AudioSystem.STREAM_DTMF, R.string.stream_dtmf);
81 STREAMS.put(AudioSystem.STREAM_MUSIC, R.string.stream_music);
Julia Reynoldsdbfb40f2017-01-23 11:05:57 -050082 STREAMS.put(AudioSystem.STREAM_ACCESSIBILITY, R.string.stream_accessibility);
Julia Reynolds03c548f2016-12-14 15:02:38 -050083 STREAMS.put(AudioSystem.STREAM_NOTIFICATION, R.string.stream_notification);
84 STREAMS.put(AudioSystem.STREAM_RING, R.string.stream_ring);
85 STREAMS.put(AudioSystem.STREAM_SYSTEM, R.string.stream_system);
86 STREAMS.put(AudioSystem.STREAM_SYSTEM_ENFORCED, R.string.stream_system_enforced);
87 STREAMS.put(AudioSystem.STREAM_TTS, R.string.stream_tts);
88 STREAMS.put(AudioSystem.STREAM_VOICE_CALL, R.string.stream_voice_call);
Julia Reynolds03c548f2016-12-14 15:02:38 -050089 }
John Spurlockf88d8082015-03-25 18:09:51 -040090
91 private final HandlerThread mWorkerThread;
92 private final W mWorker;
93 private final Context mContext;
Yao Chen634acb92016-04-13 16:17:47 -070094 private AudioManager mAudio;
Beverly8ebef842017-07-12 10:58:22 -040095 protected StatusBar mStatusBar;
John Spurlockf88d8082015-03-25 18:09:51 -040096 private final NotificationManager mNoMan;
John Spurlockf88d8082015-03-25 18:09:51 -040097 private final SettingObserver mObserver;
98 private final Receiver mReceiver = new Receiver();
99 private final MediaSessions mMediaSessions;
Beverly8ebef842017-07-12 10:58:22 -0400100 protected C mCallbacks = new C();
John Spurlockf88d8082015-03-25 18:09:51 -0400101 private final State mState = new State();
Beverly4e936612017-07-28 14:05:30 -0400102 protected final MediaSessionsCallbacks mMediaSessionsCallbacksW = new MediaSessionsCallbacks();
John Spurlockf88d8082015-03-25 18:09:51 -0400103 private final Vibrator mVibrator;
104 private final boolean mHasVibrator;
Julia Reynoldsdbfb40f2017-01-23 11:05:57 -0500105 private boolean mShowA11yStream;
Luke Songe0036662017-12-12 12:27:08 -0800106 private boolean mShowVolumeDialog;
107 private boolean mShowSafetyWarning;
John Spurlockf88d8082015-03-25 18:09:51 -0400108
John Spurlockf88d8082015-03-25 18:09:51 -0400109 private boolean mDestroyed;
John Spurlockb02c7442015-04-14 09:32:25 -0400110 private VolumePolicy mVolumePolicy;
John Spurlockd9c75db2015-04-28 11:19:13 -0400111 private boolean mShowDndTile = true;
Yao Chen634acb92016-04-13 16:17:47 -0700112 @GuardedBy("this")
113 private UserActivityListener mUserActivityListener;
114
115 protected final VC mVolumeController = new VC();
John Spurlockf88d8082015-03-25 18:09:51 -0400116
Jason Monk782cd672017-03-22 12:50:57 -0400117 public VolumeDialogControllerImpl(Context context) {
John Spurlockf88d8082015-03-25 18:09:51 -0400118 mContext = context.getApplicationContext();
Chris Wrene565ee62015-06-17 15:24:56 -0400119 Events.writeEvent(mContext, Events.EVENT_COLLECTION_STARTED);
Jason Monk782cd672017-03-22 12:50:57 -0400120 mWorkerThread = new HandlerThread(VolumeDialogControllerImpl.class.getSimpleName());
John Spurlockf88d8082015-03-25 18:09:51 -0400121 mWorkerThread.start();
122 mWorker = new W(mWorkerThread.getLooper());
123 mMediaSessions = createMediaSessions(mContext, mWorkerThread.getLooper(),
124 mMediaSessionsCallbacksW);
125 mAudio = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
126 mNoMan = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
127 mObserver = new SettingObserver(mWorker);
128 mObserver.init();
129 mReceiver.init();
John Spurlockf88d8082015-03-25 18:09:51 -0400130 mVibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
131 mHasVibrator = mVibrator != null && mVibrator.hasVibrator();
Beverly8ebef842017-07-12 10:58:22 -0400132 updateStatusBar();
Jason Monkae305972017-06-27 14:46:03 -0400133
134 boolean accessibilityVolumeStreamActive = context.getSystemService(
135 AccessibilityManager.class).isAccessibilityVolumeStreamActive();
136 mVolumeController.setA11yMode(accessibilityVolumeStreamActive ?
137 VolumePolicy.A11Y_MODE_INDEPENDENT_A11Y_VOLUME :
138 VolumePolicy.A11Y_MODE_MEDIA_A11Y_VOLUME);
John Spurlockf88d8082015-03-25 18:09:51 -0400139 }
140
John Spurlock76b52b32015-04-03 00:00:12 -0400141 public AudioManager getAudioManager() {
142 return mAudio;
143 }
144
John Spurlockf88d8082015-03-25 18:09:51 -0400145 public void dismiss() {
146 mCallbacks.onDismissRequested(Events.DISMISS_REASON_VOLUME_CONTROLLER);
147 }
148
Yao Chen634acb92016-04-13 16:17:47 -0700149 protected void setVolumeController() {
John Spurlockf88d8082015-03-25 18:09:51 -0400150 try {
151 mAudio.setVolumeController(mVolumeController);
152 } catch (SecurityException e) {
153 Log.w(TAG, "Unable to set the volume controller", e);
154 return;
155 }
Yao Chen634acb92016-04-13 16:17:47 -0700156 }
157
158 protected void setAudioManagerStreamVolume(int stream, int level, int flag) {
159 mAudio.setStreamVolume(stream, level, flag);
160 }
161
162 protected int getAudioManagerStreamVolume(int stream) {
163 return mAudio.getLastAudibleStreamVolume(stream);
164 }
165
166 protected int getAudioManagerStreamMaxVolume(int stream) {
167 return mAudio.getStreamMaxVolume(stream);
168 }
169
170 protected int getAudioManagerStreamMinVolume(int stream) {
Jean-Michel Trivi8e7aca32017-11-28 18:12:38 -0800171 return mAudio.getStreamMinVolumeInt(stream);
Yao Chen634acb92016-04-13 16:17:47 -0700172 }
173
174 public void register() {
175 setVolumeController();
John Spurlockf88d8082015-03-25 18:09:51 -0400176 setVolumePolicy(mVolumePolicy);
177 showDndTile(mShowDndTile);
178 try {
179 mMediaSessions.init();
180 } catch (SecurityException e) {
181 Log.w(TAG, "No access to media sessions", e);
182 }
183 }
184
185 public void setVolumePolicy(VolumePolicy policy) {
186 mVolumePolicy = policy;
John Spurlockb02c7442015-04-14 09:32:25 -0400187 if (mVolumePolicy == null) return;
John Spurlockf88d8082015-03-25 18:09:51 -0400188 try {
189 mAudio.setVolumePolicy(mVolumePolicy);
190 } catch (NoSuchMethodError e) {
191 Log.w(TAG, "No volume policy api");
192 }
193 }
194
195 protected MediaSessions createMediaSessions(Context context, Looper looper,
196 MediaSessions.Callbacks callbacks) {
197 return new MediaSessions(context, looper, callbacks);
198 }
199
200 public void destroy() {
201 if (D.BUG) Log.d(TAG, "destroy");
202 if (mDestroyed) return;
203 mDestroyed = true;
Chris Wrene565ee62015-06-17 15:24:56 -0400204 Events.writeEvent(mContext, Events.EVENT_COLLECTION_STOPPED);
John Spurlockf88d8082015-03-25 18:09:51 -0400205 mMediaSessions.destroy();
206 mObserver.destroy();
207 mReceiver.destroy();
208 mWorkerThread.quitSafely();
209 }
210
211 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jason Monk782cd672017-03-22 12:50:57 -0400212 pw.println(VolumeDialogControllerImpl.class.getSimpleName() + " state:");
John Spurlockf88d8082015-03-25 18:09:51 -0400213 pw.print(" mDestroyed: "); pw.println(mDestroyed);
214 pw.print(" mVolumePolicy: "); pw.println(mVolumePolicy);
John Spurlocke56efa712015-05-19 12:26:25 -0400215 pw.print(" mState: "); pw.println(mState.toString(4));
John Spurlockf88d8082015-03-25 18:09:51 -0400216 pw.print(" mShowDndTile: "); pw.println(mShowDndTile);
217 pw.print(" mHasVibrator: "); pw.println(mHasVibrator);
218 pw.print(" mRemoteStreams: "); pw.println(mMediaSessionsCallbacksW.mRemoteStreams
219 .values());
Julia Reynoldsdbfb40f2017-01-23 11:05:57 -0500220 pw.print(" mShowA11yStream: "); pw.println(mShowA11yStream);
John Spurlockf88d8082015-03-25 18:09:51 -0400221 pw.println();
222 mMediaSessions.dump(pw);
223 }
224
225 public void addCallback(Callbacks callback, Handler handler) {
226 mCallbacks.add(callback, handler);
Jason Monkae305972017-06-27 14:46:03 -0400227 callback.onAccessibilityModeChanged(mShowA11yStream);
John Spurlockf88d8082015-03-25 18:09:51 -0400228 }
229
Yao Chen634acb92016-04-13 16:17:47 -0700230 public void setUserActivityListener(UserActivityListener listener) {
231 if (mDestroyed) return;
232 synchronized (this) {
233 mUserActivityListener = listener;
234 }
235 }
236
John Spurlockf88d8082015-03-25 18:09:51 -0400237 public void removeCallback(Callbacks callback) {
238 mCallbacks.remove(callback);
239 }
240
241 public void getState() {
242 if (mDestroyed) return;
243 mWorker.sendEmptyMessage(W.GET_STATE);
244 }
245
246 public void notifyVisible(boolean visible) {
247 if (mDestroyed) return;
248 mWorker.obtainMessage(W.NOTIFY_VISIBLE, visible ? 1 : 0, 0).sendToTarget();
249 }
250
251 public void userActivity() {
252 if (mDestroyed) return;
253 mWorker.removeMessages(W.USER_ACTIVITY);
254 mWorker.sendEmptyMessage(W.USER_ACTIVITY);
255 }
256
257 public void setRingerMode(int value, boolean external) {
258 if (mDestroyed) return;
259 mWorker.obtainMessage(W.SET_RINGER_MODE, value, external ? 1 : 0).sendToTarget();
260 }
261
262 public void setZenMode(int value) {
263 if (mDestroyed) return;
264 mWorker.obtainMessage(W.SET_ZEN_MODE, value, 0).sendToTarget();
265 }
266
267 public void setExitCondition(Condition condition) {
268 if (mDestroyed) return;
269 mWorker.obtainMessage(W.SET_EXIT_CONDITION, condition).sendToTarget();
270 }
271
272 public void setStreamMute(int stream, boolean mute) {
273 if (mDestroyed) return;
274 mWorker.obtainMessage(W.SET_STREAM_MUTE, stream, mute ? 1 : 0).sendToTarget();
275 }
276
277 public void setStreamVolume(int stream, int level) {
278 if (mDestroyed) return;
279 mWorker.obtainMessage(W.SET_STREAM_VOLUME, stream, level).sendToTarget();
280 }
281
282 public void setActiveStream(int stream) {
283 if (mDestroyed) return;
284 mWorker.obtainMessage(W.SET_ACTIVE_STREAM, stream, 0).sendToTarget();
285 }
286
Luke Songe0036662017-12-12 12:27:08 -0800287 public void setEnableDialogs(boolean volumeUi, boolean safetyWarning) {
288 mShowVolumeDialog = volumeUi;
289 mShowSafetyWarning = safetyWarning;
290 }
291
John Spurlockf88d8082015-03-25 18:09:51 -0400292 public void vibrate() {
293 if (mHasVibrator) {
294 mVibrator.vibrate(VIBRATE_HINT_DURATION);
295 }
296 }
297
298 public boolean hasVibrator() {
299 return mHasVibrator;
300 }
301
302 private void onNotifyVisibleW(boolean visible) {
303 if (mDestroyed) return;
304 mAudio.notifyVolumeControllerVisible(mVolumeController, visible);
305 if (!visible) {
306 if (updateActiveStreamW(-1)) {
307 mCallbacks.onStateChanged(mState);
308 }
309 }
310 }
311
Yao Chen634acb92016-04-13 16:17:47 -0700312 private void onUserActivityW() {
313 synchronized (this) {
314 if (mUserActivityListener != null) {
315 mUserActivityListener.onUserActivity();
316 }
317 }
John Spurlockf88d8082015-03-25 18:09:51 -0400318 }
319
John Spurlock76b52b32015-04-03 00:00:12 -0400320 private void onShowSafetyWarningW(int flags) {
Luke Songe0036662017-12-12 12:27:08 -0800321 if (mShowSafetyWarning) {
322 mCallbacks.onShowSafetyWarning(flags);
323 }
John Spurlock76b52b32015-04-03 00:00:12 -0400324 }
325
Julia Reynoldsdbfb40f2017-01-23 11:05:57 -0500326 private void onAccessibilityModeChanged(Boolean showA11yStream) {
327 mCallbacks.onAccessibilityModeChanged(showA11yStream);
328 }
329
John Spurlockf88d8082015-03-25 18:09:51 -0400330 private boolean checkRoutedToBluetoothW(int stream) {
331 boolean changed = false;
332 if (stream == AudioManager.STREAM_MUSIC) {
333 final boolean routedToBluetooth =
334 (mAudio.getDevicesForStream(AudioManager.STREAM_MUSIC) &
335 (AudioManager.DEVICE_OUT_BLUETOOTH_A2DP |
336 AudioManager.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
337 AudioManager.DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER)) != 0;
338 changed |= updateStreamRoutedToBluetoothW(stream, routedToBluetooth);
339 }
340 return changed;
341 }
342
Beverly8ebef842017-07-12 10:58:22 -0400343 private void updateStatusBar() {
344 if (mStatusBar == null) {
345 mStatusBar = SysUiServiceProvider.getComponent(mContext, StatusBar.class);
346 }
347 }
348
Beverly85e05eb2017-07-21 14:49:27 -0400349 private boolean shouldShowUI(int flags) {
Beverly8ebef842017-07-12 10:58:22 -0400350 updateStatusBar();
Beverly85e05eb2017-07-21 14:49:27 -0400351 return mStatusBar != null
352 && mStatusBar.getWakefulnessState() != WakefulnessLifecycle.WAKEFULNESS_ASLEEP
353 && mStatusBar.getWakefulnessState() != WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP
354 && mStatusBar.isDeviceInteractive()
Luke Songe0036662017-12-12 12:27:08 -0800355 && (flags & AudioManager.FLAG_SHOW_UI) != 0
356 && mShowVolumeDialog;
Beverly85e05eb2017-07-21 14:49:27 -0400357 }
Beverly8ebef842017-07-12 10:58:22 -0400358
Beverly85e05eb2017-07-21 14:49:27 -0400359 boolean onVolumeChangedW(int stream, int flags) {
360 final boolean showUI = shouldShowUI(flags);
John Spurlockf88d8082015-03-25 18:09:51 -0400361 final boolean fromKey = (flags & AudioManager.FLAG_FROM_KEY) != 0;
362 final boolean showVibrateHint = (flags & AudioManager.FLAG_SHOW_VIBRATE_HINT) != 0;
363 final boolean showSilentHint = (flags & AudioManager.FLAG_SHOW_SILENT_HINT) != 0;
364 boolean changed = false;
365 if (showUI) {
366 changed |= updateActiveStreamW(stream);
367 }
Yao Chen634acb92016-04-13 16:17:47 -0700368 int lastAudibleStreamVolume = getAudioManagerStreamVolume(stream);
Chris Wrene565ee62015-06-17 15:24:56 -0400369 changed |= updateStreamLevelW(stream, lastAudibleStreamVolume);
John Spurlockf88d8082015-03-25 18:09:51 -0400370 changed |= checkRoutedToBluetoothW(showUI ? AudioManager.STREAM_MUSIC : stream);
371 if (changed) {
372 mCallbacks.onStateChanged(mState);
373 }
374 if (showUI) {
375 mCallbacks.onShowRequested(Events.SHOW_REASON_VOLUME_CHANGED);
376 }
377 if (showVibrateHint) {
378 mCallbacks.onShowVibrateHint();
379 }
380 if (showSilentHint) {
381 mCallbacks.onShowSilentHint();
382 }
383 if (changed && fromKey) {
Chris Wrene565ee62015-06-17 15:24:56 -0400384 Events.writeEvent(mContext, Events.EVENT_KEY, stream, lastAudibleStreamVolume);
John Spurlockf88d8082015-03-25 18:09:51 -0400385 }
Julia Reynolds8ae994f2015-09-14 11:12:42 -0400386 return changed;
John Spurlockf88d8082015-03-25 18:09:51 -0400387 }
388
389 private boolean updateActiveStreamW(int activeStream) {
390 if (activeStream == mState.activeStream) return false;
391 mState.activeStream = activeStream;
Chris Wrene565ee62015-06-17 15:24:56 -0400392 Events.writeEvent(mContext, Events.EVENT_ACTIVE_STREAM_CHANGED, activeStream);
John Spurlockf88d8082015-03-25 18:09:51 -0400393 if (D.BUG) Log.d(TAG, "updateActiveStreamW " + activeStream);
394 final int s = activeStream < DYNAMIC_STREAM_START_INDEX ? activeStream : -1;
395 if (D.BUG) Log.d(TAG, "forceVolumeControlStream " + s);
396 mAudio.forceVolumeControlStream(s);
397 return true;
398 }
399
400 private StreamState streamStateW(int stream) {
401 StreamState ss = mState.states.get(stream);
402 if (ss == null) {
403 ss = new StreamState();
404 mState.states.put(stream, ss);
405 }
406 return ss;
407 }
408
409 private void onGetStateW() {
Julia Reynolds03c548f2016-12-14 15:02:38 -0500410 for (int stream : STREAMS.keySet()) {
Yao Chen634acb92016-04-13 16:17:47 -0700411 updateStreamLevelW(stream, getAudioManagerStreamVolume(stream));
412 streamStateW(stream).levelMin = getAudioManagerStreamMinVolume(stream);
413 streamStateW(stream).levelMax = getAudioManagerStreamMaxVolume(stream);
John Spurlockf88d8082015-03-25 18:09:51 -0400414 updateStreamMuteW(stream, mAudio.isStreamMute(stream));
415 final StreamState ss = streamStateW(stream);
416 ss.muteSupported = mAudio.isStreamAffectedByMute(stream);
Julia Reynolds03c548f2016-12-14 15:02:38 -0500417 ss.name = STREAMS.get(stream);
John Spurlockf88d8082015-03-25 18:09:51 -0400418 checkRoutedToBluetoothW(stream);
419 }
420 updateRingerModeExternalW(mAudio.getRingerMode());
421 updateZenModeW();
422 updateEffectsSuppressorW(mNoMan.getEffectsSuppressor());
John Spurlockf88d8082015-03-25 18:09:51 -0400423 mCallbacks.onStateChanged(mState);
424 }
425
426 private boolean updateStreamRoutedToBluetoothW(int stream, boolean routedToBluetooth) {
427 final StreamState ss = streamStateW(stream);
428 if (ss.routedToBluetooth == routedToBluetooth) return false;
429 ss.routedToBluetooth = routedToBluetooth;
430 if (D.BUG) Log.d(TAG, "updateStreamRoutedToBluetoothW stream=" + stream
431 + " routedToBluetooth=" + routedToBluetooth);
432 return true;
433 }
434
435 private boolean updateStreamLevelW(int stream, int level) {
436 final StreamState ss = streamStateW(stream);
437 if (ss.level == level) return false;
438 ss.level = level;
439 if (isLogWorthy(stream)) {
Chris Wrene565ee62015-06-17 15:24:56 -0400440 Events.writeEvent(mContext, Events.EVENT_LEVEL_CHANGED, stream, level);
John Spurlockf88d8082015-03-25 18:09:51 -0400441 }
442 return true;
443 }
444
445 private static boolean isLogWorthy(int stream) {
446 switch (stream) {
447 case AudioSystem.STREAM_ALARM:
448 case AudioSystem.STREAM_BLUETOOTH_SCO:
449 case AudioSystem.STREAM_MUSIC:
450 case AudioSystem.STREAM_RING:
451 case AudioSystem.STREAM_SYSTEM:
452 case AudioSystem.STREAM_VOICE_CALL:
453 return true;
454 }
455 return false;
456 }
457
458 private boolean updateStreamMuteW(int stream, boolean muted) {
459 final StreamState ss = streamStateW(stream);
460 if (ss.muted == muted) return false;
461 ss.muted = muted;
462 if (isLogWorthy(stream)) {
Chris Wrene565ee62015-06-17 15:24:56 -0400463 Events.writeEvent(mContext, Events.EVENT_MUTE_CHANGED, stream, muted);
John Spurlockf88d8082015-03-25 18:09:51 -0400464 }
465 if (muted && isRinger(stream)) {
466 updateRingerModeInternalW(mAudio.getRingerModeInternal());
467 }
468 return true;
469 }
470
471 private static boolean isRinger(int stream) {
472 return stream == AudioManager.STREAM_RING || stream == AudioManager.STREAM_NOTIFICATION;
473 }
474
John Spurlockf88d8082015-03-25 18:09:51 -0400475 private boolean updateEffectsSuppressorW(ComponentName effectsSuppressor) {
476 if (Objects.equals(mState.effectsSuppressor, effectsSuppressor)) return false;
477 mState.effectsSuppressor = effectsSuppressor;
478 mState.effectsSuppressorName = getApplicationName(mContext, mState.effectsSuppressor);
Chris Wrene565ee62015-06-17 15:24:56 -0400479 Events.writeEvent(mContext, Events.EVENT_SUPPRESSOR_CHANGED, mState.effectsSuppressor,
John Spurlockf88d8082015-03-25 18:09:51 -0400480 mState.effectsSuppressorName);
481 return true;
482 }
483
484 private static String getApplicationName(Context context, ComponentName component) {
485 if (component == null) return null;
486 final PackageManager pm = context.getPackageManager();
487 final String pkg = component.getPackageName();
488 try {
489 final ApplicationInfo ai = pm.getApplicationInfo(pkg, 0);
490 final String rt = Objects.toString(ai.loadLabel(pm), "").trim();
491 if (rt.length() > 0) {
492 return rt;
493 }
494 } catch (NameNotFoundException e) {}
495 return pkg;
496 }
497
498 private boolean updateZenModeW() {
499 final int zen = Settings.Global.getInt(mContext.getContentResolver(),
500 Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
501 if (mState.zenMode == zen) return false;
502 mState.zenMode = zen;
Chris Wrene565ee62015-06-17 15:24:56 -0400503 Events.writeEvent(mContext, Events.EVENT_ZEN_MODE_CHANGED, zen);
John Spurlockf88d8082015-03-25 18:09:51 -0400504 return true;
505 }
506
507 private boolean updateRingerModeExternalW(int rm) {
508 if (rm == mState.ringerModeExternal) return false;
509 mState.ringerModeExternal = rm;
Chris Wrene565ee62015-06-17 15:24:56 -0400510 Events.writeEvent(mContext, Events.EVENT_EXTERNAL_RINGER_MODE_CHANGED, rm);
John Spurlockf88d8082015-03-25 18:09:51 -0400511 return true;
512 }
513
514 private boolean updateRingerModeInternalW(int rm) {
515 if (rm == mState.ringerModeInternal) return false;
516 mState.ringerModeInternal = rm;
Chris Wrene565ee62015-06-17 15:24:56 -0400517 Events.writeEvent(mContext, Events.EVENT_INTERNAL_RINGER_MODE_CHANGED, rm);
John Spurlockf88d8082015-03-25 18:09:51 -0400518 return true;
519 }
520
521 private void onSetRingerModeW(int mode, boolean external) {
522 if (external) {
523 mAudio.setRingerMode(mode);
524 } else {
525 mAudio.setRingerModeInternal(mode);
526 }
527 }
528
529 private void onSetStreamMuteW(int stream, boolean mute) {
530 mAudio.adjustStreamVolume(stream, mute ? AudioManager.ADJUST_MUTE
531 : AudioManager.ADJUST_UNMUTE, 0);
532 }
533
534 private void onSetStreamVolumeW(int stream, int level) {
535 if (D.BUG) Log.d(TAG, "onSetStreamVolume " + stream + " level=" + level);
536 if (stream >= DYNAMIC_STREAM_START_INDEX) {
537 mMediaSessionsCallbacksW.setStreamVolume(stream, level);
538 return;
539 }
Yao Chen634acb92016-04-13 16:17:47 -0700540 setAudioManagerStreamVolume(stream, level, 0);
John Spurlockf88d8082015-03-25 18:09:51 -0400541 }
542
543 private void onSetActiveStreamW(int stream) {
544 boolean changed = updateActiveStreamW(stream);
545 if (changed) {
546 mCallbacks.onStateChanged(mState);
547 }
548 }
549
550 private void onSetExitConditionW(Condition condition) {
John Spurlockb2278d62015-04-07 12:47:12 -0400551 mNoMan.setZenMode(mState.zenMode, condition != null ? condition.id : null, TAG);
John Spurlockf88d8082015-03-25 18:09:51 -0400552 }
553
554 private void onSetZenModeW(int mode) {
555 if (D.BUG) Log.d(TAG, "onSetZenModeW " + mode);
John Spurlockb2278d62015-04-07 12:47:12 -0400556 mNoMan.setZenMode(mode, null, TAG);
John Spurlockf88d8082015-03-25 18:09:51 -0400557 }
558
559 private void onDismissRequestedW(int reason) {
560 mCallbacks.onDismissRequested(reason);
561 }
562
563 public void showDndTile(boolean visible) {
564 if (D.BUG) Log.d(TAG, "showDndTile");
John Spurlockcd863ad2015-04-07 14:01:28 -0400565 DndTile.setVisible(mContext, visible);
John Spurlockf88d8082015-03-25 18:09:51 -0400566 }
567
568 private final class VC extends IVolumeController.Stub {
Jason Monk782cd672017-03-22 12:50:57 -0400569 private final String TAG = VolumeDialogControllerImpl.TAG + ".VC";
John Spurlockf88d8082015-03-25 18:09:51 -0400570
571 @Override
572 public void displaySafeVolumeWarning(int flags) throws RemoteException {
John Spurlock76b52b32015-04-03 00:00:12 -0400573 if (D.BUG) Log.d(TAG, "displaySafeVolumeWarning "
574 + Util.audioManagerFlagsToString(flags));
575 if (mDestroyed) return;
576 mWorker.obtainMessage(W.SHOW_SAFETY_WARNING, flags, 0).sendToTarget();
John Spurlockf88d8082015-03-25 18:09:51 -0400577 }
578
579 @Override
580 public void volumeChanged(int streamType, int flags) throws RemoteException {
581 if (D.BUG) Log.d(TAG, "volumeChanged " + AudioSystem.streamToString(streamType)
582 + " " + Util.audioManagerFlagsToString(flags));
583 if (mDestroyed) return;
584 mWorker.obtainMessage(W.VOLUME_CHANGED, streamType, flags).sendToTarget();
585 }
586
587 @Override
588 public void masterMuteChanged(int flags) throws RemoteException {
589 if (D.BUG) Log.d(TAG, "masterMuteChanged");
590 }
591
592 @Override
593 public void setLayoutDirection(int layoutDirection) throws RemoteException {
594 if (D.BUG) Log.d(TAG, "setLayoutDirection");
595 if (mDestroyed) return;
596 mWorker.obtainMessage(W.LAYOUT_DIRECTION_CHANGED, layoutDirection, 0).sendToTarget();
597 }
598
599 @Override
600 public void dismiss() throws RemoteException {
601 if (D.BUG) Log.d(TAG, "dismiss requested");
602 if (mDestroyed) return;
603 mWorker.obtainMessage(W.DISMISS_REQUESTED, Events.DISMISS_REASON_VOLUME_CONTROLLER, 0)
604 .sendToTarget();
605 mWorker.sendEmptyMessage(W.DISMISS_REQUESTED);
606 }
Jean-Michel Triviac487672016-11-11 10:05:18 -0800607
608 @Override
609 public void setA11yMode(int mode) {
610 if (D.BUG) Log.d(TAG, "setA11yMode to " + mode);
611 if (mDestroyed) return;
612 switch (mode) {
613 case VolumePolicy.A11Y_MODE_MEDIA_A11Y_VOLUME:
614 // "legacy" mode
Julia Reynoldsdbfb40f2017-01-23 11:05:57 -0500615 mShowA11yStream = false;
Jean-Michel Triviac487672016-11-11 10:05:18 -0800616 break;
617 case VolumePolicy.A11Y_MODE_INDEPENDENT_A11Y_VOLUME:
Julia Reynoldsdbfb40f2017-01-23 11:05:57 -0500618 mShowA11yStream = true;
Jean-Michel Triviac487672016-11-11 10:05:18 -0800619 break;
620 default:
621 Log.e(TAG, "Invalid accessibility mode " + mode);
622 break;
623 }
Julia Reynoldsdbfb40f2017-01-23 11:05:57 -0500624 mWorker.obtainMessage(W.ACCESSIBILITY_MODE_CHANGED, mShowA11yStream).sendToTarget();
Jean-Michel Triviac487672016-11-11 10:05:18 -0800625 }
John Spurlockf88d8082015-03-25 18:09:51 -0400626 }
627
628 private final class W extends Handler {
629 private static final int VOLUME_CHANGED = 1;
630 private static final int DISMISS_REQUESTED = 2;
631 private static final int GET_STATE = 3;
632 private static final int SET_RINGER_MODE = 4;
633 private static final int SET_ZEN_MODE = 5;
634 private static final int SET_EXIT_CONDITION = 6;
635 private static final int SET_STREAM_MUTE = 7;
636 private static final int LAYOUT_DIRECTION_CHANGED = 8;
637 private static final int CONFIGURATION_CHANGED = 9;
638 private static final int SET_STREAM_VOLUME = 10;
639 private static final int SET_ACTIVE_STREAM = 11;
640 private static final int NOTIFY_VISIBLE = 12;
641 private static final int USER_ACTIVITY = 13;
John Spurlock76b52b32015-04-03 00:00:12 -0400642 private static final int SHOW_SAFETY_WARNING = 14;
Julia Reynoldsdbfb40f2017-01-23 11:05:57 -0500643 private static final int ACCESSIBILITY_MODE_CHANGED = 15;
John Spurlockf88d8082015-03-25 18:09:51 -0400644
645 W(Looper looper) {
646 super(looper);
647 }
648
649 @Override
650 public void handleMessage(Message msg) {
651 switch (msg.what) {
652 case VOLUME_CHANGED: onVolumeChangedW(msg.arg1, msg.arg2); break;
653 case DISMISS_REQUESTED: onDismissRequestedW(msg.arg1); break;
654 case GET_STATE: onGetStateW(); break;
655 case SET_RINGER_MODE: onSetRingerModeW(msg.arg1, msg.arg2 != 0); break;
656 case SET_ZEN_MODE: onSetZenModeW(msg.arg1); break;
657 case SET_EXIT_CONDITION: onSetExitConditionW((Condition) msg.obj); break;
658 case SET_STREAM_MUTE: onSetStreamMuteW(msg.arg1, msg.arg2 != 0); break;
659 case LAYOUT_DIRECTION_CHANGED: mCallbacks.onLayoutDirectionChanged(msg.arg1); break;
660 case CONFIGURATION_CHANGED: mCallbacks.onConfigurationChanged(); break;
661 case SET_STREAM_VOLUME: onSetStreamVolumeW(msg.arg1, msg.arg2); break;
662 case SET_ACTIVE_STREAM: onSetActiveStreamW(msg.arg1); break;
John Spurlock76b52b32015-04-03 00:00:12 -0400663 case NOTIFY_VISIBLE: onNotifyVisibleW(msg.arg1 != 0); break;
664 case USER_ACTIVITY: onUserActivityW(); break;
665 case SHOW_SAFETY_WARNING: onShowSafetyWarningW(msg.arg1); break;
Julia Reynoldsdbfb40f2017-01-23 11:05:57 -0500666 case ACCESSIBILITY_MODE_CHANGED: onAccessibilityModeChanged((Boolean) msg.obj);
John Spurlockf88d8082015-03-25 18:09:51 -0400667 }
668 }
669 }
670
Beverly8ebef842017-07-12 10:58:22 -0400671 class C implements Callbacks {
John Spurlockf88d8082015-03-25 18:09:51 -0400672 private final HashMap<Callbacks, Handler> mCallbackMap = new HashMap<>();
673
674 public void add(Callbacks callback, Handler handler) {
675 if (callback == null || handler == null) throw new IllegalArgumentException();
676 mCallbackMap.put(callback, handler);
677 }
678
679 public void remove(Callbacks callback) {
680 mCallbackMap.remove(callback);
681 }
682
683 @Override
684 public void onShowRequested(final int reason) {
685 for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
686 entry.getValue().post(new Runnable() {
687 @Override
688 public void run() {
689 entry.getKey().onShowRequested(reason);
690 }
691 });
692 }
693 }
694
695 @Override
696 public void onDismissRequested(final int reason) {
697 for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
698 entry.getValue().post(new Runnable() {
699 @Override
700 public void run() {
701 entry.getKey().onDismissRequested(reason);
702 }
703 });
704 }
705 }
706
707 @Override
708 public void onStateChanged(final State state) {
709 final long time = System.currentTimeMillis();
710 final State copy = state.copy();
711 for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
712 entry.getValue().post(new Runnable() {
713 @Override
714 public void run() {
715 entry.getKey().onStateChanged(copy);
716 }
717 });
718 }
719 Events.writeState(time, copy);
720 }
721
722 @Override
723 public void onLayoutDirectionChanged(final int layoutDirection) {
724 for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
725 entry.getValue().post(new Runnable() {
726 @Override
727 public void run() {
728 entry.getKey().onLayoutDirectionChanged(layoutDirection);
729 }
730 });
731 }
732 }
733
734 @Override
735 public void onConfigurationChanged() {
736 for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
737 entry.getValue().post(new Runnable() {
738 @Override
739 public void run() {
740 entry.getKey().onConfigurationChanged();
741 }
742 });
743 }
744 }
745
746 @Override
747 public void onShowVibrateHint() {
748 for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
749 entry.getValue().post(new Runnable() {
750 @Override
751 public void run() {
752 entry.getKey().onShowVibrateHint();
753 }
754 });
755 }
756 }
757
758 @Override
759 public void onShowSilentHint() {
760 for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
761 entry.getValue().post(new Runnable() {
762 @Override
763 public void run() {
764 entry.getKey().onShowSilentHint();
765 }
766 });
767 }
768 }
769
770 @Override
771 public void onScreenOff() {
772 for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
773 entry.getValue().post(new Runnable() {
774 @Override
775 public void run() {
776 entry.getKey().onScreenOff();
777 }
778 });
779 }
780 }
John Spurlock76b52b32015-04-03 00:00:12 -0400781
782 @Override
783 public void onShowSafetyWarning(final int flags) {
784 for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
785 entry.getValue().post(new Runnable() {
786 @Override
787 public void run() {
788 entry.getKey().onShowSafetyWarning(flags);
789 }
790 });
791 }
792 }
Julia Reynoldsdbfb40f2017-01-23 11:05:57 -0500793
794 @Override
795 public void onAccessibilityModeChanged(Boolean showA11yStream) {
796 boolean show = showA11yStream == null ? false : showA11yStream;
797 for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
798 entry.getValue().post(new Runnable() {
799 @Override
800 public void run() {
801 entry.getKey().onAccessibilityModeChanged(show);
802 }
803 });
804 }
805 }
John Spurlockf88d8082015-03-25 18:09:51 -0400806 }
807
808
809 private final class SettingObserver extends ContentObserver {
John Spurlockf88d8082015-03-25 18:09:51 -0400810 private final Uri ZEN_MODE_URI =
811 Settings.Global.getUriFor(Settings.Global.ZEN_MODE);
812 private final Uri ZEN_MODE_CONFIG_URI =
813 Settings.Global.getUriFor(Settings.Global.ZEN_MODE_CONFIG_ETAG);
814
815 public SettingObserver(Handler handler) {
816 super(handler);
817 }
818
819 public void init() {
John Spurlockf88d8082015-03-25 18:09:51 -0400820 mContext.getContentResolver().registerContentObserver(ZEN_MODE_URI, false, this);
821 mContext.getContentResolver().registerContentObserver(ZEN_MODE_CONFIG_URI, false, this);
John Spurlockf88d8082015-03-25 18:09:51 -0400822 }
823
824 public void destroy() {
825 mContext.getContentResolver().unregisterContentObserver(this);
826 }
827
828 @Override
829 public void onChange(boolean selfChange, Uri uri) {
830 boolean changed = false;
John Spurlockf88d8082015-03-25 18:09:51 -0400831 if (ZEN_MODE_URI.equals(uri)) {
832 changed = updateZenModeW();
833 }
John Spurlockf88d8082015-03-25 18:09:51 -0400834 if (changed) {
835 mCallbacks.onStateChanged(mState);
836 }
837 }
838 }
839
840 private final class Receiver extends BroadcastReceiver {
841
842 public void init() {
843 final IntentFilter filter = new IntentFilter();
844 filter.addAction(AudioManager.VOLUME_CHANGED_ACTION);
845 filter.addAction(AudioManager.STREAM_DEVICES_CHANGED_ACTION);
846 filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
847 filter.addAction(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION);
848 filter.addAction(AudioManager.STREAM_MUTE_CHANGED_ACTION);
849 filter.addAction(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED);
850 filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
851 filter.addAction(Intent.ACTION_SCREEN_OFF);
John Spurlockbc7233a2015-06-29 15:34:18 -0400852 filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
John Spurlockf88d8082015-03-25 18:09:51 -0400853 mContext.registerReceiver(this, filter, null, mWorker);
854 }
855
856 public void destroy() {
857 mContext.unregisterReceiver(this);
858 }
859
860 @Override
861 public void onReceive(Context context, Intent intent) {
862 final String action = intent.getAction();
863 boolean changed = false;
864 if (action.equals(AudioManager.VOLUME_CHANGED_ACTION)) {
865 final int stream = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1);
866 final int level = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, -1);
867 final int oldLevel = intent
868 .getIntExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, -1);
869 if (D.BUG) Log.d(TAG, "onReceive VOLUME_CHANGED_ACTION stream=" + stream
870 + " level=" + level + " oldLevel=" + oldLevel);
871 changed = updateStreamLevelW(stream, level);
872 } else if (action.equals(AudioManager.STREAM_DEVICES_CHANGED_ACTION)) {
873 final int stream = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1);
874 final int devices = intent
875 .getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_DEVICES, -1);
876 final int oldDevices = intent
877 .getIntExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_DEVICES, -1);
878 if (D.BUG) Log.d(TAG, "onReceive STREAM_DEVICES_CHANGED_ACTION stream="
879 + stream + " devices=" + devices + " oldDevices=" + oldDevices);
880 changed = checkRoutedToBluetoothW(stream);
Julia Reynolds8ae994f2015-09-14 11:12:42 -0400881 changed |= onVolumeChangedW(stream, 0);
John Spurlockf88d8082015-03-25 18:09:51 -0400882 } else if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) {
883 final int rm = intent.getIntExtra(AudioManager.EXTRA_RINGER_MODE, -1);
884 if (D.BUG) Log.d(TAG, "onReceive RINGER_MODE_CHANGED_ACTION rm="
885 + Util.ringerModeToString(rm));
886 changed = updateRingerModeExternalW(rm);
887 } else if (action.equals(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION)) {
888 final int rm = intent.getIntExtra(AudioManager.EXTRA_RINGER_MODE, -1);
889 if (D.BUG) Log.d(TAG, "onReceive INTERNAL_RINGER_MODE_CHANGED_ACTION rm="
890 + Util.ringerModeToString(rm));
891 changed = updateRingerModeInternalW(rm);
892 } else if (action.equals(AudioManager.STREAM_MUTE_CHANGED_ACTION)) {
893 final int stream = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1);
894 final boolean muted = intent
895 .getBooleanExtra(AudioManager.EXTRA_STREAM_VOLUME_MUTED, false);
896 if (D.BUG) Log.d(TAG, "onReceive STREAM_MUTE_CHANGED_ACTION stream=" + stream
897 + " muted=" + muted);
898 changed = updateStreamMuteW(stream, muted);
899 } else if (action.equals(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED)) {
900 if (D.BUG) Log.d(TAG, "onReceive ACTION_EFFECTS_SUPPRESSOR_CHANGED");
901 changed = updateEffectsSuppressorW(mNoMan.getEffectsSuppressor());
902 } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
903 if (D.BUG) Log.d(TAG, "onReceive ACTION_CONFIGURATION_CHANGED");
904 mCallbacks.onConfigurationChanged();
905 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
906 if (D.BUG) Log.d(TAG, "onReceive ACTION_SCREEN_OFF");
907 mCallbacks.onScreenOff();
John Spurlockbc7233a2015-06-29 15:34:18 -0400908 } else if (action.equals(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) {
909 if (D.BUG) Log.d(TAG, "onReceive ACTION_CLOSE_SYSTEM_DIALOGS");
910 dismiss();
John Spurlockf88d8082015-03-25 18:09:51 -0400911 }
912 if (changed) {
913 mCallbacks.onStateChanged(mState);
914 }
915 }
916 }
917
Beverly4e936612017-07-28 14:05:30 -0400918 protected final class MediaSessionsCallbacks implements MediaSessions.Callbacks {
John Spurlockf88d8082015-03-25 18:09:51 -0400919 private final HashMap<Token, Integer> mRemoteStreams = new HashMap<>();
920
921 private int mNextStream = DYNAMIC_STREAM_START_INDEX;
922
923 @Override
924 public void onRemoteUpdate(Token token, String name, PlaybackInfo pi) {
Beverlyb5a27812017-07-24 11:34:48 -0400925 addStream(token, "onRemoteUpdate");
John Spurlockf88d8082015-03-25 18:09:51 -0400926 final int stream = mRemoteStreams.get(token);
927 boolean changed = mState.states.indexOfKey(stream) < 0;
928 final StreamState ss = streamStateW(stream);
929 ss.dynamic = true;
930 ss.levelMin = 0;
931 ss.levelMax = pi.getMaxVolume();
932 if (ss.level != pi.getCurrentVolume()) {
933 ss.level = pi.getCurrentVolume();
934 changed = true;
935 }
Julia Reynolds03c548f2016-12-14 15:02:38 -0500936 if (!Objects.equals(ss.remoteLabel, name)) {
937 ss.name = -1;
938 ss.remoteLabel = name;
John Spurlockf88d8082015-03-25 18:09:51 -0400939 changed = true;
940 }
941 if (changed) {
942 if (D.BUG) Log.d(TAG, "onRemoteUpdate: " + name + ": " + ss.level
943 + " of " + ss.levelMax);
944 mCallbacks.onStateChanged(mState);
945 }
946 }
947
948 @Override
949 public void onRemoteVolumeChanged(Token token, int flags) {
Beverlyb5a27812017-07-24 11:34:48 -0400950 addStream(token, "onRemoteVolumeChanged");
John Spurlockf88d8082015-03-25 18:09:51 -0400951 final int stream = mRemoteStreams.get(token);
Beverly85e05eb2017-07-21 14:49:27 -0400952 final boolean showUI = shouldShowUI(flags);
John Spurlockf88d8082015-03-25 18:09:51 -0400953 boolean changed = updateActiveStreamW(stream);
954 if (showUI) {
955 changed |= checkRoutedToBluetoothW(AudioManager.STREAM_MUSIC);
956 }
957 if (changed) {
958 mCallbacks.onStateChanged(mState);
959 }
960 if (showUI) {
961 mCallbacks.onShowRequested(Events.SHOW_REASON_REMOTE_VOLUME_CHANGED);
962 }
963 }
964
965 @Override
966 public void onRemoteRemoved(Token token) {
Beverlyb5a27812017-07-24 11:34:48 -0400967 if (!mRemoteStreams.containsKey(token)) {
968 if (D.BUG) Log.d(TAG, "onRemoteRemoved: stream doesn't exist, "
969 + "aborting remote removed for token:" + token.toString());
970 return;
971 }
John Spurlockf88d8082015-03-25 18:09:51 -0400972 final int stream = mRemoteStreams.get(token);
973 mState.states.remove(stream);
974 if (mState.activeStream == stream) {
975 updateActiveStreamW(-1);
976 }
977 mCallbacks.onStateChanged(mState);
978 }
979
980 public void setStreamVolume(int stream, int level) {
981 final Token t = findToken(stream);
982 if (t == null) {
983 Log.w(TAG, "setStreamVolume: No token found for stream: " + stream);
984 return;
985 }
986 mMediaSessions.setVolume(t, level);
987 }
988
989 private Token findToken(int stream) {
990 for (Map.Entry<Token, Integer> entry : mRemoteStreams.entrySet()) {
991 if (entry.getValue().equals(stream)) {
992 return entry.getKey();
993 }
994 }
995 return null;
996 }
Beverlyb5a27812017-07-24 11:34:48 -0400997
998 private void addStream(Token token, String triggeringMethod) {
999 if (!mRemoteStreams.containsKey(token)) {
1000 mRemoteStreams.put(token, mNextStream);
1001 if (D.BUG) Log.d(TAG, triggeringMethod + ": added stream " + mNextStream
1002 + " from token + "+ token.toString());
1003 mNextStream++;
1004 }
1005 }
John Spurlockf88d8082015-03-25 18:09:51 -04001006 }
1007
Yao Chen634acb92016-04-13 16:17:47 -07001008 public interface UserActivityListener {
1009 void onUserActivity();
1010 }
John Spurlockf88d8082015-03-25 18:09:51 -04001011}