blob: 7c71b2a058f596b4342d3a499551c9dc02d0ebd6 [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;
Julia Reynolds6692b472018-01-24 07:23:56 -050029import android.media.AudioDeviceCallback;
30import android.media.AudioDeviceInfo;
John Spurlockf88d8082015-03-25 18:09:51 -040031import android.media.AudioManager;
32import android.media.AudioSystem;
33import android.media.IVolumeController;
34import android.media.VolumePolicy;
35import android.media.session.MediaController.PlaybackInfo;
36import android.media.session.MediaSession.Token;
37import android.net.Uri;
38import android.os.Handler;
39import android.os.HandlerThread;
40import android.os.Looper;
41import android.os.Message;
42import android.os.RemoteException;
43import android.os.Vibrator;
44import android.provider.Settings;
45import android.service.notification.Condition;
Beverly925cde82018-01-23 09:31:23 -050046import android.service.notification.ZenModeConfig;
Julia Reynolds03c548f2016-12-14 15:02:38 -050047import android.util.ArrayMap;
John Spurlockf88d8082015-03-25 18:09:51 -040048import android.util.Log;
Jason Monkae305972017-06-27 14:46:03 -040049import android.view.accessibility.AccessibilityManager;
John Spurlockf88d8082015-03-25 18:09:51 -040050
Yao Chen634acb92016-04-13 16:17:47 -070051import com.android.internal.annotations.GuardedBy;
Jason Monk782cd672017-03-22 12:50:57 -040052import com.android.systemui.Dumpable;
John Spurlockf88d8082015-03-25 18:09:51 -040053import com.android.systemui.R;
Beverly8ebef842017-07-12 10:58:22 -040054import com.android.systemui.SysUiServiceProvider;
Beverly85e05eb2017-07-21 14:49:27 -040055import com.android.systemui.keyguard.WakefulnessLifecycle;
Jason Monk782cd672017-03-22 12:50:57 -040056import com.android.systemui.plugins.VolumeDialogController;
John Spurlockcd863ad2015-04-07 14:01:28 -040057import com.android.systemui.qs.tiles.DndTile;
Beverly8ebef842017-07-12 10:58:22 -040058import com.android.systemui.statusbar.phone.StatusBar;
John Spurlockf88d8082015-03-25 18:09:51 -040059
60import java.io.FileDescriptor;
61import java.io.PrintWriter;
Julia Reynolds24cc7592018-01-25 15:51:45 -050062import java.util.ArrayList;
John Spurlockf88d8082015-03-25 18:09:51 -040063import java.util.HashMap;
Julia Reynolds24cc7592018-01-25 15:51:45 -050064import java.util.List;
John Spurlockf88d8082015-03-25 18:09:51 -040065import java.util.Map;
66import java.util.Objects;
67
68/**
69 * Source of truth for all state / events related to the volume dialog. No presentation.
70 *
71 * All work done on a dedicated background worker thread & associated worker.
72 *
73 * Methods ending in "W" must be called on the worker thread.
74 */
Jason Monk782cd672017-03-22 12:50:57 -040075public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpable {
76 private static final String TAG = Util.logTag(VolumeDialogControllerImpl.class);
John Spurlockf88d8082015-03-25 18:09:51 -040077
78 private static final int DYNAMIC_STREAM_START_INDEX = 100;
79 private static final int VIBRATE_HINT_DURATION = 50;
80
Julia Reynolds561d3f42018-01-26 11:31:02 -050081 static final ArrayMap<Integer, Integer> STREAMS = new ArrayMap<>();
Julia Reynolds03c548f2016-12-14 15:02:38 -050082 static {
83 STREAMS.put(AudioSystem.STREAM_ALARM, R.string.stream_alarm);
84 STREAMS.put(AudioSystem.STREAM_BLUETOOTH_SCO, R.string.stream_bluetooth_sco);
85 STREAMS.put(AudioSystem.STREAM_DTMF, R.string.stream_dtmf);
86 STREAMS.put(AudioSystem.STREAM_MUSIC, R.string.stream_music);
Julia Reynoldsdbfb40f2017-01-23 11:05:57 -050087 STREAMS.put(AudioSystem.STREAM_ACCESSIBILITY, R.string.stream_accessibility);
Julia Reynolds03c548f2016-12-14 15:02:38 -050088 STREAMS.put(AudioSystem.STREAM_NOTIFICATION, R.string.stream_notification);
89 STREAMS.put(AudioSystem.STREAM_RING, R.string.stream_ring);
90 STREAMS.put(AudioSystem.STREAM_SYSTEM, R.string.stream_system);
91 STREAMS.put(AudioSystem.STREAM_SYSTEM_ENFORCED, R.string.stream_system_enforced);
92 STREAMS.put(AudioSystem.STREAM_TTS, R.string.stream_tts);
93 STREAMS.put(AudioSystem.STREAM_VOICE_CALL, R.string.stream_voice_call);
Julia Reynolds03c548f2016-12-14 15:02:38 -050094 }
John Spurlockf88d8082015-03-25 18:09:51 -040095
96 private final HandlerThread mWorkerThread;
97 private final W mWorker;
98 private final Context mContext;
Yao Chen634acb92016-04-13 16:17:47 -070099 private AudioManager mAudio;
Beverly8ebef842017-07-12 10:58:22 -0400100 protected StatusBar mStatusBar;
John Spurlockf88d8082015-03-25 18:09:51 -0400101 private final NotificationManager mNoMan;
John Spurlockf88d8082015-03-25 18:09:51 -0400102 private final SettingObserver mObserver;
103 private final Receiver mReceiver = new Receiver();
104 private final MediaSessions mMediaSessions;
Beverly8ebef842017-07-12 10:58:22 -0400105 protected C mCallbacks = new C();
John Spurlockf88d8082015-03-25 18:09:51 -0400106 private final State mState = new State();
Beverly4e936612017-07-28 14:05:30 -0400107 protected final MediaSessionsCallbacks mMediaSessionsCallbacksW = new MediaSessionsCallbacks();
John Spurlockf88d8082015-03-25 18:09:51 -0400108 private final Vibrator mVibrator;
109 private final boolean mHasVibrator;
Julia Reynoldsdbfb40f2017-01-23 11:05:57 -0500110 private boolean mShowA11yStream;
Luke Songe0036662017-12-12 12:27:08 -0800111 private boolean mShowVolumeDialog;
112 private boolean mShowSafetyWarning;
Beverly925cde82018-01-23 09:31:23 -0500113 private final NotificationManager mNotificationManager;
John Spurlockf88d8082015-03-25 18:09:51 -0400114
John Spurlockf88d8082015-03-25 18:09:51 -0400115 private boolean mDestroyed;
John Spurlockb02c7442015-04-14 09:32:25 -0400116 private VolumePolicy mVolumePolicy;
John Spurlockd9c75db2015-04-28 11:19:13 -0400117 private boolean mShowDndTile = true;
Yao Chen634acb92016-04-13 16:17:47 -0700118 @GuardedBy("this")
119 private UserActivityListener mUserActivityListener;
120
121 protected final VC mVolumeController = new VC();
John Spurlockf88d8082015-03-25 18:09:51 -0400122
Jason Monk782cd672017-03-22 12:50:57 -0400123 public VolumeDialogControllerImpl(Context context) {
John Spurlockf88d8082015-03-25 18:09:51 -0400124 mContext = context.getApplicationContext();
Beverly925cde82018-01-23 09:31:23 -0500125 mNotificationManager = (NotificationManager) mContext.getSystemService(
126 Context.NOTIFICATION_SERVICE);
Chris Wrene565ee62015-06-17 15:24:56 -0400127 Events.writeEvent(mContext, Events.EVENT_COLLECTION_STARTED);
Jason Monk782cd672017-03-22 12:50:57 -0400128 mWorkerThread = new HandlerThread(VolumeDialogControllerImpl.class.getSimpleName());
John Spurlockf88d8082015-03-25 18:09:51 -0400129 mWorkerThread.start();
130 mWorker = new W(mWorkerThread.getLooper());
131 mMediaSessions = createMediaSessions(mContext, mWorkerThread.getLooper(),
132 mMediaSessionsCallbacksW);
133 mAudio = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
134 mNoMan = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
135 mObserver = new SettingObserver(mWorker);
136 mObserver.init();
137 mReceiver.init();
John Spurlockf88d8082015-03-25 18:09:51 -0400138 mVibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
139 mHasVibrator = mVibrator != null && mVibrator.hasVibrator();
Beverly8ebef842017-07-12 10:58:22 -0400140 updateStatusBar();
Jason Monkae305972017-06-27 14:46:03 -0400141
142 boolean accessibilityVolumeStreamActive = context.getSystemService(
143 AccessibilityManager.class).isAccessibilityVolumeStreamActive();
144 mVolumeController.setA11yMode(accessibilityVolumeStreamActive ?
145 VolumePolicy.A11Y_MODE_INDEPENDENT_A11Y_VOLUME :
146 VolumePolicy.A11Y_MODE_MEDIA_A11Y_VOLUME);
John Spurlockf88d8082015-03-25 18:09:51 -0400147 }
148
John Spurlock76b52b32015-04-03 00:00:12 -0400149 public AudioManager getAudioManager() {
150 return mAudio;
151 }
152
John Spurlockf88d8082015-03-25 18:09:51 -0400153 public void dismiss() {
154 mCallbacks.onDismissRequested(Events.DISMISS_REASON_VOLUME_CONTROLLER);
155 }
156
Yao Chen634acb92016-04-13 16:17:47 -0700157 protected void setVolumeController() {
John Spurlockf88d8082015-03-25 18:09:51 -0400158 try {
159 mAudio.setVolumeController(mVolumeController);
160 } catch (SecurityException e) {
161 Log.w(TAG, "Unable to set the volume controller", e);
162 return;
163 }
Yao Chen634acb92016-04-13 16:17:47 -0700164 }
165
166 protected void setAudioManagerStreamVolume(int stream, int level, int flag) {
167 mAudio.setStreamVolume(stream, level, flag);
168 }
169
170 protected int getAudioManagerStreamVolume(int stream) {
171 return mAudio.getLastAudibleStreamVolume(stream);
172 }
173
174 protected int getAudioManagerStreamMaxVolume(int stream) {
175 return mAudio.getStreamMaxVolume(stream);
176 }
177
178 protected int getAudioManagerStreamMinVolume(int stream) {
Jean-Michel Trivi8e7aca32017-11-28 18:12:38 -0800179 return mAudio.getStreamMinVolumeInt(stream);
Yao Chen634acb92016-04-13 16:17:47 -0700180 }
181
182 public void register() {
183 setVolumeController();
John Spurlockf88d8082015-03-25 18:09:51 -0400184 setVolumePolicy(mVolumePolicy);
185 showDndTile(mShowDndTile);
186 try {
187 mMediaSessions.init();
188 } catch (SecurityException e) {
189 Log.w(TAG, "No access to media sessions", e);
190 }
191 }
192
193 public void setVolumePolicy(VolumePolicy policy) {
194 mVolumePolicy = policy;
John Spurlockb02c7442015-04-14 09:32:25 -0400195 if (mVolumePolicy == null) return;
John Spurlockf88d8082015-03-25 18:09:51 -0400196 try {
197 mAudio.setVolumePolicy(mVolumePolicy);
198 } catch (NoSuchMethodError e) {
199 Log.w(TAG, "No volume policy api");
200 }
201 }
202
203 protected MediaSessions createMediaSessions(Context context, Looper looper,
204 MediaSessions.Callbacks callbacks) {
205 return new MediaSessions(context, looper, callbacks);
206 }
207
208 public void destroy() {
209 if (D.BUG) Log.d(TAG, "destroy");
210 if (mDestroyed) return;
211 mDestroyed = true;
Chris Wrene565ee62015-06-17 15:24:56 -0400212 Events.writeEvent(mContext, Events.EVENT_COLLECTION_STOPPED);
John Spurlockf88d8082015-03-25 18:09:51 -0400213 mMediaSessions.destroy();
214 mObserver.destroy();
215 mReceiver.destroy();
216 mWorkerThread.quitSafely();
217 }
218
219 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jason Monk782cd672017-03-22 12:50:57 -0400220 pw.println(VolumeDialogControllerImpl.class.getSimpleName() + " state:");
John Spurlockf88d8082015-03-25 18:09:51 -0400221 pw.print(" mDestroyed: "); pw.println(mDestroyed);
222 pw.print(" mVolumePolicy: "); pw.println(mVolumePolicy);
John Spurlocke56efa712015-05-19 12:26:25 -0400223 pw.print(" mState: "); pw.println(mState.toString(4));
John Spurlockf88d8082015-03-25 18:09:51 -0400224 pw.print(" mShowDndTile: "); pw.println(mShowDndTile);
225 pw.print(" mHasVibrator: "); pw.println(mHasVibrator);
226 pw.print(" mRemoteStreams: "); pw.println(mMediaSessionsCallbacksW.mRemoteStreams
227 .values());
Julia Reynoldsdbfb40f2017-01-23 11:05:57 -0500228 pw.print(" mShowA11yStream: "); pw.println(mShowA11yStream);
John Spurlockf88d8082015-03-25 18:09:51 -0400229 pw.println();
230 mMediaSessions.dump(pw);
231 }
232
233 public void addCallback(Callbacks callback, Handler handler) {
234 mCallbacks.add(callback, handler);
Jason Monkae305972017-06-27 14:46:03 -0400235 callback.onAccessibilityModeChanged(mShowA11yStream);
John Spurlockf88d8082015-03-25 18:09:51 -0400236 }
237
Yao Chen634acb92016-04-13 16:17:47 -0700238 public void setUserActivityListener(UserActivityListener listener) {
239 if (mDestroyed) return;
240 synchronized (this) {
241 mUserActivityListener = listener;
242 }
243 }
244
John Spurlockf88d8082015-03-25 18:09:51 -0400245 public void removeCallback(Callbacks callback) {
246 mCallbacks.remove(callback);
247 }
248
249 public void getState() {
250 if (mDestroyed) return;
251 mWorker.sendEmptyMessage(W.GET_STATE);
252 }
253
254 public void notifyVisible(boolean visible) {
255 if (mDestroyed) return;
256 mWorker.obtainMessage(W.NOTIFY_VISIBLE, visible ? 1 : 0, 0).sendToTarget();
257 }
258
259 public void userActivity() {
260 if (mDestroyed) return;
261 mWorker.removeMessages(W.USER_ACTIVITY);
262 mWorker.sendEmptyMessage(W.USER_ACTIVITY);
263 }
264
265 public void setRingerMode(int value, boolean external) {
266 if (mDestroyed) return;
267 mWorker.obtainMessage(W.SET_RINGER_MODE, value, external ? 1 : 0).sendToTarget();
268 }
269
270 public void setZenMode(int value) {
271 if (mDestroyed) return;
272 mWorker.obtainMessage(W.SET_ZEN_MODE, value, 0).sendToTarget();
273 }
274
275 public void setExitCondition(Condition condition) {
276 if (mDestroyed) return;
277 mWorker.obtainMessage(W.SET_EXIT_CONDITION, condition).sendToTarget();
278 }
279
280 public void setStreamMute(int stream, boolean mute) {
281 if (mDestroyed) return;
282 mWorker.obtainMessage(W.SET_STREAM_MUTE, stream, mute ? 1 : 0).sendToTarget();
283 }
284
285 public void setStreamVolume(int stream, int level) {
286 if (mDestroyed) return;
287 mWorker.obtainMessage(W.SET_STREAM_VOLUME, stream, level).sendToTarget();
288 }
289
290 public void setActiveStream(int stream) {
291 if (mDestroyed) return;
292 mWorker.obtainMessage(W.SET_ACTIVE_STREAM, stream, 0).sendToTarget();
293 }
294
Luke Songe0036662017-12-12 12:27:08 -0800295 public void setEnableDialogs(boolean volumeUi, boolean safetyWarning) {
296 mShowVolumeDialog = volumeUi;
297 mShowSafetyWarning = safetyWarning;
298 }
299
John Spurlockf88d8082015-03-25 18:09:51 -0400300 public void vibrate() {
301 if (mHasVibrator) {
302 mVibrator.vibrate(VIBRATE_HINT_DURATION);
303 }
304 }
305
306 public boolean hasVibrator() {
307 return mHasVibrator;
308 }
309
310 private void onNotifyVisibleW(boolean visible) {
311 if (mDestroyed) return;
312 mAudio.notifyVolumeControllerVisible(mVolumeController, visible);
313 if (!visible) {
314 if (updateActiveStreamW(-1)) {
315 mCallbacks.onStateChanged(mState);
316 }
317 }
318 }
319
Yao Chen634acb92016-04-13 16:17:47 -0700320 private void onUserActivityW() {
321 synchronized (this) {
322 if (mUserActivityListener != null) {
323 mUserActivityListener.onUserActivity();
324 }
325 }
John Spurlockf88d8082015-03-25 18:09:51 -0400326 }
327
John Spurlock76b52b32015-04-03 00:00:12 -0400328 private void onShowSafetyWarningW(int flags) {
Luke Songe0036662017-12-12 12:27:08 -0800329 if (mShowSafetyWarning) {
330 mCallbacks.onShowSafetyWarning(flags);
331 }
John Spurlock76b52b32015-04-03 00:00:12 -0400332 }
333
Julia Reynoldsdbfb40f2017-01-23 11:05:57 -0500334 private void onAccessibilityModeChanged(Boolean showA11yStream) {
335 mCallbacks.onAccessibilityModeChanged(showA11yStream);
336 }
337
John Spurlockf88d8082015-03-25 18:09:51 -0400338 private boolean checkRoutedToBluetoothW(int stream) {
339 boolean changed = false;
340 if (stream == AudioManager.STREAM_MUSIC) {
341 final boolean routedToBluetooth =
342 (mAudio.getDevicesForStream(AudioManager.STREAM_MUSIC) &
343 (AudioManager.DEVICE_OUT_BLUETOOTH_A2DP |
344 AudioManager.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
345 AudioManager.DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER)) != 0;
346 changed |= updateStreamRoutedToBluetoothW(stream, routedToBluetooth);
347 }
348 return changed;
349 }
350
Beverly8ebef842017-07-12 10:58:22 -0400351 private void updateStatusBar() {
352 if (mStatusBar == null) {
353 mStatusBar = SysUiServiceProvider.getComponent(mContext, StatusBar.class);
354 }
355 }
356
Beverly85e05eb2017-07-21 14:49:27 -0400357 private boolean shouldShowUI(int flags) {
Beverly8ebef842017-07-12 10:58:22 -0400358 updateStatusBar();
Beverlya2f682f2018-02-01 11:29:25 -0500359 // if status bar isn't null, check if phone is in AOD, else check flags
360 // since we could be using a different status bar
361 return mStatusBar != null ?
362 mStatusBar.getWakefulnessState() != WakefulnessLifecycle.WAKEFULNESS_ASLEEP
363 && mStatusBar.getWakefulnessState() !=
364 WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP
Beverly85e05eb2017-07-21 14:49:27 -0400365 && mStatusBar.isDeviceInteractive()
Beverlya2f682f2018-02-01 11:29:25 -0500366 && (flags & AudioManager.FLAG_SHOW_UI) != 0 && mShowVolumeDialog
367 : mShowVolumeDialog && (flags & AudioManager.FLAG_SHOW_UI) != 0;
Beverly85e05eb2017-07-21 14:49:27 -0400368 }
Beverly8ebef842017-07-12 10:58:22 -0400369
Beverly85e05eb2017-07-21 14:49:27 -0400370 boolean onVolumeChangedW(int stream, int flags) {
371 final boolean showUI = shouldShowUI(flags);
John Spurlockf88d8082015-03-25 18:09:51 -0400372 final boolean fromKey = (flags & AudioManager.FLAG_FROM_KEY) != 0;
373 final boolean showVibrateHint = (flags & AudioManager.FLAG_SHOW_VIBRATE_HINT) != 0;
374 final boolean showSilentHint = (flags & AudioManager.FLAG_SHOW_SILENT_HINT) != 0;
375 boolean changed = false;
376 if (showUI) {
377 changed |= updateActiveStreamW(stream);
378 }
Yao Chen634acb92016-04-13 16:17:47 -0700379 int lastAudibleStreamVolume = getAudioManagerStreamVolume(stream);
Chris Wrene565ee62015-06-17 15:24:56 -0400380 changed |= updateStreamLevelW(stream, lastAudibleStreamVolume);
John Spurlockf88d8082015-03-25 18:09:51 -0400381 changed |= checkRoutedToBluetoothW(showUI ? AudioManager.STREAM_MUSIC : stream);
382 if (changed) {
383 mCallbacks.onStateChanged(mState);
384 }
385 if (showUI) {
386 mCallbacks.onShowRequested(Events.SHOW_REASON_VOLUME_CHANGED);
387 }
388 if (showVibrateHint) {
389 mCallbacks.onShowVibrateHint();
390 }
391 if (showSilentHint) {
392 mCallbacks.onShowSilentHint();
393 }
394 if (changed && fromKey) {
Chris Wrene565ee62015-06-17 15:24:56 -0400395 Events.writeEvent(mContext, Events.EVENT_KEY, stream, lastAudibleStreamVolume);
John Spurlockf88d8082015-03-25 18:09:51 -0400396 }
Julia Reynolds8ae994f2015-09-14 11:12:42 -0400397 return changed;
John Spurlockf88d8082015-03-25 18:09:51 -0400398 }
399
400 private boolean updateActiveStreamW(int activeStream) {
401 if (activeStream == mState.activeStream) return false;
402 mState.activeStream = activeStream;
Chris Wrene565ee62015-06-17 15:24:56 -0400403 Events.writeEvent(mContext, Events.EVENT_ACTIVE_STREAM_CHANGED, activeStream);
John Spurlockf88d8082015-03-25 18:09:51 -0400404 if (D.BUG) Log.d(TAG, "updateActiveStreamW " + activeStream);
405 final int s = activeStream < DYNAMIC_STREAM_START_INDEX ? activeStream : -1;
406 if (D.BUG) Log.d(TAG, "forceVolumeControlStream " + s);
407 mAudio.forceVolumeControlStream(s);
408 return true;
409 }
410
411 private StreamState streamStateW(int stream) {
412 StreamState ss = mState.states.get(stream);
413 if (ss == null) {
414 ss = new StreamState();
415 mState.states.put(stream, ss);
416 }
417 return ss;
418 }
419
420 private void onGetStateW() {
Julia Reynolds03c548f2016-12-14 15:02:38 -0500421 for (int stream : STREAMS.keySet()) {
Yao Chen634acb92016-04-13 16:17:47 -0700422 updateStreamLevelW(stream, getAudioManagerStreamVolume(stream));
423 streamStateW(stream).levelMin = getAudioManagerStreamMinVolume(stream);
424 streamStateW(stream).levelMax = getAudioManagerStreamMaxVolume(stream);
John Spurlockf88d8082015-03-25 18:09:51 -0400425 updateStreamMuteW(stream, mAudio.isStreamMute(stream));
426 final StreamState ss = streamStateW(stream);
427 ss.muteSupported = mAudio.isStreamAffectedByMute(stream);
Julia Reynolds03c548f2016-12-14 15:02:38 -0500428 ss.name = STREAMS.get(stream);
John Spurlockf88d8082015-03-25 18:09:51 -0400429 checkRoutedToBluetoothW(stream);
430 }
431 updateRingerModeExternalW(mAudio.getRingerMode());
432 updateZenModeW();
Beverly925cde82018-01-23 09:31:23 -0500433 updateZenConfig();
John Spurlockf88d8082015-03-25 18:09:51 -0400434 updateEffectsSuppressorW(mNoMan.getEffectsSuppressor());
John Spurlockf88d8082015-03-25 18:09:51 -0400435 mCallbacks.onStateChanged(mState);
436 }
437
438 private boolean updateStreamRoutedToBluetoothW(int stream, boolean routedToBluetooth) {
439 final StreamState ss = streamStateW(stream);
440 if (ss.routedToBluetooth == routedToBluetooth) return false;
441 ss.routedToBluetooth = routedToBluetooth;
442 if (D.BUG) Log.d(TAG, "updateStreamRoutedToBluetoothW stream=" + stream
443 + " routedToBluetooth=" + routedToBluetooth);
444 return true;
445 }
446
447 private boolean updateStreamLevelW(int stream, int level) {
448 final StreamState ss = streamStateW(stream);
449 if (ss.level == level) return false;
450 ss.level = level;
451 if (isLogWorthy(stream)) {
Chris Wrene565ee62015-06-17 15:24:56 -0400452 Events.writeEvent(mContext, Events.EVENT_LEVEL_CHANGED, stream, level);
John Spurlockf88d8082015-03-25 18:09:51 -0400453 }
454 return true;
455 }
456
457 private static boolean isLogWorthy(int stream) {
458 switch (stream) {
459 case AudioSystem.STREAM_ALARM:
460 case AudioSystem.STREAM_BLUETOOTH_SCO:
461 case AudioSystem.STREAM_MUSIC:
462 case AudioSystem.STREAM_RING:
463 case AudioSystem.STREAM_SYSTEM:
464 case AudioSystem.STREAM_VOICE_CALL:
465 return true;
466 }
467 return false;
468 }
469
470 private boolean updateStreamMuteW(int stream, boolean muted) {
471 final StreamState ss = streamStateW(stream);
472 if (ss.muted == muted) return false;
473 ss.muted = muted;
474 if (isLogWorthy(stream)) {
Chris Wrene565ee62015-06-17 15:24:56 -0400475 Events.writeEvent(mContext, Events.EVENT_MUTE_CHANGED, stream, muted);
John Spurlockf88d8082015-03-25 18:09:51 -0400476 }
477 if (muted && isRinger(stream)) {
478 updateRingerModeInternalW(mAudio.getRingerModeInternal());
479 }
480 return true;
481 }
482
483 private static boolean isRinger(int stream) {
484 return stream == AudioManager.STREAM_RING || stream == AudioManager.STREAM_NOTIFICATION;
485 }
486
John Spurlockf88d8082015-03-25 18:09:51 -0400487 private boolean updateEffectsSuppressorW(ComponentName effectsSuppressor) {
488 if (Objects.equals(mState.effectsSuppressor, effectsSuppressor)) return false;
489 mState.effectsSuppressor = effectsSuppressor;
490 mState.effectsSuppressorName = getApplicationName(mContext, mState.effectsSuppressor);
Chris Wrene565ee62015-06-17 15:24:56 -0400491 Events.writeEvent(mContext, Events.EVENT_SUPPRESSOR_CHANGED, mState.effectsSuppressor,
John Spurlockf88d8082015-03-25 18:09:51 -0400492 mState.effectsSuppressorName);
493 return true;
494 }
495
496 private static String getApplicationName(Context context, ComponentName component) {
497 if (component == null) return null;
498 final PackageManager pm = context.getPackageManager();
499 final String pkg = component.getPackageName();
500 try {
501 final ApplicationInfo ai = pm.getApplicationInfo(pkg, 0);
502 final String rt = Objects.toString(ai.loadLabel(pm), "").trim();
503 if (rt.length() > 0) {
504 return rt;
505 }
506 } catch (NameNotFoundException e) {}
507 return pkg;
508 }
509
510 private boolean updateZenModeW() {
511 final int zen = Settings.Global.getInt(mContext.getContentResolver(),
512 Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
513 if (mState.zenMode == zen) return false;
514 mState.zenMode = zen;
Chris Wrene565ee62015-06-17 15:24:56 -0400515 Events.writeEvent(mContext, Events.EVENT_ZEN_MODE_CHANGED, zen);
John Spurlockf88d8082015-03-25 18:09:51 -0400516 return true;
517 }
518
Beverly925cde82018-01-23 09:31:23 -0500519 private boolean updateZenConfig() {
520 final NotificationManager.Policy policy = mNotificationManager.getNotificationPolicy();
521 boolean disallowAlarms = (policy.priorityCategories & NotificationManager.Policy
522 .PRIORITY_CATEGORY_ALARMS) == 0;
523 boolean disallowMedia = (policy.priorityCategories & NotificationManager.Policy
524 .PRIORITY_CATEGORY_MEDIA_SYSTEM_OTHER) == 0;
525 boolean disallowRinger = ZenModeConfig.areAllPriorityOnlyNotificationZenSoundsMuted(policy);
526 if (mState.disallowAlarms == disallowAlarms && mState.disallowMedia == disallowMedia
527 && mState.disallowRinger == disallowRinger) {
528 return false;
529 }
530 mState.disallowAlarms = disallowAlarms;
531 mState.disallowMedia = disallowMedia;
532 mState.disallowRinger = disallowRinger;
533 Events.writeEvent(mContext, Events.EVENT_ZEN_CONFIG_CHANGED, "disallowAlarms=" +
534 disallowAlarms + " disallowMedia=" + disallowMedia + " disallowRinger=" +
535 disallowRinger);
536 return true;
537 }
538
John Spurlockf88d8082015-03-25 18:09:51 -0400539 private boolean updateRingerModeExternalW(int rm) {
540 if (rm == mState.ringerModeExternal) return false;
541 mState.ringerModeExternal = rm;
Chris Wrene565ee62015-06-17 15:24:56 -0400542 Events.writeEvent(mContext, Events.EVENT_EXTERNAL_RINGER_MODE_CHANGED, rm);
John Spurlockf88d8082015-03-25 18:09:51 -0400543 return true;
544 }
545
546 private boolean updateRingerModeInternalW(int rm) {
547 if (rm == mState.ringerModeInternal) return false;
548 mState.ringerModeInternal = rm;
Chris Wrene565ee62015-06-17 15:24:56 -0400549 Events.writeEvent(mContext, Events.EVENT_INTERNAL_RINGER_MODE_CHANGED, rm);
John Spurlockf88d8082015-03-25 18:09:51 -0400550 return true;
551 }
552
553 private void onSetRingerModeW(int mode, boolean external) {
554 if (external) {
555 mAudio.setRingerMode(mode);
556 } else {
557 mAudio.setRingerModeInternal(mode);
558 }
559 }
560
561 private void onSetStreamMuteW(int stream, boolean mute) {
562 mAudio.adjustStreamVolume(stream, mute ? AudioManager.ADJUST_MUTE
563 : AudioManager.ADJUST_UNMUTE, 0);
564 }
565
566 private void onSetStreamVolumeW(int stream, int level) {
567 if (D.BUG) Log.d(TAG, "onSetStreamVolume " + stream + " level=" + level);
568 if (stream >= DYNAMIC_STREAM_START_INDEX) {
569 mMediaSessionsCallbacksW.setStreamVolume(stream, level);
570 return;
571 }
Yao Chen634acb92016-04-13 16:17:47 -0700572 setAudioManagerStreamVolume(stream, level, 0);
John Spurlockf88d8082015-03-25 18:09:51 -0400573 }
574
575 private void onSetActiveStreamW(int stream) {
576 boolean changed = updateActiveStreamW(stream);
577 if (changed) {
578 mCallbacks.onStateChanged(mState);
579 }
580 }
581
582 private void onSetExitConditionW(Condition condition) {
John Spurlockb2278d62015-04-07 12:47:12 -0400583 mNoMan.setZenMode(mState.zenMode, condition != null ? condition.id : null, TAG);
John Spurlockf88d8082015-03-25 18:09:51 -0400584 }
585
586 private void onSetZenModeW(int mode) {
587 if (D.BUG) Log.d(TAG, "onSetZenModeW " + mode);
John Spurlockb2278d62015-04-07 12:47:12 -0400588 mNoMan.setZenMode(mode, null, TAG);
John Spurlockf88d8082015-03-25 18:09:51 -0400589 }
590
591 private void onDismissRequestedW(int reason) {
592 mCallbacks.onDismissRequested(reason);
593 }
594
595 public void showDndTile(boolean visible) {
596 if (D.BUG) Log.d(TAG, "showDndTile");
John Spurlockcd863ad2015-04-07 14:01:28 -0400597 DndTile.setVisible(mContext, visible);
John Spurlockf88d8082015-03-25 18:09:51 -0400598 }
599
600 private final class VC extends IVolumeController.Stub {
Jason Monk782cd672017-03-22 12:50:57 -0400601 private final String TAG = VolumeDialogControllerImpl.TAG + ".VC";
John Spurlockf88d8082015-03-25 18:09:51 -0400602
603 @Override
604 public void displaySafeVolumeWarning(int flags) throws RemoteException {
John Spurlock76b52b32015-04-03 00:00:12 -0400605 if (D.BUG) Log.d(TAG, "displaySafeVolumeWarning "
606 + Util.audioManagerFlagsToString(flags));
607 if (mDestroyed) return;
608 mWorker.obtainMessage(W.SHOW_SAFETY_WARNING, flags, 0).sendToTarget();
John Spurlockf88d8082015-03-25 18:09:51 -0400609 }
610
611 @Override
612 public void volumeChanged(int streamType, int flags) throws RemoteException {
613 if (D.BUG) Log.d(TAG, "volumeChanged " + AudioSystem.streamToString(streamType)
614 + " " + Util.audioManagerFlagsToString(flags));
615 if (mDestroyed) return;
616 mWorker.obtainMessage(W.VOLUME_CHANGED, streamType, flags).sendToTarget();
617 }
618
619 @Override
620 public void masterMuteChanged(int flags) throws RemoteException {
621 if (D.BUG) Log.d(TAG, "masterMuteChanged");
622 }
623
624 @Override
625 public void setLayoutDirection(int layoutDirection) throws RemoteException {
626 if (D.BUG) Log.d(TAG, "setLayoutDirection");
627 if (mDestroyed) return;
628 mWorker.obtainMessage(W.LAYOUT_DIRECTION_CHANGED, layoutDirection, 0).sendToTarget();
629 }
630
631 @Override
632 public void dismiss() throws RemoteException {
633 if (D.BUG) Log.d(TAG, "dismiss requested");
634 if (mDestroyed) return;
635 mWorker.obtainMessage(W.DISMISS_REQUESTED, Events.DISMISS_REASON_VOLUME_CONTROLLER, 0)
636 .sendToTarget();
637 mWorker.sendEmptyMessage(W.DISMISS_REQUESTED);
638 }
Jean-Michel Triviac487672016-11-11 10:05:18 -0800639
640 @Override
641 public void setA11yMode(int mode) {
642 if (D.BUG) Log.d(TAG, "setA11yMode to " + mode);
643 if (mDestroyed) return;
644 switch (mode) {
645 case VolumePolicy.A11Y_MODE_MEDIA_A11Y_VOLUME:
646 // "legacy" mode
Julia Reynoldsdbfb40f2017-01-23 11:05:57 -0500647 mShowA11yStream = false;
Jean-Michel Triviac487672016-11-11 10:05:18 -0800648 break;
649 case VolumePolicy.A11Y_MODE_INDEPENDENT_A11Y_VOLUME:
Julia Reynoldsdbfb40f2017-01-23 11:05:57 -0500650 mShowA11yStream = true;
Jean-Michel Triviac487672016-11-11 10:05:18 -0800651 break;
652 default:
653 Log.e(TAG, "Invalid accessibility mode " + mode);
654 break;
655 }
Julia Reynoldsdbfb40f2017-01-23 11:05:57 -0500656 mWorker.obtainMessage(W.ACCESSIBILITY_MODE_CHANGED, mShowA11yStream).sendToTarget();
Jean-Michel Triviac487672016-11-11 10:05:18 -0800657 }
John Spurlockf88d8082015-03-25 18:09:51 -0400658 }
659
660 private final class W extends Handler {
661 private static final int VOLUME_CHANGED = 1;
662 private static final int DISMISS_REQUESTED = 2;
663 private static final int GET_STATE = 3;
664 private static final int SET_RINGER_MODE = 4;
665 private static final int SET_ZEN_MODE = 5;
666 private static final int SET_EXIT_CONDITION = 6;
667 private static final int SET_STREAM_MUTE = 7;
668 private static final int LAYOUT_DIRECTION_CHANGED = 8;
669 private static final int CONFIGURATION_CHANGED = 9;
670 private static final int SET_STREAM_VOLUME = 10;
671 private static final int SET_ACTIVE_STREAM = 11;
672 private static final int NOTIFY_VISIBLE = 12;
673 private static final int USER_ACTIVITY = 13;
John Spurlock76b52b32015-04-03 00:00:12 -0400674 private static final int SHOW_SAFETY_WARNING = 14;
Julia Reynoldsdbfb40f2017-01-23 11:05:57 -0500675 private static final int ACCESSIBILITY_MODE_CHANGED = 15;
John Spurlockf88d8082015-03-25 18:09:51 -0400676
677 W(Looper looper) {
678 super(looper);
679 }
680
681 @Override
682 public void handleMessage(Message msg) {
683 switch (msg.what) {
684 case VOLUME_CHANGED: onVolumeChangedW(msg.arg1, msg.arg2); break;
685 case DISMISS_REQUESTED: onDismissRequestedW(msg.arg1); break;
686 case GET_STATE: onGetStateW(); break;
687 case SET_RINGER_MODE: onSetRingerModeW(msg.arg1, msg.arg2 != 0); break;
688 case SET_ZEN_MODE: onSetZenModeW(msg.arg1); break;
689 case SET_EXIT_CONDITION: onSetExitConditionW((Condition) msg.obj); break;
690 case SET_STREAM_MUTE: onSetStreamMuteW(msg.arg1, msg.arg2 != 0); break;
691 case LAYOUT_DIRECTION_CHANGED: mCallbacks.onLayoutDirectionChanged(msg.arg1); break;
692 case CONFIGURATION_CHANGED: mCallbacks.onConfigurationChanged(); break;
693 case SET_STREAM_VOLUME: onSetStreamVolumeW(msg.arg1, msg.arg2); break;
694 case SET_ACTIVE_STREAM: onSetActiveStreamW(msg.arg1); break;
John Spurlock76b52b32015-04-03 00:00:12 -0400695 case NOTIFY_VISIBLE: onNotifyVisibleW(msg.arg1 != 0); break;
696 case USER_ACTIVITY: onUserActivityW(); break;
697 case SHOW_SAFETY_WARNING: onShowSafetyWarningW(msg.arg1); break;
Julia Reynoldsdbfb40f2017-01-23 11:05:57 -0500698 case ACCESSIBILITY_MODE_CHANGED: onAccessibilityModeChanged((Boolean) msg.obj);
Julia Reynolds6692b472018-01-24 07:23:56 -0500699
John Spurlockf88d8082015-03-25 18:09:51 -0400700 }
701 }
702 }
703
Beverly8ebef842017-07-12 10:58:22 -0400704 class C implements Callbacks {
John Spurlockf88d8082015-03-25 18:09:51 -0400705 private final HashMap<Callbacks, Handler> mCallbackMap = new HashMap<>();
706
707 public void add(Callbacks callback, Handler handler) {
708 if (callback == null || handler == null) throw new IllegalArgumentException();
709 mCallbackMap.put(callback, handler);
710 }
711
712 public void remove(Callbacks callback) {
713 mCallbackMap.remove(callback);
714 }
715
716 @Override
717 public void onShowRequested(final int reason) {
718 for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
719 entry.getValue().post(new Runnable() {
720 @Override
721 public void run() {
722 entry.getKey().onShowRequested(reason);
723 }
724 });
725 }
726 }
727
728 @Override
729 public void onDismissRequested(final int reason) {
730 for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
731 entry.getValue().post(new Runnable() {
732 @Override
733 public void run() {
734 entry.getKey().onDismissRequested(reason);
735 }
736 });
737 }
738 }
739
740 @Override
741 public void onStateChanged(final State state) {
742 final long time = System.currentTimeMillis();
743 final State copy = state.copy();
744 for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
745 entry.getValue().post(new Runnable() {
746 @Override
747 public void run() {
748 entry.getKey().onStateChanged(copy);
749 }
750 });
751 }
752 Events.writeState(time, copy);
753 }
754
755 @Override
756 public void onLayoutDirectionChanged(final int layoutDirection) {
757 for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
758 entry.getValue().post(new Runnable() {
759 @Override
760 public void run() {
761 entry.getKey().onLayoutDirectionChanged(layoutDirection);
762 }
763 });
764 }
765 }
766
767 @Override
768 public void onConfigurationChanged() {
769 for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
770 entry.getValue().post(new Runnable() {
771 @Override
772 public void run() {
773 entry.getKey().onConfigurationChanged();
774 }
775 });
776 }
777 }
778
779 @Override
780 public void onShowVibrateHint() {
781 for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
782 entry.getValue().post(new Runnable() {
783 @Override
784 public void run() {
785 entry.getKey().onShowVibrateHint();
786 }
787 });
788 }
789 }
790
791 @Override
792 public void onShowSilentHint() {
793 for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
794 entry.getValue().post(new Runnable() {
795 @Override
796 public void run() {
797 entry.getKey().onShowSilentHint();
798 }
799 });
800 }
801 }
802
803 @Override
804 public void onScreenOff() {
805 for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
806 entry.getValue().post(new Runnable() {
807 @Override
808 public void run() {
809 entry.getKey().onScreenOff();
810 }
811 });
812 }
813 }
John Spurlock76b52b32015-04-03 00:00:12 -0400814
815 @Override
816 public void onShowSafetyWarning(final int flags) {
817 for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
818 entry.getValue().post(new Runnable() {
819 @Override
820 public void run() {
821 entry.getKey().onShowSafetyWarning(flags);
822 }
823 });
824 }
825 }
Julia Reynoldsdbfb40f2017-01-23 11:05:57 -0500826
827 @Override
828 public void onAccessibilityModeChanged(Boolean showA11yStream) {
829 boolean show = showA11yStream == null ? false : showA11yStream;
830 for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
831 entry.getValue().post(new Runnable() {
832 @Override
833 public void run() {
834 entry.getKey().onAccessibilityModeChanged(show);
835 }
836 });
837 }
838 }
John Spurlockf88d8082015-03-25 18:09:51 -0400839 }
840
841
842 private final class SettingObserver extends ContentObserver {
John Spurlockf88d8082015-03-25 18:09:51 -0400843 private final Uri ZEN_MODE_URI =
844 Settings.Global.getUriFor(Settings.Global.ZEN_MODE);
845 private final Uri ZEN_MODE_CONFIG_URI =
846 Settings.Global.getUriFor(Settings.Global.ZEN_MODE_CONFIG_ETAG);
847
848 public SettingObserver(Handler handler) {
849 super(handler);
850 }
851
852 public void init() {
John Spurlockf88d8082015-03-25 18:09:51 -0400853 mContext.getContentResolver().registerContentObserver(ZEN_MODE_URI, false, this);
854 mContext.getContentResolver().registerContentObserver(ZEN_MODE_CONFIG_URI, false, this);
John Spurlockf88d8082015-03-25 18:09:51 -0400855 }
856
857 public void destroy() {
858 mContext.getContentResolver().unregisterContentObserver(this);
859 }
860
861 @Override
862 public void onChange(boolean selfChange, Uri uri) {
863 boolean changed = false;
John Spurlockf88d8082015-03-25 18:09:51 -0400864 if (ZEN_MODE_URI.equals(uri)) {
865 changed = updateZenModeW();
866 }
Beverly925cde82018-01-23 09:31:23 -0500867 if (ZEN_MODE_CONFIG_URI.equals(uri)) {
868 changed |= updateZenConfig();
869 }
870
John Spurlockf88d8082015-03-25 18:09:51 -0400871 if (changed) {
872 mCallbacks.onStateChanged(mState);
873 }
874 }
875 }
876
877 private final class Receiver extends BroadcastReceiver {
878
879 public void init() {
880 final IntentFilter filter = new IntentFilter();
881 filter.addAction(AudioManager.VOLUME_CHANGED_ACTION);
882 filter.addAction(AudioManager.STREAM_DEVICES_CHANGED_ACTION);
883 filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
884 filter.addAction(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION);
885 filter.addAction(AudioManager.STREAM_MUTE_CHANGED_ACTION);
886 filter.addAction(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED);
887 filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
888 filter.addAction(Intent.ACTION_SCREEN_OFF);
John Spurlockbc7233a2015-06-29 15:34:18 -0400889 filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
John Spurlockf88d8082015-03-25 18:09:51 -0400890 mContext.registerReceiver(this, filter, null, mWorker);
891 }
892
893 public void destroy() {
894 mContext.unregisterReceiver(this);
895 }
896
897 @Override
898 public void onReceive(Context context, Intent intent) {
899 final String action = intent.getAction();
900 boolean changed = false;
901 if (action.equals(AudioManager.VOLUME_CHANGED_ACTION)) {
902 final int stream = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1);
903 final int level = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, -1);
904 final int oldLevel = intent
905 .getIntExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, -1);
906 if (D.BUG) Log.d(TAG, "onReceive VOLUME_CHANGED_ACTION stream=" + stream
907 + " level=" + level + " oldLevel=" + oldLevel);
908 changed = updateStreamLevelW(stream, level);
909 } else if (action.equals(AudioManager.STREAM_DEVICES_CHANGED_ACTION)) {
910 final int stream = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1);
911 final int devices = intent
912 .getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_DEVICES, -1);
913 final int oldDevices = intent
914 .getIntExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_DEVICES, -1);
915 if (D.BUG) Log.d(TAG, "onReceive STREAM_DEVICES_CHANGED_ACTION stream="
916 + stream + " devices=" + devices + " oldDevices=" + oldDevices);
917 changed = checkRoutedToBluetoothW(stream);
Julia Reynolds8ae994f2015-09-14 11:12:42 -0400918 changed |= onVolumeChangedW(stream, 0);
John Spurlockf88d8082015-03-25 18:09:51 -0400919 } else if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) {
920 final int rm = intent.getIntExtra(AudioManager.EXTRA_RINGER_MODE, -1);
921 if (D.BUG) Log.d(TAG, "onReceive RINGER_MODE_CHANGED_ACTION rm="
922 + Util.ringerModeToString(rm));
923 changed = updateRingerModeExternalW(rm);
924 } else if (action.equals(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION)) {
925 final int rm = intent.getIntExtra(AudioManager.EXTRA_RINGER_MODE, -1);
926 if (D.BUG) Log.d(TAG, "onReceive INTERNAL_RINGER_MODE_CHANGED_ACTION rm="
927 + Util.ringerModeToString(rm));
928 changed = updateRingerModeInternalW(rm);
929 } else if (action.equals(AudioManager.STREAM_MUTE_CHANGED_ACTION)) {
930 final int stream = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1);
931 final boolean muted = intent
932 .getBooleanExtra(AudioManager.EXTRA_STREAM_VOLUME_MUTED, false);
933 if (D.BUG) Log.d(TAG, "onReceive STREAM_MUTE_CHANGED_ACTION stream=" + stream
934 + " muted=" + muted);
935 changed = updateStreamMuteW(stream, muted);
936 } else if (action.equals(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED)) {
937 if (D.BUG) Log.d(TAG, "onReceive ACTION_EFFECTS_SUPPRESSOR_CHANGED");
938 changed = updateEffectsSuppressorW(mNoMan.getEffectsSuppressor());
939 } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
940 if (D.BUG) Log.d(TAG, "onReceive ACTION_CONFIGURATION_CHANGED");
941 mCallbacks.onConfigurationChanged();
942 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
943 if (D.BUG) Log.d(TAG, "onReceive ACTION_SCREEN_OFF");
944 mCallbacks.onScreenOff();
John Spurlockbc7233a2015-06-29 15:34:18 -0400945 } else if (action.equals(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) {
946 if (D.BUG) Log.d(TAG, "onReceive ACTION_CLOSE_SYSTEM_DIALOGS");
947 dismiss();
John Spurlockf88d8082015-03-25 18:09:51 -0400948 }
949 if (changed) {
950 mCallbacks.onStateChanged(mState);
951 }
952 }
953 }
954
Beverly4e936612017-07-28 14:05:30 -0400955 protected final class MediaSessionsCallbacks implements MediaSessions.Callbacks {
John Spurlockf88d8082015-03-25 18:09:51 -0400956 private final HashMap<Token, Integer> mRemoteStreams = new HashMap<>();
957
958 private int mNextStream = DYNAMIC_STREAM_START_INDEX;
959
960 @Override
961 public void onRemoteUpdate(Token token, String name, PlaybackInfo pi) {
Beverlyb5a27812017-07-24 11:34:48 -0400962 addStream(token, "onRemoteUpdate");
John Spurlockf88d8082015-03-25 18:09:51 -0400963 final int stream = mRemoteStreams.get(token);
964 boolean changed = mState.states.indexOfKey(stream) < 0;
965 final StreamState ss = streamStateW(stream);
966 ss.dynamic = true;
967 ss.levelMin = 0;
968 ss.levelMax = pi.getMaxVolume();
969 if (ss.level != pi.getCurrentVolume()) {
970 ss.level = pi.getCurrentVolume();
971 changed = true;
972 }
Julia Reynolds03c548f2016-12-14 15:02:38 -0500973 if (!Objects.equals(ss.remoteLabel, name)) {
974 ss.name = -1;
975 ss.remoteLabel = name;
John Spurlockf88d8082015-03-25 18:09:51 -0400976 changed = true;
977 }
978 if (changed) {
979 if (D.BUG) Log.d(TAG, "onRemoteUpdate: " + name + ": " + ss.level
980 + " of " + ss.levelMax);
981 mCallbacks.onStateChanged(mState);
982 }
983 }
984
985 @Override
986 public void onRemoteVolumeChanged(Token token, int flags) {
Beverlyb5a27812017-07-24 11:34:48 -0400987 addStream(token, "onRemoteVolumeChanged");
John Spurlockf88d8082015-03-25 18:09:51 -0400988 final int stream = mRemoteStreams.get(token);
Beverly85e05eb2017-07-21 14:49:27 -0400989 final boolean showUI = shouldShowUI(flags);
John Spurlockf88d8082015-03-25 18:09:51 -0400990 boolean changed = updateActiveStreamW(stream);
991 if (showUI) {
992 changed |= checkRoutedToBluetoothW(AudioManager.STREAM_MUSIC);
993 }
994 if (changed) {
995 mCallbacks.onStateChanged(mState);
996 }
997 if (showUI) {
998 mCallbacks.onShowRequested(Events.SHOW_REASON_REMOTE_VOLUME_CHANGED);
999 }
1000 }
1001
1002 @Override
1003 public void onRemoteRemoved(Token token) {
Beverlyb5a27812017-07-24 11:34:48 -04001004 if (!mRemoteStreams.containsKey(token)) {
1005 if (D.BUG) Log.d(TAG, "onRemoteRemoved: stream doesn't exist, "
1006 + "aborting remote removed for token:" + token.toString());
1007 return;
1008 }
John Spurlockf88d8082015-03-25 18:09:51 -04001009 final int stream = mRemoteStreams.get(token);
1010 mState.states.remove(stream);
1011 if (mState.activeStream == stream) {
1012 updateActiveStreamW(-1);
1013 }
1014 mCallbacks.onStateChanged(mState);
1015 }
1016
1017 public void setStreamVolume(int stream, int level) {
1018 final Token t = findToken(stream);
1019 if (t == null) {
1020 Log.w(TAG, "setStreamVolume: No token found for stream: " + stream);
1021 return;
1022 }
1023 mMediaSessions.setVolume(t, level);
1024 }
1025
1026 private Token findToken(int stream) {
1027 for (Map.Entry<Token, Integer> entry : mRemoteStreams.entrySet()) {
1028 if (entry.getValue().equals(stream)) {
1029 return entry.getKey();
1030 }
1031 }
1032 return null;
1033 }
Beverlyb5a27812017-07-24 11:34:48 -04001034
1035 private void addStream(Token token, String triggeringMethod) {
1036 if (!mRemoteStreams.containsKey(token)) {
1037 mRemoteStreams.put(token, mNextStream);
1038 if (D.BUG) Log.d(TAG, triggeringMethod + ": added stream " + mNextStream
1039 + " from token + "+ token.toString());
1040 mNextStream++;
1041 }
1042 }
John Spurlockf88d8082015-03-25 18:09:51 -04001043 }
1044
Yao Chen634acb92016-04-13 16:17:47 -07001045 public interface UserActivityListener {
1046 void onUserActivity();
1047 }
John Spurlockf88d8082015-03-25 18:09:51 -04001048}