blob: 32bc01cdfdfee011fba0908f822ca097e4a395ae [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;
Jason Monk782cd672017-03-22 12:50:57 -040056import com.android.systemui.Dumpable;
John Spurlockf88d8082015-03-25 18:09:51 -040057import com.android.systemui.R;
Beverly8ebef842017-07-12 10:58:22 -040058import com.android.systemui.SysUiServiceProvider;
Beverly85e05eb2017-07-21 14:49:27 -040059import com.android.systemui.keyguard.WakefulnessLifecycle;
Jason Monk782cd672017-03-22 12:50:57 -040060import com.android.systemui.plugins.VolumeDialogController;
John Spurlockcd863ad2015-04-07 14:01:28 -040061import com.android.systemui.qs.tiles.DndTile;
Beverly8ebef842017-07-12 10:58:22 -040062import com.android.systemui.statusbar.phone.StatusBar;
John Spurlockf88d8082015-03-25 18:09:51 -040063
64import java.io.FileDescriptor;
65import java.io.PrintWriter;
66import java.util.HashMap;
67import java.util.Map;
68import java.util.Objects;
69
Jason Monk196d6392018-12-20 13:25:34 -050070import javax.inject.Inject;
71import javax.inject.Singleton;
72
John Spurlockf88d8082015-03-25 18:09:51 -040073/**
74 * Source of truth for all state / events related to the volume dialog. No presentation.
75 *
76 * All work done on a dedicated background worker thread & associated worker.
77 *
78 * Methods ending in "W" must be called on the worker thread.
79 */
Jason Monk196d6392018-12-20 13:25:34 -050080@Singleton
Jason Monk782cd672017-03-22 12:50:57 -040081public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpable {
82 private static final String TAG = Util.logTag(VolumeDialogControllerImpl.class);
John Spurlockf88d8082015-03-25 18:09:51 -040083
Julia Reynoldsac55e012018-03-27 11:17:30 -040084
85 private static final int TOUCH_FEEDBACK_TIMEOUT_MS = 1000;
John Spurlockf88d8082015-03-25 18:09:51 -040086 private static final int DYNAMIC_STREAM_START_INDEX = 100;
87 private static final int VIBRATE_HINT_DURATION = 50;
Julia Reynoldsac55e012018-03-27 11:17:30 -040088 private static final AudioAttributes SONIFICIATION_VIBRATION_ATTRIBUTES =
Beverly512077e2018-03-15 13:54:43 -040089 new AudioAttributes.Builder()
90 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
91 .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
92 .build();
John Spurlockf88d8082015-03-25 18:09:51 -040093
Julia Reynolds561d3f42018-01-26 11:31:02 -050094 static final ArrayMap<Integer, Integer> STREAMS = new ArrayMap<>();
Julia Reynolds03c548f2016-12-14 15:02:38 -050095 static {
96 STREAMS.put(AudioSystem.STREAM_ALARM, R.string.stream_alarm);
97 STREAMS.put(AudioSystem.STREAM_BLUETOOTH_SCO, R.string.stream_bluetooth_sco);
98 STREAMS.put(AudioSystem.STREAM_DTMF, R.string.stream_dtmf);
99 STREAMS.put(AudioSystem.STREAM_MUSIC, R.string.stream_music);
Julia Reynoldsdbfb40f2017-01-23 11:05:57 -0500100 STREAMS.put(AudioSystem.STREAM_ACCESSIBILITY, R.string.stream_accessibility);
Julia Reynolds03c548f2016-12-14 15:02:38 -0500101 STREAMS.put(AudioSystem.STREAM_NOTIFICATION, R.string.stream_notification);
102 STREAMS.put(AudioSystem.STREAM_RING, R.string.stream_ring);
103 STREAMS.put(AudioSystem.STREAM_SYSTEM, R.string.stream_system);
104 STREAMS.put(AudioSystem.STREAM_SYSTEM_ENFORCED, R.string.stream_system_enforced);
105 STREAMS.put(AudioSystem.STREAM_TTS, R.string.stream_tts);
106 STREAMS.put(AudioSystem.STREAM_VOICE_CALL, R.string.stream_voice_call);
Julia Reynolds03c548f2016-12-14 15:02:38 -0500107 }
John Spurlockf88d8082015-03-25 18:09:51 -0400108
109 private final HandlerThread mWorkerThread;
110 private final W mWorker;
111 private final Context mContext;
Yao Chen634acb92016-04-13 16:17:47 -0700112 private AudioManager mAudio;
Julia Reynoldsac55e012018-03-27 11:17:30 -0400113 private IAudioService mAudioService;
Beverly8ebef842017-07-12 10:58:22 -0400114 protected StatusBar mStatusBar;
John Spurlockf88d8082015-03-25 18:09:51 -0400115 private final NotificationManager mNoMan;
John Spurlockf88d8082015-03-25 18:09:51 -0400116 private final SettingObserver mObserver;
117 private final Receiver mReceiver = new Receiver();
118 private final MediaSessions mMediaSessions;
Beverly8ebef842017-07-12 10:58:22 -0400119 protected C mCallbacks = new C();
John Spurlockf88d8082015-03-25 18:09:51 -0400120 private final State mState = new State();
Beverly4e936612017-07-28 14:05:30 -0400121 protected final MediaSessionsCallbacks mMediaSessionsCallbacksW = new MediaSessionsCallbacks();
John Spurlockf88d8082015-03-25 18:09:51 -0400122 private final Vibrator mVibrator;
123 private final boolean mHasVibrator;
Julia Reynoldsdbfb40f2017-01-23 11:05:57 -0500124 private boolean mShowA11yStream;
Luke Songe0036662017-12-12 12:27:08 -0800125 private boolean mShowVolumeDialog;
126 private boolean mShowSafetyWarning;
Julia Reynoldsac55e012018-03-27 11:17:30 -0400127 private long mLastToggledRingerOn;
Beverly925cde82018-01-23 09:31:23 -0500128 private final NotificationManager mNotificationManager;
John Spurlockf88d8082015-03-25 18:09:51 -0400129
John Spurlockf88d8082015-03-25 18:09:51 -0400130 private boolean mDestroyed;
John Spurlockb02c7442015-04-14 09:32:25 -0400131 private VolumePolicy mVolumePolicy;
John Spurlockd9c75db2015-04-28 11:19:13 -0400132 private boolean mShowDndTile = true;
Yao Chen634acb92016-04-13 16:17:47 -0700133 @GuardedBy("this")
134 private UserActivityListener mUserActivityListener;
135
136 protected final VC mVolumeController = new VC();
John Spurlockf88d8082015-03-25 18:09:51 -0400137
Jason Monk196d6392018-12-20 13:25:34 -0500138 @Inject
Jason Monk782cd672017-03-22 12:50:57 -0400139 public VolumeDialogControllerImpl(Context context) {
John Spurlockf88d8082015-03-25 18:09:51 -0400140 mContext = context.getApplicationContext();
Beverly925cde82018-01-23 09:31:23 -0500141 mNotificationManager = (NotificationManager) mContext.getSystemService(
142 Context.NOTIFICATION_SERVICE);
Chris Wrene565ee62015-06-17 15:24:56 -0400143 Events.writeEvent(mContext, Events.EVENT_COLLECTION_STARTED);
Jason Monk782cd672017-03-22 12:50:57 -0400144 mWorkerThread = new HandlerThread(VolumeDialogControllerImpl.class.getSimpleName());
John Spurlockf88d8082015-03-25 18:09:51 -0400145 mWorkerThread.start();
146 mWorker = new W(mWorkerThread.getLooper());
147 mMediaSessions = createMediaSessions(mContext, mWorkerThread.getLooper(),
148 mMediaSessionsCallbacksW);
149 mAudio = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
150 mNoMan = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
151 mObserver = new SettingObserver(mWorker);
152 mObserver.init();
153 mReceiver.init();
John Spurlockf88d8082015-03-25 18:09:51 -0400154 mVibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
155 mHasVibrator = mVibrator != null && mVibrator.hasVibrator();
Julia Reynoldsac55e012018-03-27 11:17:30 -0400156 mAudioService = IAudioService.Stub.asInterface(
157 ServiceManager.getService(Context.AUDIO_SERVICE));
Beverly8ebef842017-07-12 10:58:22 -0400158 updateStatusBar();
Jason Monkae305972017-06-27 14:46:03 -0400159
160 boolean accessibilityVolumeStreamActive = context.getSystemService(
161 AccessibilityManager.class).isAccessibilityVolumeStreamActive();
162 mVolumeController.setA11yMode(accessibilityVolumeStreamActive ?
163 VolumePolicy.A11Y_MODE_INDEPENDENT_A11Y_VOLUME :
164 VolumePolicy.A11Y_MODE_MEDIA_A11Y_VOLUME);
John Spurlockf88d8082015-03-25 18:09:51 -0400165 }
166
John Spurlock76b52b32015-04-03 00:00:12 -0400167 public AudioManager getAudioManager() {
168 return mAudio;
169 }
170
John Spurlockf88d8082015-03-25 18:09:51 -0400171 public void dismiss() {
172 mCallbacks.onDismissRequested(Events.DISMISS_REASON_VOLUME_CONTROLLER);
173 }
174
Yao Chen634acb92016-04-13 16:17:47 -0700175 protected void setVolumeController() {
John Spurlockf88d8082015-03-25 18:09:51 -0400176 try {
177 mAudio.setVolumeController(mVolumeController);
178 } catch (SecurityException e) {
179 Log.w(TAG, "Unable to set the volume controller", e);
180 return;
181 }
Yao Chen634acb92016-04-13 16:17:47 -0700182 }
183
184 protected void setAudioManagerStreamVolume(int stream, int level, int flag) {
185 mAudio.setStreamVolume(stream, level, flag);
186 }
187
188 protected int getAudioManagerStreamVolume(int stream) {
189 return mAudio.getLastAudibleStreamVolume(stream);
190 }
191
192 protected int getAudioManagerStreamMaxVolume(int stream) {
193 return mAudio.getStreamMaxVolume(stream);
194 }
195
196 protected int getAudioManagerStreamMinVolume(int stream) {
Jean-Michel Trivi8e7aca32017-11-28 18:12:38 -0800197 return mAudio.getStreamMinVolumeInt(stream);
Yao Chen634acb92016-04-13 16:17:47 -0700198 }
199
200 public void register() {
201 setVolumeController();
John Spurlockf88d8082015-03-25 18:09:51 -0400202 setVolumePolicy(mVolumePolicy);
203 showDndTile(mShowDndTile);
204 try {
205 mMediaSessions.init();
206 } catch (SecurityException e) {
207 Log.w(TAG, "No access to media sessions", e);
208 }
209 }
210
211 public void setVolumePolicy(VolumePolicy policy) {
212 mVolumePolicy = policy;
John Spurlockb02c7442015-04-14 09:32:25 -0400213 if (mVolumePolicy == null) return;
John Spurlockf88d8082015-03-25 18:09:51 -0400214 try {
215 mAudio.setVolumePolicy(mVolumePolicy);
216 } catch (NoSuchMethodError e) {
217 Log.w(TAG, "No volume policy api");
218 }
219 }
220
221 protected MediaSessions createMediaSessions(Context context, Looper looper,
222 MediaSessions.Callbacks callbacks) {
223 return new MediaSessions(context, looper, callbacks);
224 }
225
226 public void destroy() {
227 if (D.BUG) Log.d(TAG, "destroy");
228 if (mDestroyed) return;
229 mDestroyed = true;
Chris Wrene565ee62015-06-17 15:24:56 -0400230 Events.writeEvent(mContext, Events.EVENT_COLLECTION_STOPPED);
John Spurlockf88d8082015-03-25 18:09:51 -0400231 mMediaSessions.destroy();
232 mObserver.destroy();
233 mReceiver.destroy();
234 mWorkerThread.quitSafely();
235 }
236
237 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jason Monk782cd672017-03-22 12:50:57 -0400238 pw.println(VolumeDialogControllerImpl.class.getSimpleName() + " state:");
John Spurlockf88d8082015-03-25 18:09:51 -0400239 pw.print(" mDestroyed: "); pw.println(mDestroyed);
240 pw.print(" mVolumePolicy: "); pw.println(mVolumePolicy);
John Spurlocke56efa712015-05-19 12:26:25 -0400241 pw.print(" mState: "); pw.println(mState.toString(4));
John Spurlockf88d8082015-03-25 18:09:51 -0400242 pw.print(" mShowDndTile: "); pw.println(mShowDndTile);
243 pw.print(" mHasVibrator: "); pw.println(mHasVibrator);
244 pw.print(" mRemoteStreams: "); pw.println(mMediaSessionsCallbacksW.mRemoteStreams
245 .values());
Julia Reynoldsdbfb40f2017-01-23 11:05:57 -0500246 pw.print(" mShowA11yStream: "); pw.println(mShowA11yStream);
John Spurlockf88d8082015-03-25 18:09:51 -0400247 pw.println();
248 mMediaSessions.dump(pw);
249 }
250
251 public void addCallback(Callbacks callback, Handler handler) {
252 mCallbacks.add(callback, handler);
Jason Monkae305972017-06-27 14:46:03 -0400253 callback.onAccessibilityModeChanged(mShowA11yStream);
John Spurlockf88d8082015-03-25 18:09:51 -0400254 }
255
Yao Chen634acb92016-04-13 16:17:47 -0700256 public void setUserActivityListener(UserActivityListener listener) {
257 if (mDestroyed) return;
258 synchronized (this) {
259 mUserActivityListener = listener;
260 }
261 }
262
John Spurlockf88d8082015-03-25 18:09:51 -0400263 public void removeCallback(Callbacks callback) {
264 mCallbacks.remove(callback);
265 }
266
267 public void getState() {
268 if (mDestroyed) return;
269 mWorker.sendEmptyMessage(W.GET_STATE);
270 }
271
272 public void notifyVisible(boolean visible) {
273 if (mDestroyed) return;
274 mWorker.obtainMessage(W.NOTIFY_VISIBLE, visible ? 1 : 0, 0).sendToTarget();
275 }
276
277 public void userActivity() {
278 if (mDestroyed) return;
279 mWorker.removeMessages(W.USER_ACTIVITY);
280 mWorker.sendEmptyMessage(W.USER_ACTIVITY);
281 }
282
283 public void setRingerMode(int value, boolean external) {
284 if (mDestroyed) return;
285 mWorker.obtainMessage(W.SET_RINGER_MODE, value, external ? 1 : 0).sendToTarget();
286 }
287
288 public void setZenMode(int value) {
289 if (mDestroyed) return;
290 mWorker.obtainMessage(W.SET_ZEN_MODE, value, 0).sendToTarget();
291 }
292
293 public void setExitCondition(Condition condition) {
294 if (mDestroyed) return;
295 mWorker.obtainMessage(W.SET_EXIT_CONDITION, condition).sendToTarget();
296 }
297
298 public void setStreamMute(int stream, boolean mute) {
299 if (mDestroyed) return;
300 mWorker.obtainMessage(W.SET_STREAM_MUTE, stream, mute ? 1 : 0).sendToTarget();
301 }
302
303 public void setStreamVolume(int stream, int level) {
304 if (mDestroyed) return;
305 mWorker.obtainMessage(W.SET_STREAM_VOLUME, stream, level).sendToTarget();
306 }
307
308 public void setActiveStream(int stream) {
309 if (mDestroyed) return;
310 mWorker.obtainMessage(W.SET_ACTIVE_STREAM, stream, 0).sendToTarget();
311 }
312
Luke Songe0036662017-12-12 12:27:08 -0800313 public void setEnableDialogs(boolean volumeUi, boolean safetyWarning) {
314 mShowVolumeDialog = volumeUi;
315 mShowSafetyWarning = safetyWarning;
316 }
317
Julia Reynoldsac55e012018-03-27 11:17:30 -0400318 @Override
319 public void scheduleTouchFeedback() {
320 mLastToggledRingerOn = System.currentTimeMillis();
321 }
322
323 private void playTouchFeedback() {
324 if (System.currentTimeMillis() - mLastToggledRingerOn < TOUCH_FEEDBACK_TIMEOUT_MS) {
325 try {
326 mAudioService.playSoundEffect(AudioManager.FX_KEYPRESS_STANDARD);
327 } catch (RemoteException e) {
328 // ignore
329 }
330 }
331 }
332
333 public void vibrate(VibrationEffect effect) {
John Spurlockf88d8082015-03-25 18:09:51 -0400334 if (mHasVibrator) {
Julia Reynoldsac55e012018-03-27 11:17:30 -0400335 mVibrator.vibrate(effect, SONIFICIATION_VIBRATION_ATTRIBUTES);
John Spurlockf88d8082015-03-25 18:09:51 -0400336 }
337 }
338
339 public boolean hasVibrator() {
340 return mHasVibrator;
341 }
342
343 private void onNotifyVisibleW(boolean visible) {
Beverly512077e2018-03-15 13:54:43 -0400344 if (mDestroyed) return;
John Spurlockf88d8082015-03-25 18:09:51 -0400345 mAudio.notifyVolumeControllerVisible(mVolumeController, visible);
346 if (!visible) {
347 if (updateActiveStreamW(-1)) {
348 mCallbacks.onStateChanged(mState);
349 }
350 }
351 }
352
Yao Chen634acb92016-04-13 16:17:47 -0700353 private void onUserActivityW() {
354 synchronized (this) {
355 if (mUserActivityListener != null) {
356 mUserActivityListener.onUserActivity();
357 }
358 }
John Spurlockf88d8082015-03-25 18:09:51 -0400359 }
360
John Spurlock76b52b32015-04-03 00:00:12 -0400361 private void onShowSafetyWarningW(int flags) {
Luke Songe0036662017-12-12 12:27:08 -0800362 if (mShowSafetyWarning) {
363 mCallbacks.onShowSafetyWarning(flags);
364 }
John Spurlock76b52b32015-04-03 00:00:12 -0400365 }
366
Julia Reynoldsdbfb40f2017-01-23 11:05:57 -0500367 private void onAccessibilityModeChanged(Boolean showA11yStream) {
368 mCallbacks.onAccessibilityModeChanged(showA11yStream);
369 }
370
John Spurlockf88d8082015-03-25 18:09:51 -0400371 private boolean checkRoutedToBluetoothW(int stream) {
372 boolean changed = false;
373 if (stream == AudioManager.STREAM_MUSIC) {
374 final boolean routedToBluetooth =
375 (mAudio.getDevicesForStream(AudioManager.STREAM_MUSIC) &
376 (AudioManager.DEVICE_OUT_BLUETOOTH_A2DP |
377 AudioManager.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
378 AudioManager.DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER)) != 0;
379 changed |= updateStreamRoutedToBluetoothW(stream, routedToBluetooth);
380 }
381 return changed;
382 }
383
Beverly8ebef842017-07-12 10:58:22 -0400384 private void updateStatusBar() {
385 if (mStatusBar == null) {
386 mStatusBar = SysUiServiceProvider.getComponent(mContext, StatusBar.class);
387 }
388 }
389
Beverly85e05eb2017-07-21 14:49:27 -0400390 private boolean shouldShowUI(int flags) {
Beverly8ebef842017-07-12 10:58:22 -0400391 updateStatusBar();
Beverlya2f682f2018-02-01 11:29:25 -0500392 // if status bar isn't null, check if phone is in AOD, else check flags
393 // since we could be using a different status bar
394 return mStatusBar != null ?
395 mStatusBar.getWakefulnessState() != WakefulnessLifecycle.WAKEFULNESS_ASLEEP
396 && mStatusBar.getWakefulnessState() !=
397 WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP
Beverly85e05eb2017-07-21 14:49:27 -0400398 && mStatusBar.isDeviceInteractive()
Beverlya2f682f2018-02-01 11:29:25 -0500399 && (flags & AudioManager.FLAG_SHOW_UI) != 0 && mShowVolumeDialog
400 : mShowVolumeDialog && (flags & AudioManager.FLAG_SHOW_UI) != 0;
Beverly85e05eb2017-07-21 14:49:27 -0400401 }
Beverly8ebef842017-07-12 10:58:22 -0400402
Beverly85e05eb2017-07-21 14:49:27 -0400403 boolean onVolumeChangedW(int stream, int flags) {
404 final boolean showUI = shouldShowUI(flags);
John Spurlockf88d8082015-03-25 18:09:51 -0400405 final boolean fromKey = (flags & AudioManager.FLAG_FROM_KEY) != 0;
406 final boolean showVibrateHint = (flags & AudioManager.FLAG_SHOW_VIBRATE_HINT) != 0;
407 final boolean showSilentHint = (flags & AudioManager.FLAG_SHOW_SILENT_HINT) != 0;
408 boolean changed = false;
409 if (showUI) {
410 changed |= updateActiveStreamW(stream);
411 }
Yao Chen634acb92016-04-13 16:17:47 -0700412 int lastAudibleStreamVolume = getAudioManagerStreamVolume(stream);
Chris Wrene565ee62015-06-17 15:24:56 -0400413 changed |= updateStreamLevelW(stream, lastAudibleStreamVolume);
John Spurlockf88d8082015-03-25 18:09:51 -0400414 changed |= checkRoutedToBluetoothW(showUI ? AudioManager.STREAM_MUSIC : stream);
415 if (changed) {
416 mCallbacks.onStateChanged(mState);
417 }
418 if (showUI) {
419 mCallbacks.onShowRequested(Events.SHOW_REASON_VOLUME_CHANGED);
420 }
421 if (showVibrateHint) {
422 mCallbacks.onShowVibrateHint();
423 }
424 if (showSilentHint) {
425 mCallbacks.onShowSilentHint();
426 }
427 if (changed && fromKey) {
Chris Wrene565ee62015-06-17 15:24:56 -0400428 Events.writeEvent(mContext, Events.EVENT_KEY, stream, lastAudibleStreamVolume);
John Spurlockf88d8082015-03-25 18:09:51 -0400429 }
Julia Reynolds8ae994f2015-09-14 11:12:42 -0400430 return changed;
John Spurlockf88d8082015-03-25 18:09:51 -0400431 }
432
433 private boolean updateActiveStreamW(int activeStream) {
434 if (activeStream == mState.activeStream) return false;
435 mState.activeStream = activeStream;
Chris Wrene565ee62015-06-17 15:24:56 -0400436 Events.writeEvent(mContext, Events.EVENT_ACTIVE_STREAM_CHANGED, activeStream);
John Spurlockf88d8082015-03-25 18:09:51 -0400437 if (D.BUG) Log.d(TAG, "updateActiveStreamW " + activeStream);
438 final int s = activeStream < DYNAMIC_STREAM_START_INDEX ? activeStream : -1;
439 if (D.BUG) Log.d(TAG, "forceVolumeControlStream " + s);
440 mAudio.forceVolumeControlStream(s);
441 return true;
442 }
443
444 private StreamState streamStateW(int stream) {
445 StreamState ss = mState.states.get(stream);
446 if (ss == null) {
447 ss = new StreamState();
448 mState.states.put(stream, ss);
449 }
450 return ss;
451 }
452
453 private void onGetStateW() {
Julia Reynolds03c548f2016-12-14 15:02:38 -0500454 for (int stream : STREAMS.keySet()) {
Yao Chen634acb92016-04-13 16:17:47 -0700455 updateStreamLevelW(stream, getAudioManagerStreamVolume(stream));
456 streamStateW(stream).levelMin = getAudioManagerStreamMinVolume(stream);
Julia Reynoldsac55e012018-03-27 11:17:30 -0400457 streamStateW(stream).levelMax = Math.max(1, getAudioManagerStreamMaxVolume(stream));
John Spurlockf88d8082015-03-25 18:09:51 -0400458 updateStreamMuteW(stream, mAudio.isStreamMute(stream));
459 final StreamState ss = streamStateW(stream);
460 ss.muteSupported = mAudio.isStreamAffectedByMute(stream);
Julia Reynolds03c548f2016-12-14 15:02:38 -0500461 ss.name = STREAMS.get(stream);
John Spurlockf88d8082015-03-25 18:09:51 -0400462 checkRoutedToBluetoothW(stream);
463 }
464 updateRingerModeExternalW(mAudio.getRingerMode());
465 updateZenModeW();
Beverly925cde82018-01-23 09:31:23 -0500466 updateZenConfig();
John Spurlockf88d8082015-03-25 18:09:51 -0400467 updateEffectsSuppressorW(mNoMan.getEffectsSuppressor());
John Spurlockf88d8082015-03-25 18:09:51 -0400468 mCallbacks.onStateChanged(mState);
469 }
470
471 private boolean updateStreamRoutedToBluetoothW(int stream, boolean routedToBluetooth) {
472 final StreamState ss = streamStateW(stream);
473 if (ss.routedToBluetooth == routedToBluetooth) return false;
474 ss.routedToBluetooth = routedToBluetooth;
475 if (D.BUG) Log.d(TAG, "updateStreamRoutedToBluetoothW stream=" + stream
476 + " routedToBluetooth=" + routedToBluetooth);
477 return true;
478 }
479
480 private boolean updateStreamLevelW(int stream, int level) {
481 final StreamState ss = streamStateW(stream);
482 if (ss.level == level) return false;
483 ss.level = level;
484 if (isLogWorthy(stream)) {
Chris Wrene565ee62015-06-17 15:24:56 -0400485 Events.writeEvent(mContext, Events.EVENT_LEVEL_CHANGED, stream, level);
John Spurlockf88d8082015-03-25 18:09:51 -0400486 }
487 return true;
488 }
489
490 private static boolean isLogWorthy(int stream) {
491 switch (stream) {
492 case AudioSystem.STREAM_ALARM:
493 case AudioSystem.STREAM_BLUETOOTH_SCO:
494 case AudioSystem.STREAM_MUSIC:
495 case AudioSystem.STREAM_RING:
496 case AudioSystem.STREAM_SYSTEM:
497 case AudioSystem.STREAM_VOICE_CALL:
498 return true;
499 }
500 return false;
501 }
502
503 private boolean updateStreamMuteW(int stream, boolean muted) {
504 final StreamState ss = streamStateW(stream);
505 if (ss.muted == muted) return false;
506 ss.muted = muted;
507 if (isLogWorthy(stream)) {
Chris Wrene565ee62015-06-17 15:24:56 -0400508 Events.writeEvent(mContext, Events.EVENT_MUTE_CHANGED, stream, muted);
John Spurlockf88d8082015-03-25 18:09:51 -0400509 }
510 if (muted && isRinger(stream)) {
511 updateRingerModeInternalW(mAudio.getRingerModeInternal());
512 }
513 return true;
514 }
515
516 private static boolean isRinger(int stream) {
517 return stream == AudioManager.STREAM_RING || stream == AudioManager.STREAM_NOTIFICATION;
518 }
519
John Spurlockf88d8082015-03-25 18:09:51 -0400520 private boolean updateEffectsSuppressorW(ComponentName effectsSuppressor) {
521 if (Objects.equals(mState.effectsSuppressor, effectsSuppressor)) return false;
522 mState.effectsSuppressor = effectsSuppressor;
523 mState.effectsSuppressorName = getApplicationName(mContext, mState.effectsSuppressor);
Chris Wrene565ee62015-06-17 15:24:56 -0400524 Events.writeEvent(mContext, Events.EVENT_SUPPRESSOR_CHANGED, mState.effectsSuppressor,
John Spurlockf88d8082015-03-25 18:09:51 -0400525 mState.effectsSuppressorName);
526 return true;
527 }
528
529 private static String getApplicationName(Context context, ComponentName component) {
530 if (component == null) return null;
531 final PackageManager pm = context.getPackageManager();
532 final String pkg = component.getPackageName();
533 try {
534 final ApplicationInfo ai = pm.getApplicationInfo(pkg, 0);
535 final String rt = Objects.toString(ai.loadLabel(pm), "").trim();
536 if (rt.length() > 0) {
537 return rt;
538 }
539 } catch (NameNotFoundException e) {}
540 return pkg;
541 }
542
543 private boolean updateZenModeW() {
544 final int zen = Settings.Global.getInt(mContext.getContentResolver(),
545 Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
546 if (mState.zenMode == zen) return false;
547 mState.zenMode = zen;
Chris Wrene565ee62015-06-17 15:24:56 -0400548 Events.writeEvent(mContext, Events.EVENT_ZEN_MODE_CHANGED, zen);
John Spurlockf88d8082015-03-25 18:09:51 -0400549 return true;
550 }
551
Beverly925cde82018-01-23 09:31:23 -0500552 private boolean updateZenConfig() {
Beverly12196702018-12-12 15:05:51 -0500553 final NotificationManager.Policy policy =
554 mNotificationManager.getConsolidatedNotificationPolicy();
Beverly925cde82018-01-23 09:31:23 -0500555 boolean disallowAlarms = (policy.priorityCategories & NotificationManager.Policy
556 .PRIORITY_CATEGORY_ALARMS) == 0;
557 boolean disallowMedia = (policy.priorityCategories & NotificationManager.Policy
Beverlyd6964762018-02-16 14:07:03 -0500558 .PRIORITY_CATEGORY_MEDIA) == 0;
559 boolean disallowSystem = (policy.priorityCategories & NotificationManager.Policy
560 .PRIORITY_CATEGORY_SYSTEM) == 0;
Beverly925cde82018-01-23 09:31:23 -0500561 boolean disallowRinger = ZenModeConfig.areAllPriorityOnlyNotificationZenSoundsMuted(policy);
Beverlyd6964762018-02-16 14:07:03 -0500562 if (mState.disallowAlarms == disallowAlarms
563 && mState.disallowMedia == disallowMedia
564 && mState.disallowRinger == disallowRinger
565 && mState.disallowSystem == disallowSystem) {
Beverly925cde82018-01-23 09:31:23 -0500566 return false;
567 }
568 mState.disallowAlarms = disallowAlarms;
569 mState.disallowMedia = disallowMedia;
Beverlyd6964762018-02-16 14:07:03 -0500570 mState.disallowSystem = disallowSystem;
Beverly925cde82018-01-23 09:31:23 -0500571 mState.disallowRinger = disallowRinger;
572 Events.writeEvent(mContext, Events.EVENT_ZEN_CONFIG_CHANGED, "disallowAlarms=" +
Beverlyd6964762018-02-16 14:07:03 -0500573 disallowAlarms + " disallowMedia=" + disallowMedia + " disallowSystem=" +
574 disallowSystem + " disallowRinger=" + disallowRinger);
Beverly925cde82018-01-23 09:31:23 -0500575 return true;
576 }
577
John Spurlockf88d8082015-03-25 18:09:51 -0400578 private boolean updateRingerModeExternalW(int rm) {
579 if (rm == mState.ringerModeExternal) return false;
580 mState.ringerModeExternal = rm;
Chris Wrene565ee62015-06-17 15:24:56 -0400581 Events.writeEvent(mContext, Events.EVENT_EXTERNAL_RINGER_MODE_CHANGED, rm);
John Spurlockf88d8082015-03-25 18:09:51 -0400582 return true;
583 }
584
585 private boolean updateRingerModeInternalW(int rm) {
586 if (rm == mState.ringerModeInternal) return false;
587 mState.ringerModeInternal = rm;
Chris Wrene565ee62015-06-17 15:24:56 -0400588 Events.writeEvent(mContext, Events.EVENT_INTERNAL_RINGER_MODE_CHANGED, rm);
Julia Reynoldsac55e012018-03-27 11:17:30 -0400589
Beverly Taiefd8e082018-05-15 23:49:05 +0000590 if (mState.ringerModeInternal == RINGER_MODE_NORMAL) {
591 playTouchFeedback();
592 }
593
Beverlyd253f982018-05-14 16:48:40 -0400594 return true;
595 }
596
John Spurlockf88d8082015-03-25 18:09:51 -0400597 private void onSetRingerModeW(int mode, boolean external) {
598 if (external) {
599 mAudio.setRingerMode(mode);
600 } else {
601 mAudio.setRingerModeInternal(mode);
602 }
603 }
604
605 private void onSetStreamMuteW(int stream, boolean mute) {
606 mAudio.adjustStreamVolume(stream, mute ? AudioManager.ADJUST_MUTE
607 : AudioManager.ADJUST_UNMUTE, 0);
608 }
609
610 private void onSetStreamVolumeW(int stream, int level) {
611 if (D.BUG) Log.d(TAG, "onSetStreamVolume " + stream + " level=" + level);
612 if (stream >= DYNAMIC_STREAM_START_INDEX) {
613 mMediaSessionsCallbacksW.setStreamVolume(stream, level);
614 return;
615 }
Yao Chen634acb92016-04-13 16:17:47 -0700616 setAudioManagerStreamVolume(stream, level, 0);
John Spurlockf88d8082015-03-25 18:09:51 -0400617 }
618
619 private void onSetActiveStreamW(int stream) {
620 boolean changed = updateActiveStreamW(stream);
621 if (changed) {
622 mCallbacks.onStateChanged(mState);
623 }
624 }
625
626 private void onSetExitConditionW(Condition condition) {
John Spurlockb2278d62015-04-07 12:47:12 -0400627 mNoMan.setZenMode(mState.zenMode, condition != null ? condition.id : null, TAG);
John Spurlockf88d8082015-03-25 18:09:51 -0400628 }
629
630 private void onSetZenModeW(int mode) {
631 if (D.BUG) Log.d(TAG, "onSetZenModeW " + mode);
John Spurlockb2278d62015-04-07 12:47:12 -0400632 mNoMan.setZenMode(mode, null, TAG);
John Spurlockf88d8082015-03-25 18:09:51 -0400633 }
634
635 private void onDismissRequestedW(int reason) {
636 mCallbacks.onDismissRequested(reason);
637 }
638
639 public void showDndTile(boolean visible) {
640 if (D.BUG) Log.d(TAG, "showDndTile");
John Spurlockcd863ad2015-04-07 14:01:28 -0400641 DndTile.setVisible(mContext, visible);
John Spurlockf88d8082015-03-25 18:09:51 -0400642 }
643
644 private final class VC extends IVolumeController.Stub {
Jason Monk782cd672017-03-22 12:50:57 -0400645 private final String TAG = VolumeDialogControllerImpl.TAG + ".VC";
John Spurlockf88d8082015-03-25 18:09:51 -0400646
647 @Override
648 public void displaySafeVolumeWarning(int flags) throws RemoteException {
John Spurlock76b52b32015-04-03 00:00:12 -0400649 if (D.BUG) Log.d(TAG, "displaySafeVolumeWarning "
650 + Util.audioManagerFlagsToString(flags));
651 if (mDestroyed) return;
652 mWorker.obtainMessage(W.SHOW_SAFETY_WARNING, flags, 0).sendToTarget();
John Spurlockf88d8082015-03-25 18:09:51 -0400653 }
654
655 @Override
656 public void volumeChanged(int streamType, int flags) throws RemoteException {
657 if (D.BUG) Log.d(TAG, "volumeChanged " + AudioSystem.streamToString(streamType)
658 + " " + Util.audioManagerFlagsToString(flags));
659 if (mDestroyed) return;
660 mWorker.obtainMessage(W.VOLUME_CHANGED, streamType, flags).sendToTarget();
661 }
662
663 @Override
664 public void masterMuteChanged(int flags) throws RemoteException {
665 if (D.BUG) Log.d(TAG, "masterMuteChanged");
666 }
667
668 @Override
669 public void setLayoutDirection(int layoutDirection) throws RemoteException {
670 if (D.BUG) Log.d(TAG, "setLayoutDirection");
671 if (mDestroyed) return;
672 mWorker.obtainMessage(W.LAYOUT_DIRECTION_CHANGED, layoutDirection, 0).sendToTarget();
673 }
674
675 @Override
676 public void dismiss() throws RemoteException {
677 if (D.BUG) Log.d(TAG, "dismiss requested");
678 if (mDestroyed) return;
679 mWorker.obtainMessage(W.DISMISS_REQUESTED, Events.DISMISS_REASON_VOLUME_CONTROLLER, 0)
680 .sendToTarget();
681 mWorker.sendEmptyMessage(W.DISMISS_REQUESTED);
682 }
Jean-Michel Triviac487672016-11-11 10:05:18 -0800683
684 @Override
685 public void setA11yMode(int mode) {
686 if (D.BUG) Log.d(TAG, "setA11yMode to " + mode);
687 if (mDestroyed) return;
688 switch (mode) {
689 case VolumePolicy.A11Y_MODE_MEDIA_A11Y_VOLUME:
690 // "legacy" mode
Julia Reynoldsdbfb40f2017-01-23 11:05:57 -0500691 mShowA11yStream = false;
Jean-Michel Triviac487672016-11-11 10:05:18 -0800692 break;
693 case VolumePolicy.A11Y_MODE_INDEPENDENT_A11Y_VOLUME:
Julia Reynoldsdbfb40f2017-01-23 11:05:57 -0500694 mShowA11yStream = true;
Jean-Michel Triviac487672016-11-11 10:05:18 -0800695 break;
696 default:
697 Log.e(TAG, "Invalid accessibility mode " + mode);
698 break;
699 }
Julia Reynoldsdbfb40f2017-01-23 11:05:57 -0500700 mWorker.obtainMessage(W.ACCESSIBILITY_MODE_CHANGED, mShowA11yStream).sendToTarget();
Jean-Michel Triviac487672016-11-11 10:05:18 -0800701 }
John Spurlockf88d8082015-03-25 18:09:51 -0400702 }
703
704 private final class W extends Handler {
705 private static final int VOLUME_CHANGED = 1;
706 private static final int DISMISS_REQUESTED = 2;
707 private static final int GET_STATE = 3;
708 private static final int SET_RINGER_MODE = 4;
709 private static final int SET_ZEN_MODE = 5;
710 private static final int SET_EXIT_CONDITION = 6;
711 private static final int SET_STREAM_MUTE = 7;
712 private static final int LAYOUT_DIRECTION_CHANGED = 8;
713 private static final int CONFIGURATION_CHANGED = 9;
714 private static final int SET_STREAM_VOLUME = 10;
715 private static final int SET_ACTIVE_STREAM = 11;
716 private static final int NOTIFY_VISIBLE = 12;
717 private static final int USER_ACTIVITY = 13;
John Spurlock76b52b32015-04-03 00:00:12 -0400718 private static final int SHOW_SAFETY_WARNING = 14;
Julia Reynoldsdbfb40f2017-01-23 11:05:57 -0500719 private static final int ACCESSIBILITY_MODE_CHANGED = 15;
John Spurlockf88d8082015-03-25 18:09:51 -0400720
721 W(Looper looper) {
722 super(looper);
723 }
724
725 @Override
726 public void handleMessage(Message msg) {
727 switch (msg.what) {
728 case VOLUME_CHANGED: onVolumeChangedW(msg.arg1, msg.arg2); break;
729 case DISMISS_REQUESTED: onDismissRequestedW(msg.arg1); break;
730 case GET_STATE: onGetStateW(); break;
731 case SET_RINGER_MODE: onSetRingerModeW(msg.arg1, msg.arg2 != 0); break;
732 case SET_ZEN_MODE: onSetZenModeW(msg.arg1); break;
733 case SET_EXIT_CONDITION: onSetExitConditionW((Condition) msg.obj); break;
734 case SET_STREAM_MUTE: onSetStreamMuteW(msg.arg1, msg.arg2 != 0); break;
735 case LAYOUT_DIRECTION_CHANGED: mCallbacks.onLayoutDirectionChanged(msg.arg1); break;
736 case CONFIGURATION_CHANGED: mCallbacks.onConfigurationChanged(); break;
737 case SET_STREAM_VOLUME: onSetStreamVolumeW(msg.arg1, msg.arg2); break;
738 case SET_ACTIVE_STREAM: onSetActiveStreamW(msg.arg1); break;
John Spurlock76b52b32015-04-03 00:00:12 -0400739 case NOTIFY_VISIBLE: onNotifyVisibleW(msg.arg1 != 0); break;
740 case USER_ACTIVITY: onUserActivityW(); break;
741 case SHOW_SAFETY_WARNING: onShowSafetyWarningW(msg.arg1); break;
Julia Reynoldsdbfb40f2017-01-23 11:05:57 -0500742 case ACCESSIBILITY_MODE_CHANGED: onAccessibilityModeChanged((Boolean) msg.obj);
Julia Reynolds6692b472018-01-24 07:23:56 -0500743
John Spurlockf88d8082015-03-25 18:09:51 -0400744 }
745 }
746 }
747
Beverly8ebef842017-07-12 10:58:22 -0400748 class C implements Callbacks {
John Spurlockf88d8082015-03-25 18:09:51 -0400749 private final HashMap<Callbacks, Handler> mCallbackMap = new HashMap<>();
750
751 public void add(Callbacks callback, Handler handler) {
752 if (callback == null || handler == null) throw new IllegalArgumentException();
753 mCallbackMap.put(callback, handler);
754 }
755
756 public void remove(Callbacks callback) {
757 mCallbackMap.remove(callback);
758 }
759
760 @Override
761 public void onShowRequested(final int reason) {
762 for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
763 entry.getValue().post(new Runnable() {
764 @Override
765 public void run() {
766 entry.getKey().onShowRequested(reason);
767 }
768 });
769 }
770 }
771
772 @Override
773 public void onDismissRequested(final int reason) {
774 for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
775 entry.getValue().post(new Runnable() {
776 @Override
777 public void run() {
778 entry.getKey().onDismissRequested(reason);
779 }
780 });
781 }
782 }
783
784 @Override
785 public void onStateChanged(final State state) {
786 final long time = System.currentTimeMillis();
787 final State copy = state.copy();
788 for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
789 entry.getValue().post(new Runnable() {
790 @Override
791 public void run() {
792 entry.getKey().onStateChanged(copy);
793 }
794 });
795 }
796 Events.writeState(time, copy);
797 }
798
799 @Override
800 public void onLayoutDirectionChanged(final int layoutDirection) {
801 for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
802 entry.getValue().post(new Runnable() {
803 @Override
804 public void run() {
805 entry.getKey().onLayoutDirectionChanged(layoutDirection);
806 }
807 });
808 }
809 }
810
811 @Override
812 public void onConfigurationChanged() {
813 for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
814 entry.getValue().post(new Runnable() {
815 @Override
816 public void run() {
817 entry.getKey().onConfigurationChanged();
818 }
819 });
820 }
821 }
822
823 @Override
824 public void onShowVibrateHint() {
825 for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
826 entry.getValue().post(new Runnable() {
827 @Override
828 public void run() {
829 entry.getKey().onShowVibrateHint();
830 }
831 });
832 }
833 }
834
835 @Override
836 public void onShowSilentHint() {
837 for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
838 entry.getValue().post(new Runnable() {
839 @Override
840 public void run() {
841 entry.getKey().onShowSilentHint();
842 }
843 });
844 }
845 }
846
847 @Override
848 public void onScreenOff() {
849 for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
850 entry.getValue().post(new Runnable() {
851 @Override
852 public void run() {
853 entry.getKey().onScreenOff();
854 }
855 });
856 }
857 }
John Spurlock76b52b32015-04-03 00:00:12 -0400858
859 @Override
860 public void onShowSafetyWarning(final int flags) {
861 for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
862 entry.getValue().post(new Runnable() {
863 @Override
864 public void run() {
865 entry.getKey().onShowSafetyWarning(flags);
866 }
867 });
868 }
869 }
Julia Reynoldsdbfb40f2017-01-23 11:05:57 -0500870
871 @Override
872 public void onAccessibilityModeChanged(Boolean showA11yStream) {
873 boolean show = showA11yStream == null ? false : showA11yStream;
874 for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
875 entry.getValue().post(new Runnable() {
876 @Override
877 public void run() {
878 entry.getKey().onAccessibilityModeChanged(show);
879 }
880 });
881 }
882 }
John Spurlockf88d8082015-03-25 18:09:51 -0400883 }
884
885
886 private final class SettingObserver extends ContentObserver {
John Spurlockf88d8082015-03-25 18:09:51 -0400887 private final Uri ZEN_MODE_URI =
888 Settings.Global.getUriFor(Settings.Global.ZEN_MODE);
889 private final Uri ZEN_MODE_CONFIG_URI =
890 Settings.Global.getUriFor(Settings.Global.ZEN_MODE_CONFIG_ETAG);
891
892 public SettingObserver(Handler handler) {
893 super(handler);
894 }
895
896 public void init() {
John Spurlockf88d8082015-03-25 18:09:51 -0400897 mContext.getContentResolver().registerContentObserver(ZEN_MODE_URI, false, this);
898 mContext.getContentResolver().registerContentObserver(ZEN_MODE_CONFIG_URI, false, this);
John Spurlockf88d8082015-03-25 18:09:51 -0400899 }
900
901 public void destroy() {
902 mContext.getContentResolver().unregisterContentObserver(this);
903 }
904
905 @Override
906 public void onChange(boolean selfChange, Uri uri) {
907 boolean changed = false;
John Spurlockf88d8082015-03-25 18:09:51 -0400908 if (ZEN_MODE_URI.equals(uri)) {
909 changed = updateZenModeW();
910 }
Beverly925cde82018-01-23 09:31:23 -0500911 if (ZEN_MODE_CONFIG_URI.equals(uri)) {
912 changed |= updateZenConfig();
913 }
914
John Spurlockf88d8082015-03-25 18:09:51 -0400915 if (changed) {
916 mCallbacks.onStateChanged(mState);
917 }
918 }
919 }
920
921 private final class Receiver extends BroadcastReceiver {
922
923 public void init() {
924 final IntentFilter filter = new IntentFilter();
925 filter.addAction(AudioManager.VOLUME_CHANGED_ACTION);
926 filter.addAction(AudioManager.STREAM_DEVICES_CHANGED_ACTION);
927 filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
928 filter.addAction(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION);
929 filter.addAction(AudioManager.STREAM_MUTE_CHANGED_ACTION);
930 filter.addAction(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED);
931 filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
932 filter.addAction(Intent.ACTION_SCREEN_OFF);
John Spurlockbc7233a2015-06-29 15:34:18 -0400933 filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
John Spurlockf88d8082015-03-25 18:09:51 -0400934 mContext.registerReceiver(this, filter, null, mWorker);
935 }
936
937 public void destroy() {
938 mContext.unregisterReceiver(this);
939 }
940
941 @Override
942 public void onReceive(Context context, Intent intent) {
943 final String action = intent.getAction();
944 boolean changed = false;
945 if (action.equals(AudioManager.VOLUME_CHANGED_ACTION)) {
946 final int stream = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1);
947 final int level = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, -1);
948 final int oldLevel = intent
949 .getIntExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, -1);
950 if (D.BUG) Log.d(TAG, "onReceive VOLUME_CHANGED_ACTION stream=" + stream
951 + " level=" + level + " oldLevel=" + oldLevel);
952 changed = updateStreamLevelW(stream, level);
953 } else if (action.equals(AudioManager.STREAM_DEVICES_CHANGED_ACTION)) {
954 final int stream = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1);
955 final int devices = intent
956 .getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_DEVICES, -1);
957 final int oldDevices = intent
958 .getIntExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_DEVICES, -1);
959 if (D.BUG) Log.d(TAG, "onReceive STREAM_DEVICES_CHANGED_ACTION stream="
960 + stream + " devices=" + devices + " oldDevices=" + oldDevices);
961 changed = checkRoutedToBluetoothW(stream);
Julia Reynolds8ae994f2015-09-14 11:12:42 -0400962 changed |= onVolumeChangedW(stream, 0);
John Spurlockf88d8082015-03-25 18:09:51 -0400963 } else if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) {
964 final int rm = intent.getIntExtra(AudioManager.EXTRA_RINGER_MODE, -1);
Alastair Breeze1d421652018-10-16 19:17:07 +0100965 if (isInitialStickyBroadcast()) mState.ringerModeExternal = rm;
John Spurlockf88d8082015-03-25 18:09:51 -0400966 if (D.BUG) Log.d(TAG, "onReceive RINGER_MODE_CHANGED_ACTION rm="
967 + Util.ringerModeToString(rm));
968 changed = updateRingerModeExternalW(rm);
969 } else if (action.equals(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION)) {
970 final int rm = intent.getIntExtra(AudioManager.EXTRA_RINGER_MODE, -1);
Alastair Breeze1d421652018-10-16 19:17:07 +0100971 if (isInitialStickyBroadcast()) mState.ringerModeInternal = rm;
John Spurlockf88d8082015-03-25 18:09:51 -0400972 if (D.BUG) Log.d(TAG, "onReceive INTERNAL_RINGER_MODE_CHANGED_ACTION rm="
973 + Util.ringerModeToString(rm));
974 changed = updateRingerModeInternalW(rm);
975 } else if (action.equals(AudioManager.STREAM_MUTE_CHANGED_ACTION)) {
976 final int stream = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1);
977 final boolean muted = intent
978 .getBooleanExtra(AudioManager.EXTRA_STREAM_VOLUME_MUTED, false);
979 if (D.BUG) Log.d(TAG, "onReceive STREAM_MUTE_CHANGED_ACTION stream=" + stream
980 + " muted=" + muted);
981 changed = updateStreamMuteW(stream, muted);
982 } else if (action.equals(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED)) {
983 if (D.BUG) Log.d(TAG, "onReceive ACTION_EFFECTS_SUPPRESSOR_CHANGED");
984 changed = updateEffectsSuppressorW(mNoMan.getEffectsSuppressor());
985 } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
986 if (D.BUG) Log.d(TAG, "onReceive ACTION_CONFIGURATION_CHANGED");
987 mCallbacks.onConfigurationChanged();
988 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
989 if (D.BUG) Log.d(TAG, "onReceive ACTION_SCREEN_OFF");
990 mCallbacks.onScreenOff();
John Spurlockbc7233a2015-06-29 15:34:18 -0400991 } else if (action.equals(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) {
992 if (D.BUG) Log.d(TAG, "onReceive ACTION_CLOSE_SYSTEM_DIALOGS");
993 dismiss();
John Spurlockf88d8082015-03-25 18:09:51 -0400994 }
995 if (changed) {
996 mCallbacks.onStateChanged(mState);
997 }
998 }
999 }
1000
Beverly4e936612017-07-28 14:05:30 -04001001 protected final class MediaSessionsCallbacks implements MediaSessions.Callbacks {
John Spurlockf88d8082015-03-25 18:09:51 -04001002 private final HashMap<Token, Integer> mRemoteStreams = new HashMap<>();
1003
1004 private int mNextStream = DYNAMIC_STREAM_START_INDEX;
1005
1006 @Override
1007 public void onRemoteUpdate(Token token, String name, PlaybackInfo pi) {
Beverlyb5a27812017-07-24 11:34:48 -04001008 addStream(token, "onRemoteUpdate");
John Spurlockf88d8082015-03-25 18:09:51 -04001009 final int stream = mRemoteStreams.get(token);
1010 boolean changed = mState.states.indexOfKey(stream) < 0;
1011 final StreamState ss = streamStateW(stream);
1012 ss.dynamic = true;
1013 ss.levelMin = 0;
1014 ss.levelMax = pi.getMaxVolume();
1015 if (ss.level != pi.getCurrentVolume()) {
1016 ss.level = pi.getCurrentVolume();
1017 changed = true;
1018 }
Julia Reynolds03c548f2016-12-14 15:02:38 -05001019 if (!Objects.equals(ss.remoteLabel, name)) {
1020 ss.name = -1;
1021 ss.remoteLabel = name;
John Spurlockf88d8082015-03-25 18:09:51 -04001022 changed = true;
1023 }
1024 if (changed) {
1025 if (D.BUG) Log.d(TAG, "onRemoteUpdate: " + name + ": " + ss.level
1026 + " of " + ss.levelMax);
1027 mCallbacks.onStateChanged(mState);
1028 }
1029 }
1030
1031 @Override
1032 public void onRemoteVolumeChanged(Token token, int flags) {
Beverlyb5a27812017-07-24 11:34:48 -04001033 addStream(token, "onRemoteVolumeChanged");
John Spurlockf88d8082015-03-25 18:09:51 -04001034 final int stream = mRemoteStreams.get(token);
Beverly85e05eb2017-07-21 14:49:27 -04001035 final boolean showUI = shouldShowUI(flags);
John Spurlockf88d8082015-03-25 18:09:51 -04001036 boolean changed = updateActiveStreamW(stream);
1037 if (showUI) {
1038 changed |= checkRoutedToBluetoothW(AudioManager.STREAM_MUSIC);
1039 }
1040 if (changed) {
1041 mCallbacks.onStateChanged(mState);
1042 }
1043 if (showUI) {
1044 mCallbacks.onShowRequested(Events.SHOW_REASON_REMOTE_VOLUME_CHANGED);
1045 }
1046 }
1047
1048 @Override
1049 public void onRemoteRemoved(Token token) {
Beverlyb5a27812017-07-24 11:34:48 -04001050 if (!mRemoteStreams.containsKey(token)) {
1051 if (D.BUG) Log.d(TAG, "onRemoteRemoved: stream doesn't exist, "
1052 + "aborting remote removed for token:" + token.toString());
1053 return;
1054 }
John Spurlockf88d8082015-03-25 18:09:51 -04001055 final int stream = mRemoteStreams.get(token);
1056 mState.states.remove(stream);
1057 if (mState.activeStream == stream) {
1058 updateActiveStreamW(-1);
1059 }
1060 mCallbacks.onStateChanged(mState);
1061 }
1062
1063 public void setStreamVolume(int stream, int level) {
1064 final Token t = findToken(stream);
1065 if (t == null) {
1066 Log.w(TAG, "setStreamVolume: No token found for stream: " + stream);
1067 return;
1068 }
1069 mMediaSessions.setVolume(t, level);
1070 }
1071
1072 private Token findToken(int stream) {
1073 for (Map.Entry<Token, Integer> entry : mRemoteStreams.entrySet()) {
1074 if (entry.getValue().equals(stream)) {
1075 return entry.getKey();
1076 }
1077 }
1078 return null;
1079 }
Beverlyb5a27812017-07-24 11:34:48 -04001080
1081 private void addStream(Token token, String triggeringMethod) {
1082 if (!mRemoteStreams.containsKey(token)) {
1083 mRemoteStreams.put(token, mNextStream);
1084 if (D.BUG) Log.d(TAG, triggeringMethod + ": added stream " + mNextStream
1085 + " from token + "+ token.toString());
1086 mNextStream++;
1087 }
1088 }
John Spurlockf88d8082015-03-25 18:09:51 -04001089 }
1090
Yao Chen634acb92016-04-13 16:17:47 -07001091 public interface UserActivityListener {
1092 void onUserActivity();
1093 }
John Spurlockf88d8082015-03-25 18:09:51 -04001094}