blob: 4c16297154f37fde7096729c0e7904d0aa6f461c [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
Julia Reynoldsac55e012018-03-27 11:17:30 -040019import static android.media.AudioManager.RINGER_MODE_NORMAL;
20
John Spurlockf88d8082015-03-25 18:09:51 -040021import android.app.NotificationManager;
22import android.content.BroadcastReceiver;
23import android.content.ComponentName;
24import android.content.Context;
25import android.content.Intent;
26import android.content.IntentFilter;
27import android.content.pm.ApplicationInfo;
28import android.content.pm.PackageManager;
29import android.content.pm.PackageManager.NameNotFoundException;
30import android.database.ContentObserver;
Beverly512077e2018-03-15 13:54:43 -040031import android.media.AudioAttributes;
John Spurlockf88d8082015-03-25 18:09:51 -040032import android.media.AudioManager;
33import android.media.AudioSystem;
Julia Reynoldsac55e012018-03-27 11:17:30 -040034import android.media.IAudioService;
John Spurlockf88d8082015-03-25 18:09:51 -040035import android.media.IVolumeController;
36import android.media.VolumePolicy;
37import android.media.session.MediaController.PlaybackInfo;
38import android.media.session.MediaSession.Token;
39import android.net.Uri;
40import android.os.Handler;
41import android.os.HandlerThread;
42import android.os.Looper;
43import android.os.Message;
44import android.os.RemoteException;
Julia Reynoldsac55e012018-03-27 11:17:30 -040045import android.os.ServiceManager;
Beverly512077e2018-03-15 13:54:43 -040046import android.os.VibrationEffect;
John Spurlockf88d8082015-03-25 18:09:51 -040047import android.os.Vibrator;
48import android.provider.Settings;
49import android.service.notification.Condition;
Beverly925cde82018-01-23 09:31:23 -050050import android.service.notification.ZenModeConfig;
Julia Reynolds03c548f2016-12-14 15:02:38 -050051import android.util.ArrayMap;
John Spurlockf88d8082015-03-25 18:09:51 -040052import android.util.Log;
Jason Monkae305972017-06-27 14:46:03 -040053import android.view.accessibility.AccessibilityManager;
John Spurlockf88d8082015-03-25 18:09:51 -040054
Yao Chen634acb92016-04-13 16:17:47 -070055import com.android.internal.annotations.GuardedBy;
jackqdyulei2d7de482019-02-26 13:34:27 -080056import com.android.settingslib.volume.MediaSessions;
Jason Monk782cd672017-03-22 12:50:57 -040057import com.android.systemui.Dumpable;
John Spurlockf88d8082015-03-25 18:09:51 -040058import com.android.systemui.R;
Beverly8ebef842017-07-12 10:58:22 -040059import com.android.systemui.SysUiServiceProvider;
Beverly85e05eb2017-07-21 14:49:27 -040060import com.android.systemui.keyguard.WakefulnessLifecycle;
Jason Monk782cd672017-03-22 12:50:57 -040061import com.android.systemui.plugins.VolumeDialogController;
John Spurlockcd863ad2015-04-07 14:01:28 -040062import com.android.systemui.qs.tiles.DndTile;
Beverly8ebef842017-07-12 10:58:22 -040063import com.android.systemui.statusbar.phone.StatusBar;
John Spurlockf88d8082015-03-25 18:09:51 -040064
65import java.io.FileDescriptor;
66import java.io.PrintWriter;
67import java.util.HashMap;
68import java.util.Map;
69import java.util.Objects;
70
Jason Monk196d6392018-12-20 13:25:34 -050071import javax.inject.Inject;
72import javax.inject.Singleton;
73
John Spurlockf88d8082015-03-25 18:09:51 -040074/**
75 * Source of truth for all state / events related to the volume dialog. No presentation.
76 *
77 * All work done on a dedicated background worker thread & associated worker.
78 *
79 * Methods ending in "W" must be called on the worker thread.
80 */
Jason Monk196d6392018-12-20 13:25:34 -050081@Singleton
Jason Monk782cd672017-03-22 12:50:57 -040082public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpable {
83 private static final String TAG = Util.logTag(VolumeDialogControllerImpl.class);
John Spurlockf88d8082015-03-25 18:09:51 -040084
Julia Reynoldsac55e012018-03-27 11:17:30 -040085
86 private static final int TOUCH_FEEDBACK_TIMEOUT_MS = 1000;
John Spurlockf88d8082015-03-25 18:09:51 -040087 private static final int DYNAMIC_STREAM_START_INDEX = 100;
88 private static final int VIBRATE_HINT_DURATION = 50;
Julia Reynoldsac55e012018-03-27 11:17:30 -040089 private static final AudioAttributes SONIFICIATION_VIBRATION_ATTRIBUTES =
Beverly512077e2018-03-15 13:54:43 -040090 new AudioAttributes.Builder()
91 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
92 .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
93 .build();
John Spurlockf88d8082015-03-25 18:09:51 -040094
Julia Reynolds561d3f42018-01-26 11:31:02 -050095 static final ArrayMap<Integer, Integer> STREAMS = new ArrayMap<>();
Julia Reynolds03c548f2016-12-14 15:02:38 -050096 static {
97 STREAMS.put(AudioSystem.STREAM_ALARM, R.string.stream_alarm);
98 STREAMS.put(AudioSystem.STREAM_BLUETOOTH_SCO, R.string.stream_bluetooth_sco);
99 STREAMS.put(AudioSystem.STREAM_DTMF, R.string.stream_dtmf);
100 STREAMS.put(AudioSystem.STREAM_MUSIC, R.string.stream_music);
Julia Reynoldsdbfb40f2017-01-23 11:05:57 -0500101 STREAMS.put(AudioSystem.STREAM_ACCESSIBILITY, R.string.stream_accessibility);
Julia Reynolds03c548f2016-12-14 15:02:38 -0500102 STREAMS.put(AudioSystem.STREAM_NOTIFICATION, R.string.stream_notification);
103 STREAMS.put(AudioSystem.STREAM_RING, R.string.stream_ring);
104 STREAMS.put(AudioSystem.STREAM_SYSTEM, R.string.stream_system);
105 STREAMS.put(AudioSystem.STREAM_SYSTEM_ENFORCED, R.string.stream_system_enforced);
106 STREAMS.put(AudioSystem.STREAM_TTS, R.string.stream_tts);
107 STREAMS.put(AudioSystem.STREAM_VOICE_CALL, R.string.stream_voice_call);
Julia Reynolds03c548f2016-12-14 15:02:38 -0500108 }
John Spurlockf88d8082015-03-25 18:09:51 -0400109
110 private final HandlerThread mWorkerThread;
111 private final W mWorker;
112 private final Context mContext;
Yao Chen634acb92016-04-13 16:17:47 -0700113 private AudioManager mAudio;
Julia Reynoldsac55e012018-03-27 11:17:30 -0400114 private IAudioService mAudioService;
Beverly8ebef842017-07-12 10:58:22 -0400115 protected StatusBar mStatusBar;
John Spurlockf88d8082015-03-25 18:09:51 -0400116 private final NotificationManager mNoMan;
John Spurlockf88d8082015-03-25 18:09:51 -0400117 private final SettingObserver mObserver;
118 private final Receiver mReceiver = new Receiver();
119 private final MediaSessions mMediaSessions;
Beverly8ebef842017-07-12 10:58:22 -0400120 protected C mCallbacks = new C();
John Spurlockf88d8082015-03-25 18:09:51 -0400121 private final State mState = new State();
Beverly4e936612017-07-28 14:05:30 -0400122 protected final MediaSessionsCallbacks mMediaSessionsCallbacksW = new MediaSessionsCallbacks();
John Spurlockf88d8082015-03-25 18:09:51 -0400123 private final Vibrator mVibrator;
124 private final boolean mHasVibrator;
Julia Reynoldsdbfb40f2017-01-23 11:05:57 -0500125 private boolean mShowA11yStream;
Luke Songe0036662017-12-12 12:27:08 -0800126 private boolean mShowVolumeDialog;
127 private boolean mShowSafetyWarning;
Julia Reynoldsac55e012018-03-27 11:17:30 -0400128 private long mLastToggledRingerOn;
Beverly925cde82018-01-23 09:31:23 -0500129 private final NotificationManager mNotificationManager;
John Spurlockf88d8082015-03-25 18:09:51 -0400130
John Spurlockf88d8082015-03-25 18:09:51 -0400131 private boolean mDestroyed;
John Spurlockb02c7442015-04-14 09:32:25 -0400132 private VolumePolicy mVolumePolicy;
John Spurlockd9c75db2015-04-28 11:19:13 -0400133 private boolean mShowDndTile = true;
Yao Chen634acb92016-04-13 16:17:47 -0700134 @GuardedBy("this")
135 private UserActivityListener mUserActivityListener;
136
137 protected final VC mVolumeController = new VC();
John Spurlockf88d8082015-03-25 18:09:51 -0400138
Jason Monk196d6392018-12-20 13:25:34 -0500139 @Inject
Jason Monk782cd672017-03-22 12:50:57 -0400140 public VolumeDialogControllerImpl(Context context) {
John Spurlockf88d8082015-03-25 18:09:51 -0400141 mContext = context.getApplicationContext();
Beverly925cde82018-01-23 09:31:23 -0500142 mNotificationManager = (NotificationManager) mContext.getSystemService(
143 Context.NOTIFICATION_SERVICE);
Chris Wrene565ee62015-06-17 15:24:56 -0400144 Events.writeEvent(mContext, Events.EVENT_COLLECTION_STARTED);
Jason Monk782cd672017-03-22 12:50:57 -0400145 mWorkerThread = new HandlerThread(VolumeDialogControllerImpl.class.getSimpleName());
John Spurlockf88d8082015-03-25 18:09:51 -0400146 mWorkerThread.start();
147 mWorker = new W(mWorkerThread.getLooper());
148 mMediaSessions = createMediaSessions(mContext, mWorkerThread.getLooper(),
149 mMediaSessionsCallbacksW);
150 mAudio = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
151 mNoMan = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
152 mObserver = new SettingObserver(mWorker);
153 mObserver.init();
154 mReceiver.init();
John Spurlockf88d8082015-03-25 18:09:51 -0400155 mVibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
156 mHasVibrator = mVibrator != null && mVibrator.hasVibrator();
Julia Reynoldsac55e012018-03-27 11:17:30 -0400157 mAudioService = IAudioService.Stub.asInterface(
158 ServiceManager.getService(Context.AUDIO_SERVICE));
Beverly8ebef842017-07-12 10:58:22 -0400159 updateStatusBar();
Jason Monkae305972017-06-27 14:46:03 -0400160
161 boolean accessibilityVolumeStreamActive = context.getSystemService(
162 AccessibilityManager.class).isAccessibilityVolumeStreamActive();
163 mVolumeController.setA11yMode(accessibilityVolumeStreamActive ?
164 VolumePolicy.A11Y_MODE_INDEPENDENT_A11Y_VOLUME :
165 VolumePolicy.A11Y_MODE_MEDIA_A11Y_VOLUME);
John Spurlockf88d8082015-03-25 18:09:51 -0400166 }
167
John Spurlock76b52b32015-04-03 00:00:12 -0400168 public AudioManager getAudioManager() {
169 return mAudio;
170 }
171
John Spurlockf88d8082015-03-25 18:09:51 -0400172 public void dismiss() {
173 mCallbacks.onDismissRequested(Events.DISMISS_REASON_VOLUME_CONTROLLER);
174 }
175
Yao Chen634acb92016-04-13 16:17:47 -0700176 protected void setVolumeController() {
John Spurlockf88d8082015-03-25 18:09:51 -0400177 try {
178 mAudio.setVolumeController(mVolumeController);
179 } catch (SecurityException e) {
180 Log.w(TAG, "Unable to set the volume controller", e);
181 return;
182 }
Yao Chen634acb92016-04-13 16:17:47 -0700183 }
184
185 protected void setAudioManagerStreamVolume(int stream, int level, int flag) {
186 mAudio.setStreamVolume(stream, level, flag);
187 }
188
189 protected int getAudioManagerStreamVolume(int stream) {
190 return mAudio.getLastAudibleStreamVolume(stream);
191 }
192
193 protected int getAudioManagerStreamMaxVolume(int stream) {
194 return mAudio.getStreamMaxVolume(stream);
195 }
196
197 protected int getAudioManagerStreamMinVolume(int stream) {
Jean-Michel Trivi8e7aca32017-11-28 18:12:38 -0800198 return mAudio.getStreamMinVolumeInt(stream);
Yao Chen634acb92016-04-13 16:17:47 -0700199 }
200
201 public void register() {
202 setVolumeController();
John Spurlockf88d8082015-03-25 18:09:51 -0400203 setVolumePolicy(mVolumePolicy);
204 showDndTile(mShowDndTile);
205 try {
206 mMediaSessions.init();
207 } catch (SecurityException e) {
208 Log.w(TAG, "No access to media sessions", e);
209 }
210 }
211
212 public void setVolumePolicy(VolumePolicy policy) {
213 mVolumePolicy = policy;
John Spurlockb02c7442015-04-14 09:32:25 -0400214 if (mVolumePolicy == null) return;
John Spurlockf88d8082015-03-25 18:09:51 -0400215 try {
216 mAudio.setVolumePolicy(mVolumePolicy);
217 } catch (NoSuchMethodError e) {
218 Log.w(TAG, "No volume policy api");
219 }
220 }
221
222 protected MediaSessions createMediaSessions(Context context, Looper looper,
223 MediaSessions.Callbacks callbacks) {
224 return new MediaSessions(context, looper, callbacks);
225 }
226
227 public void destroy() {
228 if (D.BUG) Log.d(TAG, "destroy");
229 if (mDestroyed) return;
230 mDestroyed = true;
Chris Wrene565ee62015-06-17 15:24:56 -0400231 Events.writeEvent(mContext, Events.EVENT_COLLECTION_STOPPED);
John Spurlockf88d8082015-03-25 18:09:51 -0400232 mMediaSessions.destroy();
233 mObserver.destroy();
234 mReceiver.destroy();
235 mWorkerThread.quitSafely();
236 }
237
238 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jason Monk782cd672017-03-22 12:50:57 -0400239 pw.println(VolumeDialogControllerImpl.class.getSimpleName() + " state:");
John Spurlockf88d8082015-03-25 18:09:51 -0400240 pw.print(" mDestroyed: "); pw.println(mDestroyed);
241 pw.print(" mVolumePolicy: "); pw.println(mVolumePolicy);
John Spurlocke56efa712015-05-19 12:26:25 -0400242 pw.print(" mState: "); pw.println(mState.toString(4));
John Spurlockf88d8082015-03-25 18:09:51 -0400243 pw.print(" mShowDndTile: "); pw.println(mShowDndTile);
244 pw.print(" mHasVibrator: "); pw.println(mHasVibrator);
245 pw.print(" mRemoteStreams: "); pw.println(mMediaSessionsCallbacksW.mRemoteStreams
246 .values());
Julia Reynoldsdbfb40f2017-01-23 11:05:57 -0500247 pw.print(" mShowA11yStream: "); pw.println(mShowA11yStream);
John Spurlockf88d8082015-03-25 18:09:51 -0400248 pw.println();
249 mMediaSessions.dump(pw);
250 }
251
252 public void addCallback(Callbacks callback, Handler handler) {
253 mCallbacks.add(callback, handler);
Jason Monkae305972017-06-27 14:46:03 -0400254 callback.onAccessibilityModeChanged(mShowA11yStream);
John Spurlockf88d8082015-03-25 18:09:51 -0400255 }
256
Yao Chen634acb92016-04-13 16:17:47 -0700257 public void setUserActivityListener(UserActivityListener listener) {
258 if (mDestroyed) return;
259 synchronized (this) {
260 mUserActivityListener = listener;
261 }
262 }
263
John Spurlockf88d8082015-03-25 18:09:51 -0400264 public void removeCallback(Callbacks callback) {
265 mCallbacks.remove(callback);
266 }
267
268 public void getState() {
269 if (mDestroyed) return;
270 mWorker.sendEmptyMessage(W.GET_STATE);
271 }
272
273 public void notifyVisible(boolean visible) {
274 if (mDestroyed) return;
275 mWorker.obtainMessage(W.NOTIFY_VISIBLE, visible ? 1 : 0, 0).sendToTarget();
276 }
277
278 public void userActivity() {
279 if (mDestroyed) return;
280 mWorker.removeMessages(W.USER_ACTIVITY);
281 mWorker.sendEmptyMessage(W.USER_ACTIVITY);
282 }
283
284 public void setRingerMode(int value, boolean external) {
285 if (mDestroyed) return;
286 mWorker.obtainMessage(W.SET_RINGER_MODE, value, external ? 1 : 0).sendToTarget();
287 }
288
289 public void setZenMode(int value) {
290 if (mDestroyed) return;
291 mWorker.obtainMessage(W.SET_ZEN_MODE, value, 0).sendToTarget();
292 }
293
294 public void setExitCondition(Condition condition) {
295 if (mDestroyed) return;
296 mWorker.obtainMessage(W.SET_EXIT_CONDITION, condition).sendToTarget();
297 }
298
299 public void setStreamMute(int stream, boolean mute) {
300 if (mDestroyed) return;
301 mWorker.obtainMessage(W.SET_STREAM_MUTE, stream, mute ? 1 : 0).sendToTarget();
302 }
303
304 public void setStreamVolume(int stream, int level) {
305 if (mDestroyed) return;
306 mWorker.obtainMessage(W.SET_STREAM_VOLUME, stream, level).sendToTarget();
307 }
308
309 public void setActiveStream(int stream) {
310 if (mDestroyed) return;
311 mWorker.obtainMessage(W.SET_ACTIVE_STREAM, stream, 0).sendToTarget();
312 }
313
Luke Songe0036662017-12-12 12:27:08 -0800314 public void setEnableDialogs(boolean volumeUi, boolean safetyWarning) {
315 mShowVolumeDialog = volumeUi;
316 mShowSafetyWarning = safetyWarning;
317 }
318
Julia Reynoldsac55e012018-03-27 11:17:30 -0400319 @Override
320 public void scheduleTouchFeedback() {
321 mLastToggledRingerOn = System.currentTimeMillis();
322 }
323
324 private void playTouchFeedback() {
325 if (System.currentTimeMillis() - mLastToggledRingerOn < TOUCH_FEEDBACK_TIMEOUT_MS) {
326 try {
327 mAudioService.playSoundEffect(AudioManager.FX_KEYPRESS_STANDARD);
328 } catch (RemoteException e) {
329 // ignore
330 }
331 }
332 }
333
334 public void vibrate(VibrationEffect effect) {
John Spurlockf88d8082015-03-25 18:09:51 -0400335 if (mHasVibrator) {
Julia Reynoldsac55e012018-03-27 11:17:30 -0400336 mVibrator.vibrate(effect, SONIFICIATION_VIBRATION_ATTRIBUTES);
John Spurlockf88d8082015-03-25 18:09:51 -0400337 }
338 }
339
340 public boolean hasVibrator() {
341 return mHasVibrator;
342 }
343
344 private void onNotifyVisibleW(boolean visible) {
Beverly512077e2018-03-15 13:54:43 -0400345 if (mDestroyed) return;
John Spurlockf88d8082015-03-25 18:09:51 -0400346 mAudio.notifyVolumeControllerVisible(mVolumeController, visible);
347 if (!visible) {
348 if (updateActiveStreamW(-1)) {
349 mCallbacks.onStateChanged(mState);
350 }
351 }
352 }
353
Yao Chen634acb92016-04-13 16:17:47 -0700354 private void onUserActivityW() {
355 synchronized (this) {
356 if (mUserActivityListener != null) {
357 mUserActivityListener.onUserActivity();
358 }
359 }
John Spurlockf88d8082015-03-25 18:09:51 -0400360 }
361
John Spurlock76b52b32015-04-03 00:00:12 -0400362 private void onShowSafetyWarningW(int flags) {
Luke Songe0036662017-12-12 12:27:08 -0800363 if (mShowSafetyWarning) {
364 mCallbacks.onShowSafetyWarning(flags);
365 }
John Spurlock76b52b32015-04-03 00:00:12 -0400366 }
367
Julia Reynoldsdbfb40f2017-01-23 11:05:57 -0500368 private void onAccessibilityModeChanged(Boolean showA11yStream) {
369 mCallbacks.onAccessibilityModeChanged(showA11yStream);
370 }
371
John Spurlockf88d8082015-03-25 18:09:51 -0400372 private boolean checkRoutedToBluetoothW(int stream) {
373 boolean changed = false;
374 if (stream == AudioManager.STREAM_MUSIC) {
375 final boolean routedToBluetooth =
376 (mAudio.getDevicesForStream(AudioManager.STREAM_MUSIC) &
377 (AudioManager.DEVICE_OUT_BLUETOOTH_A2DP |
378 AudioManager.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
379 AudioManager.DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER)) != 0;
380 changed |= updateStreamRoutedToBluetoothW(stream, routedToBluetooth);
381 }
382 return changed;
383 }
384
Beverly8ebef842017-07-12 10:58:22 -0400385 private void updateStatusBar() {
386 if (mStatusBar == null) {
387 mStatusBar = SysUiServiceProvider.getComponent(mContext, StatusBar.class);
388 }
389 }
390
Beverly85e05eb2017-07-21 14:49:27 -0400391 private boolean shouldShowUI(int flags) {
Beverly8ebef842017-07-12 10:58:22 -0400392 updateStatusBar();
Beverlya2f682f2018-02-01 11:29:25 -0500393 // if status bar isn't null, check if phone is in AOD, else check flags
394 // since we could be using a different status bar
395 return mStatusBar != null ?
396 mStatusBar.getWakefulnessState() != WakefulnessLifecycle.WAKEFULNESS_ASLEEP
397 && mStatusBar.getWakefulnessState() !=
398 WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP
Beverly85e05eb2017-07-21 14:49:27 -0400399 && mStatusBar.isDeviceInteractive()
Beverlya2f682f2018-02-01 11:29:25 -0500400 && (flags & AudioManager.FLAG_SHOW_UI) != 0 && mShowVolumeDialog
401 : mShowVolumeDialog && (flags & AudioManager.FLAG_SHOW_UI) != 0;
Beverly85e05eb2017-07-21 14:49:27 -0400402 }
Beverly8ebef842017-07-12 10:58:22 -0400403
Beverly85e05eb2017-07-21 14:49:27 -0400404 boolean onVolumeChangedW(int stream, int flags) {
405 final boolean showUI = shouldShowUI(flags);
John Spurlockf88d8082015-03-25 18:09:51 -0400406 final boolean fromKey = (flags & AudioManager.FLAG_FROM_KEY) != 0;
407 final boolean showVibrateHint = (flags & AudioManager.FLAG_SHOW_VIBRATE_HINT) != 0;
408 final boolean showSilentHint = (flags & AudioManager.FLAG_SHOW_SILENT_HINT) != 0;
409 boolean changed = false;
410 if (showUI) {
411 changed |= updateActiveStreamW(stream);
412 }
Yao Chen634acb92016-04-13 16:17:47 -0700413 int lastAudibleStreamVolume = getAudioManagerStreamVolume(stream);
Chris Wrene565ee62015-06-17 15:24:56 -0400414 changed |= updateStreamLevelW(stream, lastAudibleStreamVolume);
John Spurlockf88d8082015-03-25 18:09:51 -0400415 changed |= checkRoutedToBluetoothW(showUI ? AudioManager.STREAM_MUSIC : stream);
416 if (changed) {
417 mCallbacks.onStateChanged(mState);
418 }
419 if (showUI) {
420 mCallbacks.onShowRequested(Events.SHOW_REASON_VOLUME_CHANGED);
421 }
422 if (showVibrateHint) {
423 mCallbacks.onShowVibrateHint();
424 }
425 if (showSilentHint) {
426 mCallbacks.onShowSilentHint();
427 }
428 if (changed && fromKey) {
Chris Wrene565ee62015-06-17 15:24:56 -0400429 Events.writeEvent(mContext, Events.EVENT_KEY, stream, lastAudibleStreamVolume);
John Spurlockf88d8082015-03-25 18:09:51 -0400430 }
Julia Reynolds8ae994f2015-09-14 11:12:42 -0400431 return changed;
John Spurlockf88d8082015-03-25 18:09:51 -0400432 }
433
434 private boolean updateActiveStreamW(int activeStream) {
435 if (activeStream == mState.activeStream) return false;
436 mState.activeStream = activeStream;
Chris Wrene565ee62015-06-17 15:24:56 -0400437 Events.writeEvent(mContext, Events.EVENT_ACTIVE_STREAM_CHANGED, activeStream);
John Spurlockf88d8082015-03-25 18:09:51 -0400438 if (D.BUG) Log.d(TAG, "updateActiveStreamW " + activeStream);
439 final int s = activeStream < DYNAMIC_STREAM_START_INDEX ? activeStream : -1;
440 if (D.BUG) Log.d(TAG, "forceVolumeControlStream " + s);
441 mAudio.forceVolumeControlStream(s);
442 return true;
443 }
444
445 private StreamState streamStateW(int stream) {
446 StreamState ss = mState.states.get(stream);
447 if (ss == null) {
448 ss = new StreamState();
449 mState.states.put(stream, ss);
450 }
451 return ss;
452 }
453
454 private void onGetStateW() {
Julia Reynolds03c548f2016-12-14 15:02:38 -0500455 for (int stream : STREAMS.keySet()) {
Yao Chen634acb92016-04-13 16:17:47 -0700456 updateStreamLevelW(stream, getAudioManagerStreamVolume(stream));
457 streamStateW(stream).levelMin = getAudioManagerStreamMinVolume(stream);
Julia Reynoldsac55e012018-03-27 11:17:30 -0400458 streamStateW(stream).levelMax = Math.max(1, getAudioManagerStreamMaxVolume(stream));
John Spurlockf88d8082015-03-25 18:09:51 -0400459 updateStreamMuteW(stream, mAudio.isStreamMute(stream));
460 final StreamState ss = streamStateW(stream);
461 ss.muteSupported = mAudio.isStreamAffectedByMute(stream);
Julia Reynolds03c548f2016-12-14 15:02:38 -0500462 ss.name = STREAMS.get(stream);
John Spurlockf88d8082015-03-25 18:09:51 -0400463 checkRoutedToBluetoothW(stream);
464 }
465 updateRingerModeExternalW(mAudio.getRingerMode());
466 updateZenModeW();
Beverly925cde82018-01-23 09:31:23 -0500467 updateZenConfig();
John Spurlockf88d8082015-03-25 18:09:51 -0400468 updateEffectsSuppressorW(mNoMan.getEffectsSuppressor());
John Spurlockf88d8082015-03-25 18:09:51 -0400469 mCallbacks.onStateChanged(mState);
470 }
471
472 private boolean updateStreamRoutedToBluetoothW(int stream, boolean routedToBluetooth) {
473 final StreamState ss = streamStateW(stream);
474 if (ss.routedToBluetooth == routedToBluetooth) return false;
475 ss.routedToBluetooth = routedToBluetooth;
476 if (D.BUG) Log.d(TAG, "updateStreamRoutedToBluetoothW stream=" + stream
477 + " routedToBluetooth=" + routedToBluetooth);
478 return true;
479 }
480
481 private boolean updateStreamLevelW(int stream, int level) {
482 final StreamState ss = streamStateW(stream);
483 if (ss.level == level) return false;
484 ss.level = level;
485 if (isLogWorthy(stream)) {
Chris Wrene565ee62015-06-17 15:24:56 -0400486 Events.writeEvent(mContext, Events.EVENT_LEVEL_CHANGED, stream, level);
John Spurlockf88d8082015-03-25 18:09:51 -0400487 }
488 return true;
489 }
490
491 private static boolean isLogWorthy(int stream) {
492 switch (stream) {
493 case AudioSystem.STREAM_ALARM:
494 case AudioSystem.STREAM_BLUETOOTH_SCO:
495 case AudioSystem.STREAM_MUSIC:
496 case AudioSystem.STREAM_RING:
497 case AudioSystem.STREAM_SYSTEM:
498 case AudioSystem.STREAM_VOICE_CALL:
499 return true;
500 }
501 return false;
502 }
503
504 private boolean updateStreamMuteW(int stream, boolean muted) {
505 final StreamState ss = streamStateW(stream);
506 if (ss.muted == muted) return false;
507 ss.muted = muted;
508 if (isLogWorthy(stream)) {
Chris Wrene565ee62015-06-17 15:24:56 -0400509 Events.writeEvent(mContext, Events.EVENT_MUTE_CHANGED, stream, muted);
John Spurlockf88d8082015-03-25 18:09:51 -0400510 }
511 if (muted && isRinger(stream)) {
512 updateRingerModeInternalW(mAudio.getRingerModeInternal());
513 }
514 return true;
515 }
516
517 private static boolean isRinger(int stream) {
518 return stream == AudioManager.STREAM_RING || stream == AudioManager.STREAM_NOTIFICATION;
519 }
520
John Spurlockf88d8082015-03-25 18:09:51 -0400521 private boolean updateEffectsSuppressorW(ComponentName effectsSuppressor) {
522 if (Objects.equals(mState.effectsSuppressor, effectsSuppressor)) return false;
523 mState.effectsSuppressor = effectsSuppressor;
524 mState.effectsSuppressorName = getApplicationName(mContext, mState.effectsSuppressor);
Chris Wrene565ee62015-06-17 15:24:56 -0400525 Events.writeEvent(mContext, Events.EVENT_SUPPRESSOR_CHANGED, mState.effectsSuppressor,
John Spurlockf88d8082015-03-25 18:09:51 -0400526 mState.effectsSuppressorName);
527 return true;
528 }
529
530 private static String getApplicationName(Context context, ComponentName component) {
531 if (component == null) return null;
532 final PackageManager pm = context.getPackageManager();
533 final String pkg = component.getPackageName();
534 try {
535 final ApplicationInfo ai = pm.getApplicationInfo(pkg, 0);
536 final String rt = Objects.toString(ai.loadLabel(pm), "").trim();
537 if (rt.length() > 0) {
538 return rt;
539 }
540 } catch (NameNotFoundException e) {}
541 return pkg;
542 }
543
544 private boolean updateZenModeW() {
545 final int zen = Settings.Global.getInt(mContext.getContentResolver(),
546 Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
547 if (mState.zenMode == zen) return false;
548 mState.zenMode = zen;
Chris Wrene565ee62015-06-17 15:24:56 -0400549 Events.writeEvent(mContext, Events.EVENT_ZEN_MODE_CHANGED, zen);
John Spurlockf88d8082015-03-25 18:09:51 -0400550 return true;
551 }
552
Beverly925cde82018-01-23 09:31:23 -0500553 private boolean updateZenConfig() {
Beverly12196702018-12-12 15:05:51 -0500554 final NotificationManager.Policy policy =
555 mNotificationManager.getConsolidatedNotificationPolicy();
Beverly925cde82018-01-23 09:31:23 -0500556 boolean disallowAlarms = (policy.priorityCategories & NotificationManager.Policy
557 .PRIORITY_CATEGORY_ALARMS) == 0;
558 boolean disallowMedia = (policy.priorityCategories & NotificationManager.Policy
Beverlyd6964762018-02-16 14:07:03 -0500559 .PRIORITY_CATEGORY_MEDIA) == 0;
560 boolean disallowSystem = (policy.priorityCategories & NotificationManager.Policy
561 .PRIORITY_CATEGORY_SYSTEM) == 0;
Beverly925cde82018-01-23 09:31:23 -0500562 boolean disallowRinger = ZenModeConfig.areAllPriorityOnlyNotificationZenSoundsMuted(policy);
Beverlyd6964762018-02-16 14:07:03 -0500563 if (mState.disallowAlarms == disallowAlarms
564 && mState.disallowMedia == disallowMedia
565 && mState.disallowRinger == disallowRinger
566 && mState.disallowSystem == disallowSystem) {
Beverly925cde82018-01-23 09:31:23 -0500567 return false;
568 }
569 mState.disallowAlarms = disallowAlarms;
570 mState.disallowMedia = disallowMedia;
Beverlyd6964762018-02-16 14:07:03 -0500571 mState.disallowSystem = disallowSystem;
Beverly925cde82018-01-23 09:31:23 -0500572 mState.disallowRinger = disallowRinger;
573 Events.writeEvent(mContext, Events.EVENT_ZEN_CONFIG_CHANGED, "disallowAlarms=" +
Beverlyd6964762018-02-16 14:07:03 -0500574 disallowAlarms + " disallowMedia=" + disallowMedia + " disallowSystem=" +
575 disallowSystem + " disallowRinger=" + disallowRinger);
Beverly925cde82018-01-23 09:31:23 -0500576 return true;
577 }
578
John Spurlockf88d8082015-03-25 18:09:51 -0400579 private boolean updateRingerModeExternalW(int rm) {
580 if (rm == mState.ringerModeExternal) return false;
581 mState.ringerModeExternal = rm;
Chris Wrene565ee62015-06-17 15:24:56 -0400582 Events.writeEvent(mContext, Events.EVENT_EXTERNAL_RINGER_MODE_CHANGED, rm);
John Spurlockf88d8082015-03-25 18:09:51 -0400583 return true;
584 }
585
586 private boolean updateRingerModeInternalW(int rm) {
587 if (rm == mState.ringerModeInternal) return false;
588 mState.ringerModeInternal = rm;
Chris Wrene565ee62015-06-17 15:24:56 -0400589 Events.writeEvent(mContext, Events.EVENT_INTERNAL_RINGER_MODE_CHANGED, rm);
Julia Reynoldsac55e012018-03-27 11:17:30 -0400590
Beverly Taiefd8e082018-05-15 23:49:05 +0000591 if (mState.ringerModeInternal == RINGER_MODE_NORMAL) {
592 playTouchFeedback();
593 }
594
Beverlyd253f982018-05-14 16:48:40 -0400595 return true;
596 }
597
John Spurlockf88d8082015-03-25 18:09:51 -0400598 private void onSetRingerModeW(int mode, boolean external) {
599 if (external) {
600 mAudio.setRingerMode(mode);
601 } else {
602 mAudio.setRingerModeInternal(mode);
603 }
604 }
605
606 private void onSetStreamMuteW(int stream, boolean mute) {
607 mAudio.adjustStreamVolume(stream, mute ? AudioManager.ADJUST_MUTE
608 : AudioManager.ADJUST_UNMUTE, 0);
609 }
610
611 private void onSetStreamVolumeW(int stream, int level) {
612 if (D.BUG) Log.d(TAG, "onSetStreamVolume " + stream + " level=" + level);
613 if (stream >= DYNAMIC_STREAM_START_INDEX) {
614 mMediaSessionsCallbacksW.setStreamVolume(stream, level);
615 return;
616 }
Yao Chen634acb92016-04-13 16:17:47 -0700617 setAudioManagerStreamVolume(stream, level, 0);
John Spurlockf88d8082015-03-25 18:09:51 -0400618 }
619
620 private void onSetActiveStreamW(int stream) {
621 boolean changed = updateActiveStreamW(stream);
622 if (changed) {
623 mCallbacks.onStateChanged(mState);
624 }
625 }
626
627 private void onSetExitConditionW(Condition condition) {
John Spurlockb2278d62015-04-07 12:47:12 -0400628 mNoMan.setZenMode(mState.zenMode, condition != null ? condition.id : null, TAG);
John Spurlockf88d8082015-03-25 18:09:51 -0400629 }
630
631 private void onSetZenModeW(int mode) {
632 if (D.BUG) Log.d(TAG, "onSetZenModeW " + mode);
John Spurlockb2278d62015-04-07 12:47:12 -0400633 mNoMan.setZenMode(mode, null, TAG);
John Spurlockf88d8082015-03-25 18:09:51 -0400634 }
635
636 private void onDismissRequestedW(int reason) {
637 mCallbacks.onDismissRequested(reason);
638 }
639
640 public void showDndTile(boolean visible) {
641 if (D.BUG) Log.d(TAG, "showDndTile");
John Spurlockcd863ad2015-04-07 14:01:28 -0400642 DndTile.setVisible(mContext, visible);
John Spurlockf88d8082015-03-25 18:09:51 -0400643 }
644
645 private final class VC extends IVolumeController.Stub {
Jason Monk782cd672017-03-22 12:50:57 -0400646 private final String TAG = VolumeDialogControllerImpl.TAG + ".VC";
John Spurlockf88d8082015-03-25 18:09:51 -0400647
648 @Override
649 public void displaySafeVolumeWarning(int flags) throws RemoteException {
John Spurlock76b52b32015-04-03 00:00:12 -0400650 if (D.BUG) Log.d(TAG, "displaySafeVolumeWarning "
651 + Util.audioManagerFlagsToString(flags));
652 if (mDestroyed) return;
653 mWorker.obtainMessage(W.SHOW_SAFETY_WARNING, flags, 0).sendToTarget();
John Spurlockf88d8082015-03-25 18:09:51 -0400654 }
655
656 @Override
657 public void volumeChanged(int streamType, int flags) throws RemoteException {
658 if (D.BUG) Log.d(TAG, "volumeChanged " + AudioSystem.streamToString(streamType)
659 + " " + Util.audioManagerFlagsToString(flags));
660 if (mDestroyed) return;
661 mWorker.obtainMessage(W.VOLUME_CHANGED, streamType, flags).sendToTarget();
662 }
663
664 @Override
665 public void masterMuteChanged(int flags) throws RemoteException {
666 if (D.BUG) Log.d(TAG, "masterMuteChanged");
667 }
668
669 @Override
670 public void setLayoutDirection(int layoutDirection) throws RemoteException {
671 if (D.BUG) Log.d(TAG, "setLayoutDirection");
672 if (mDestroyed) return;
673 mWorker.obtainMessage(W.LAYOUT_DIRECTION_CHANGED, layoutDirection, 0).sendToTarget();
674 }
675
676 @Override
677 public void dismiss() throws RemoteException {
678 if (D.BUG) Log.d(TAG, "dismiss requested");
679 if (mDestroyed) return;
680 mWorker.obtainMessage(W.DISMISS_REQUESTED, Events.DISMISS_REASON_VOLUME_CONTROLLER, 0)
681 .sendToTarget();
682 mWorker.sendEmptyMessage(W.DISMISS_REQUESTED);
683 }
Jean-Michel Triviac487672016-11-11 10:05:18 -0800684
685 @Override
686 public void setA11yMode(int mode) {
687 if (D.BUG) Log.d(TAG, "setA11yMode to " + mode);
688 if (mDestroyed) return;
689 switch (mode) {
690 case VolumePolicy.A11Y_MODE_MEDIA_A11Y_VOLUME:
691 // "legacy" mode
Julia Reynoldsdbfb40f2017-01-23 11:05:57 -0500692 mShowA11yStream = false;
Jean-Michel Triviac487672016-11-11 10:05:18 -0800693 break;
694 case VolumePolicy.A11Y_MODE_INDEPENDENT_A11Y_VOLUME:
Julia Reynoldsdbfb40f2017-01-23 11:05:57 -0500695 mShowA11yStream = true;
Jean-Michel Triviac487672016-11-11 10:05:18 -0800696 break;
697 default:
698 Log.e(TAG, "Invalid accessibility mode " + mode);
699 break;
700 }
Julia Reynoldsdbfb40f2017-01-23 11:05:57 -0500701 mWorker.obtainMessage(W.ACCESSIBILITY_MODE_CHANGED, mShowA11yStream).sendToTarget();
Jean-Michel Triviac487672016-11-11 10:05:18 -0800702 }
John Spurlockf88d8082015-03-25 18:09:51 -0400703 }
704
705 private final class W extends Handler {
706 private static final int VOLUME_CHANGED = 1;
707 private static final int DISMISS_REQUESTED = 2;
708 private static final int GET_STATE = 3;
709 private static final int SET_RINGER_MODE = 4;
710 private static final int SET_ZEN_MODE = 5;
711 private static final int SET_EXIT_CONDITION = 6;
712 private static final int SET_STREAM_MUTE = 7;
713 private static final int LAYOUT_DIRECTION_CHANGED = 8;
714 private static final int CONFIGURATION_CHANGED = 9;
715 private static final int SET_STREAM_VOLUME = 10;
716 private static final int SET_ACTIVE_STREAM = 11;
717 private static final int NOTIFY_VISIBLE = 12;
718 private static final int USER_ACTIVITY = 13;
John Spurlock76b52b32015-04-03 00:00:12 -0400719 private static final int SHOW_SAFETY_WARNING = 14;
Julia Reynoldsdbfb40f2017-01-23 11:05:57 -0500720 private static final int ACCESSIBILITY_MODE_CHANGED = 15;
John Spurlockf88d8082015-03-25 18:09:51 -0400721
722 W(Looper looper) {
723 super(looper);
724 }
725
726 @Override
727 public void handleMessage(Message msg) {
728 switch (msg.what) {
729 case VOLUME_CHANGED: onVolumeChangedW(msg.arg1, msg.arg2); break;
730 case DISMISS_REQUESTED: onDismissRequestedW(msg.arg1); break;
731 case GET_STATE: onGetStateW(); break;
732 case SET_RINGER_MODE: onSetRingerModeW(msg.arg1, msg.arg2 != 0); break;
733 case SET_ZEN_MODE: onSetZenModeW(msg.arg1); break;
734 case SET_EXIT_CONDITION: onSetExitConditionW((Condition) msg.obj); break;
735 case SET_STREAM_MUTE: onSetStreamMuteW(msg.arg1, msg.arg2 != 0); break;
736 case LAYOUT_DIRECTION_CHANGED: mCallbacks.onLayoutDirectionChanged(msg.arg1); break;
737 case CONFIGURATION_CHANGED: mCallbacks.onConfigurationChanged(); break;
738 case SET_STREAM_VOLUME: onSetStreamVolumeW(msg.arg1, msg.arg2); break;
739 case SET_ACTIVE_STREAM: onSetActiveStreamW(msg.arg1); break;
John Spurlock76b52b32015-04-03 00:00:12 -0400740 case NOTIFY_VISIBLE: onNotifyVisibleW(msg.arg1 != 0); break;
741 case USER_ACTIVITY: onUserActivityW(); break;
742 case SHOW_SAFETY_WARNING: onShowSafetyWarningW(msg.arg1); break;
Julia Reynoldsdbfb40f2017-01-23 11:05:57 -0500743 case ACCESSIBILITY_MODE_CHANGED: onAccessibilityModeChanged((Boolean) msg.obj);
Julia Reynolds6692b472018-01-24 07:23:56 -0500744
John Spurlockf88d8082015-03-25 18:09:51 -0400745 }
746 }
747 }
748
Beverly8ebef842017-07-12 10:58:22 -0400749 class C implements Callbacks {
John Spurlockf88d8082015-03-25 18:09:51 -0400750 private final HashMap<Callbacks, Handler> mCallbackMap = new HashMap<>();
751
752 public void add(Callbacks callback, Handler handler) {
753 if (callback == null || handler == null) throw new IllegalArgumentException();
754 mCallbackMap.put(callback, handler);
755 }
756
757 public void remove(Callbacks callback) {
758 mCallbackMap.remove(callback);
759 }
760
761 @Override
762 public void onShowRequested(final int reason) {
763 for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
764 entry.getValue().post(new Runnable() {
765 @Override
766 public void run() {
767 entry.getKey().onShowRequested(reason);
768 }
769 });
770 }
771 }
772
773 @Override
774 public void onDismissRequested(final int reason) {
775 for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
776 entry.getValue().post(new Runnable() {
777 @Override
778 public void run() {
779 entry.getKey().onDismissRequested(reason);
780 }
781 });
782 }
783 }
784
785 @Override
786 public void onStateChanged(final State state) {
787 final long time = System.currentTimeMillis();
788 final State copy = state.copy();
789 for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
790 entry.getValue().post(new Runnable() {
791 @Override
792 public void run() {
793 entry.getKey().onStateChanged(copy);
794 }
795 });
796 }
797 Events.writeState(time, copy);
798 }
799
800 @Override
801 public void onLayoutDirectionChanged(final int layoutDirection) {
802 for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
803 entry.getValue().post(new Runnable() {
804 @Override
805 public void run() {
806 entry.getKey().onLayoutDirectionChanged(layoutDirection);
807 }
808 });
809 }
810 }
811
812 @Override
813 public void onConfigurationChanged() {
814 for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
815 entry.getValue().post(new Runnable() {
816 @Override
817 public void run() {
818 entry.getKey().onConfigurationChanged();
819 }
820 });
821 }
822 }
823
824 @Override
825 public void onShowVibrateHint() {
826 for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
827 entry.getValue().post(new Runnable() {
828 @Override
829 public void run() {
830 entry.getKey().onShowVibrateHint();
831 }
832 });
833 }
834 }
835
836 @Override
837 public void onShowSilentHint() {
838 for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
839 entry.getValue().post(new Runnable() {
840 @Override
841 public void run() {
842 entry.getKey().onShowSilentHint();
843 }
844 });
845 }
846 }
847
848 @Override
849 public void onScreenOff() {
850 for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
851 entry.getValue().post(new Runnable() {
852 @Override
853 public void run() {
854 entry.getKey().onScreenOff();
855 }
856 });
857 }
858 }
John Spurlock76b52b32015-04-03 00:00:12 -0400859
860 @Override
861 public void onShowSafetyWarning(final int flags) {
862 for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
863 entry.getValue().post(new Runnable() {
864 @Override
865 public void run() {
866 entry.getKey().onShowSafetyWarning(flags);
867 }
868 });
869 }
870 }
Julia Reynoldsdbfb40f2017-01-23 11:05:57 -0500871
872 @Override
873 public void onAccessibilityModeChanged(Boolean showA11yStream) {
874 boolean show = showA11yStream == null ? false : showA11yStream;
875 for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
876 entry.getValue().post(new Runnable() {
877 @Override
878 public void run() {
879 entry.getKey().onAccessibilityModeChanged(show);
880 }
881 });
882 }
883 }
John Spurlockf88d8082015-03-25 18:09:51 -0400884 }
885
886
887 private final class SettingObserver extends ContentObserver {
John Spurlockf88d8082015-03-25 18:09:51 -0400888 private final Uri ZEN_MODE_URI =
889 Settings.Global.getUriFor(Settings.Global.ZEN_MODE);
890 private final Uri ZEN_MODE_CONFIG_URI =
891 Settings.Global.getUriFor(Settings.Global.ZEN_MODE_CONFIG_ETAG);
892
893 public SettingObserver(Handler handler) {
894 super(handler);
895 }
896
897 public void init() {
John Spurlockf88d8082015-03-25 18:09:51 -0400898 mContext.getContentResolver().registerContentObserver(ZEN_MODE_URI, false, this);
899 mContext.getContentResolver().registerContentObserver(ZEN_MODE_CONFIG_URI, false, this);
John Spurlockf88d8082015-03-25 18:09:51 -0400900 }
901
902 public void destroy() {
903 mContext.getContentResolver().unregisterContentObserver(this);
904 }
905
906 @Override
907 public void onChange(boolean selfChange, Uri uri) {
908 boolean changed = false;
John Spurlockf88d8082015-03-25 18:09:51 -0400909 if (ZEN_MODE_URI.equals(uri)) {
910 changed = updateZenModeW();
911 }
Beverly925cde82018-01-23 09:31:23 -0500912 if (ZEN_MODE_CONFIG_URI.equals(uri)) {
913 changed |= updateZenConfig();
914 }
915
John Spurlockf88d8082015-03-25 18:09:51 -0400916 if (changed) {
917 mCallbacks.onStateChanged(mState);
918 }
919 }
920 }
921
922 private final class Receiver extends BroadcastReceiver {
923
924 public void init() {
925 final IntentFilter filter = new IntentFilter();
926 filter.addAction(AudioManager.VOLUME_CHANGED_ACTION);
927 filter.addAction(AudioManager.STREAM_DEVICES_CHANGED_ACTION);
928 filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
929 filter.addAction(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION);
930 filter.addAction(AudioManager.STREAM_MUTE_CHANGED_ACTION);
931 filter.addAction(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED);
932 filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
933 filter.addAction(Intent.ACTION_SCREEN_OFF);
John Spurlockbc7233a2015-06-29 15:34:18 -0400934 filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
John Spurlockf88d8082015-03-25 18:09:51 -0400935 mContext.registerReceiver(this, filter, null, mWorker);
936 }
937
938 public void destroy() {
939 mContext.unregisterReceiver(this);
940 }
941
942 @Override
943 public void onReceive(Context context, Intent intent) {
944 final String action = intent.getAction();
945 boolean changed = false;
946 if (action.equals(AudioManager.VOLUME_CHANGED_ACTION)) {
947 final int stream = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1);
948 final int level = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, -1);
949 final int oldLevel = intent
950 .getIntExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, -1);
951 if (D.BUG) Log.d(TAG, "onReceive VOLUME_CHANGED_ACTION stream=" + stream
952 + " level=" + level + " oldLevel=" + oldLevel);
953 changed = updateStreamLevelW(stream, level);
954 } else if (action.equals(AudioManager.STREAM_DEVICES_CHANGED_ACTION)) {
955 final int stream = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1);
956 final int devices = intent
957 .getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_DEVICES, -1);
958 final int oldDevices = intent
959 .getIntExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_DEVICES, -1);
960 if (D.BUG) Log.d(TAG, "onReceive STREAM_DEVICES_CHANGED_ACTION stream="
961 + stream + " devices=" + devices + " oldDevices=" + oldDevices);
962 changed = checkRoutedToBluetoothW(stream);
Julia Reynolds8ae994f2015-09-14 11:12:42 -0400963 changed |= onVolumeChangedW(stream, 0);
John Spurlockf88d8082015-03-25 18:09:51 -0400964 } else if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) {
965 final int rm = intent.getIntExtra(AudioManager.EXTRA_RINGER_MODE, -1);
Alastair Breeze1d421652018-10-16 19:17:07 +0100966 if (isInitialStickyBroadcast()) mState.ringerModeExternal = rm;
John Spurlockf88d8082015-03-25 18:09:51 -0400967 if (D.BUG) Log.d(TAG, "onReceive RINGER_MODE_CHANGED_ACTION rm="
968 + Util.ringerModeToString(rm));
969 changed = updateRingerModeExternalW(rm);
970 } else if (action.equals(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION)) {
971 final int rm = intent.getIntExtra(AudioManager.EXTRA_RINGER_MODE, -1);
Alastair Breeze1d421652018-10-16 19:17:07 +0100972 if (isInitialStickyBroadcast()) mState.ringerModeInternal = rm;
John Spurlockf88d8082015-03-25 18:09:51 -0400973 if (D.BUG) Log.d(TAG, "onReceive INTERNAL_RINGER_MODE_CHANGED_ACTION rm="
974 + Util.ringerModeToString(rm));
975 changed = updateRingerModeInternalW(rm);
976 } else if (action.equals(AudioManager.STREAM_MUTE_CHANGED_ACTION)) {
977 final int stream = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1);
978 final boolean muted = intent
979 .getBooleanExtra(AudioManager.EXTRA_STREAM_VOLUME_MUTED, false);
980 if (D.BUG) Log.d(TAG, "onReceive STREAM_MUTE_CHANGED_ACTION stream=" + stream
981 + " muted=" + muted);
982 changed = updateStreamMuteW(stream, muted);
983 } else if (action.equals(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED)) {
984 if (D.BUG) Log.d(TAG, "onReceive ACTION_EFFECTS_SUPPRESSOR_CHANGED");
985 changed = updateEffectsSuppressorW(mNoMan.getEffectsSuppressor());
986 } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
987 if (D.BUG) Log.d(TAG, "onReceive ACTION_CONFIGURATION_CHANGED");
988 mCallbacks.onConfigurationChanged();
989 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
990 if (D.BUG) Log.d(TAG, "onReceive ACTION_SCREEN_OFF");
991 mCallbacks.onScreenOff();
John Spurlockbc7233a2015-06-29 15:34:18 -0400992 } else if (action.equals(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) {
993 if (D.BUG) Log.d(TAG, "onReceive ACTION_CLOSE_SYSTEM_DIALOGS");
994 dismiss();
John Spurlockf88d8082015-03-25 18:09:51 -0400995 }
996 if (changed) {
997 mCallbacks.onStateChanged(mState);
998 }
999 }
1000 }
1001
Beverly4e936612017-07-28 14:05:30 -04001002 protected final class MediaSessionsCallbacks implements MediaSessions.Callbacks {
John Spurlockf88d8082015-03-25 18:09:51 -04001003 private final HashMap<Token, Integer> mRemoteStreams = new HashMap<>();
1004
1005 private int mNextStream = DYNAMIC_STREAM_START_INDEX;
1006
1007 @Override
1008 public void onRemoteUpdate(Token token, String name, PlaybackInfo pi) {
Beverlyb5a27812017-07-24 11:34:48 -04001009 addStream(token, "onRemoteUpdate");
John Spurlockf88d8082015-03-25 18:09:51 -04001010 final int stream = mRemoteStreams.get(token);
1011 boolean changed = mState.states.indexOfKey(stream) < 0;
1012 final StreamState ss = streamStateW(stream);
1013 ss.dynamic = true;
1014 ss.levelMin = 0;
1015 ss.levelMax = pi.getMaxVolume();
1016 if (ss.level != pi.getCurrentVolume()) {
1017 ss.level = pi.getCurrentVolume();
1018 changed = true;
1019 }
Julia Reynolds03c548f2016-12-14 15:02:38 -05001020 if (!Objects.equals(ss.remoteLabel, name)) {
1021 ss.name = -1;
1022 ss.remoteLabel = name;
John Spurlockf88d8082015-03-25 18:09:51 -04001023 changed = true;
1024 }
1025 if (changed) {
1026 if (D.BUG) Log.d(TAG, "onRemoteUpdate: " + name + ": " + ss.level
1027 + " of " + ss.levelMax);
1028 mCallbacks.onStateChanged(mState);
1029 }
1030 }
1031
1032 @Override
1033 public void onRemoteVolumeChanged(Token token, int flags) {
Beverlyb5a27812017-07-24 11:34:48 -04001034 addStream(token, "onRemoteVolumeChanged");
John Spurlockf88d8082015-03-25 18:09:51 -04001035 final int stream = mRemoteStreams.get(token);
Beverly85e05eb2017-07-21 14:49:27 -04001036 final boolean showUI = shouldShowUI(flags);
John Spurlockf88d8082015-03-25 18:09:51 -04001037 boolean changed = updateActiveStreamW(stream);
1038 if (showUI) {
1039 changed |= checkRoutedToBluetoothW(AudioManager.STREAM_MUSIC);
1040 }
1041 if (changed) {
1042 mCallbacks.onStateChanged(mState);
1043 }
1044 if (showUI) {
1045 mCallbacks.onShowRequested(Events.SHOW_REASON_REMOTE_VOLUME_CHANGED);
1046 }
1047 }
1048
1049 @Override
1050 public void onRemoteRemoved(Token token) {
Beverlyb5a27812017-07-24 11:34:48 -04001051 if (!mRemoteStreams.containsKey(token)) {
1052 if (D.BUG) Log.d(TAG, "onRemoteRemoved: stream doesn't exist, "
1053 + "aborting remote removed for token:" + token.toString());
1054 return;
1055 }
John Spurlockf88d8082015-03-25 18:09:51 -04001056 final int stream = mRemoteStreams.get(token);
1057 mState.states.remove(stream);
1058 if (mState.activeStream == stream) {
1059 updateActiveStreamW(-1);
1060 }
1061 mCallbacks.onStateChanged(mState);
1062 }
1063
1064 public void setStreamVolume(int stream, int level) {
1065 final Token t = findToken(stream);
1066 if (t == null) {
1067 Log.w(TAG, "setStreamVolume: No token found for stream: " + stream);
1068 return;
1069 }
1070 mMediaSessions.setVolume(t, level);
1071 }
1072
1073 private Token findToken(int stream) {
1074 for (Map.Entry<Token, Integer> entry : mRemoteStreams.entrySet()) {
1075 if (entry.getValue().equals(stream)) {
1076 return entry.getKey();
1077 }
1078 }
1079 return null;
1080 }
Beverlyb5a27812017-07-24 11:34:48 -04001081
1082 private void addStream(Token token, String triggeringMethod) {
1083 if (!mRemoteStreams.containsKey(token)) {
1084 mRemoteStreams.put(token, mNextStream);
1085 if (D.BUG) Log.d(TAG, triggeringMethod + ": added stream " + mNextStream
1086 + " from token + "+ token.toString());
1087 mNextStream++;
1088 }
1089 }
John Spurlockf88d8082015-03-25 18:09:51 -04001090 }
1091
Yao Chen634acb92016-04-13 16:17:47 -07001092 public interface UserActivityListener {
1093 void onUserActivity();
1094 }
John Spurlockf88d8082015-03-25 18:09:51 -04001095}