1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.preference;
18 
19 import android.annotation.NonNull;
20 import android.app.NotificationManager;
21 import android.compat.annotation.UnsupportedAppUsage;
22 import android.content.BroadcastReceiver;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.content.IntentFilter;
26 import android.database.ContentObserver;
27 import android.media.AudioAttributes;
28 import android.media.AudioManager;
29 import android.media.Ringtone;
30 import android.media.RingtoneManager;
31 import android.media.audiopolicy.AudioProductStrategy;
32 import android.media.audiopolicy.AudioVolumeGroup;
33 import android.net.Uri;
34 import android.os.Handler;
35 import android.os.HandlerThread;
36 import android.os.Message;
37 import android.preference.VolumePreference.VolumeStore;
38 import android.provider.Settings;
39 import android.provider.Settings.Global;
40 import android.provider.Settings.System;
41 import android.service.notification.ZenModeConfig;
42 import android.util.Log;
43 import android.widget.SeekBar;
44 import android.widget.SeekBar.OnSeekBarChangeListener;
45 
46 import com.android.internal.annotations.GuardedBy;
47 import com.android.internal.os.SomeArgs;
48 
49 import java.util.concurrent.TimeUnit;
50 
51 /**
52  * Turns a {@link SeekBar} into a volume control.
53  * @hide
54  *
55  * @deprecated Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
56  *      <a href="{@docRoot}reference/androidx/preference/package-summary.html">
57  *      Preference Library</a> for consistent behavior across all devices. For more information on
58  *      using the AndroidX Preference Library see
59  *      <a href="{@docRoot}guide/topics/ui/settings.html">Settings</a>.
60  */
61 @Deprecated
62 public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callback {
63     private static final String TAG = "SeekBarVolumizer";
64 
65     public interface Callback {
onSampleStarting(SeekBarVolumizer sbv)66         void onSampleStarting(SeekBarVolumizer sbv);
onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch)67         void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch);
onMuted(boolean muted, boolean zenMuted)68         void onMuted(boolean muted, boolean zenMuted);
69         /**
70          * Callback reporting that the seek bar is start tracking.
71          * @param sbv - The seek bar that start tracking
72          */
onStartTrackingTouch(SeekBarVolumizer sbv)73         void onStartTrackingTouch(SeekBarVolumizer sbv);
74     }
75 
76     private static final int MSG_GROUP_VOLUME_CHANGED = 1;
77     private static long sStopVolumeTime = 0L;
78     private final Handler mVolumeHandler = new VolumeHandler();
79     private AudioAttributes mAttributes;
80     private int mVolumeGroupId;
81 
82     private final AudioManager.VolumeGroupCallback mVolumeGroupCallback =
83             new AudioManager.VolumeGroupCallback() {
84         @Override
85         public void onAudioVolumeGroupChanged(int group, int flags) {
86             if (mHandler == null) {
87                 return;
88             }
89             SomeArgs args = SomeArgs.obtain();
90             args.arg1 = group;
91             args.arg2 = flags;
92             mVolumeHandler.sendMessage(mHandler.obtainMessage(MSG_GROUP_VOLUME_CHANGED, args));
93         }
94     };
95 
96     @UnsupportedAppUsage
97     private final Context mContext;
98     private final H mUiHandler = new H();
99     private final Callback mCallback;
100     private final Uri mDefaultUri;
101     @UnsupportedAppUsage
102     private final AudioManager mAudioManager;
103     private final NotificationManager mNotificationManager;
104     @UnsupportedAppUsage
105     private final int mStreamType;
106     private final int mMaxStreamVolume;
107     private boolean mAffectedByRingerMode;
108     private boolean mNotificationOrRing;
109     private final Receiver mReceiver = new Receiver();
110 
111     private Handler mHandler;
112     private Observer mVolumeObserver;
113     @UnsupportedAppUsage
114     private int mOriginalStreamVolume;
115     private int mLastAudibleStreamVolume;
116     // When the old handler is destroyed and a new one is created, there could be a situation where
117     // this is accessed at the same time in different handlers. So, access to this field needs to be
118     // synchronized.
119     @GuardedBy("this")
120     @UnsupportedAppUsage
121     private Ringtone mRingtone;
122     @UnsupportedAppUsage
123     private int mLastProgress = -1;
124     private boolean mMuted;
125     @UnsupportedAppUsage
126     private SeekBar mSeekBar;
127     private int mVolumeBeforeMute = -1;
128     private int mRingerMode;
129     private int mZenMode;
130     private boolean mPlaySample;
131 
132     private static final int MSG_SET_STREAM_VOLUME = 0;
133     private static final int MSG_START_SAMPLE = 1;
134     private static final int MSG_STOP_SAMPLE = 2;
135     private static final int MSG_INIT_SAMPLE = 3;
136     private static final int CHECK_RINGTONE_PLAYBACK_DELAY_MS = 1000;
137     private static final long SET_STREAM_VOLUME_DELAY_MS = TimeUnit.MILLISECONDS.toMillis(500);
138     private static final long START_SAMPLE_DELAY_MS = TimeUnit.MILLISECONDS.toMillis(500);
139     private static final long DURATION_TO_START_DELAYING = TimeUnit.MILLISECONDS.toMillis(2000);
140 
141     private NotificationManager.Policy mNotificationPolicy;
142     private boolean mAllowAlarms;
143     private boolean mAllowMedia;
144     private boolean mAllowRinger;
145 
146     @UnsupportedAppUsage
SeekBarVolumizer(Context context, int streamType, Uri defaultUri, Callback callback)147     public SeekBarVolumizer(Context context, int streamType, Uri defaultUri, Callback callback) {
148         this(context, streamType, defaultUri, callback, true /* playSample */);
149     }
150 
SeekBarVolumizer( Context context, int streamType, Uri defaultUri, Callback callback, boolean playSample)151     public SeekBarVolumizer(
152             Context context,
153             int streamType,
154             Uri defaultUri,
155             Callback callback,
156             boolean playSample) {
157         mContext = context;
158         mAudioManager = context.getSystemService(AudioManager.class);
159         mNotificationManager = context.getSystemService(NotificationManager.class);
160         mNotificationPolicy = mNotificationManager.getConsolidatedNotificationPolicy();
161         mAllowAlarms = (mNotificationPolicy.priorityCategories & NotificationManager.Policy
162                 .PRIORITY_CATEGORY_ALARMS) != 0;
163         mAllowMedia = (mNotificationPolicy.priorityCategories & NotificationManager.Policy
164                 .PRIORITY_CATEGORY_MEDIA) != 0;
165         mAllowRinger = !ZenModeConfig.areAllPriorityOnlyRingerSoundsMuted(
166                 mNotificationPolicy);
167         mStreamType = streamType;
168         mAffectedByRingerMode = mAudioManager.isStreamAffectedByRingerMode(mStreamType);
169         mNotificationOrRing = isNotificationOrRing(mStreamType);
170         if (mNotificationOrRing) {
171             mRingerMode = mAudioManager.getRingerModeInternal();
172         }
173         mZenMode = mNotificationManager.getZenMode();
174 
175         if (hasAudioProductStrategies()) {
176             mVolumeGroupId = getVolumeGroupIdForLegacyStreamType(mStreamType);
177             mAttributes = getAudioAttributesForLegacyStreamType(
178                     mStreamType);
179         }
180 
181         mMaxStreamVolume = mAudioManager.getStreamMaxVolume(mStreamType);
182         mCallback = callback;
183         mOriginalStreamVolume = mAudioManager.getStreamVolume(mStreamType);
184         mLastAudibleStreamVolume = mAudioManager.getLastAudibleStreamVolume(mStreamType);
185         mMuted = mAudioManager.isStreamMute(mStreamType);
186         mPlaySample = playSample;
187         if (mCallback != null) {
188             mCallback.onMuted(mMuted, isZenMuted());
189         }
190         if (defaultUri == null) {
191             if (mStreamType == AudioManager.STREAM_RING) {
192                 defaultUri = Settings.System.DEFAULT_RINGTONE_URI;
193             } else if (mStreamType == AudioManager.STREAM_NOTIFICATION) {
194                 defaultUri = Settings.System.DEFAULT_NOTIFICATION_URI;
195             } else {
196                 defaultUri = Settings.System.DEFAULT_ALARM_ALERT_URI;
197             }
198         }
199         mDefaultUri = defaultUri;
200     }
201 
hasAudioProductStrategies()202     private boolean hasAudioProductStrategies() {
203         return AudioManager.getAudioProductStrategies().size() > 0;
204     }
205 
getVolumeGroupIdForLegacyStreamType(int streamType)206     private int getVolumeGroupIdForLegacyStreamType(int streamType) {
207         for (final AudioProductStrategy productStrategy :
208                 AudioManager.getAudioProductStrategies()) {
209             int volumeGroupId = productStrategy.getVolumeGroupIdForLegacyStreamType(streamType);
210             if (volumeGroupId != AudioVolumeGroup.DEFAULT_VOLUME_GROUP) {
211                 return volumeGroupId;
212             }
213         }
214 
215         return AudioManager.getAudioProductStrategies().stream()
216                 .map(strategy -> strategy.getVolumeGroupIdForAudioAttributes(
217                         AudioProductStrategy.sDefaultAttributes))
218                 .filter(volumeGroupId -> volumeGroupId != AudioVolumeGroup.DEFAULT_VOLUME_GROUP)
219                 .findFirst()
220                 .orElse(AudioVolumeGroup.DEFAULT_VOLUME_GROUP);
221     }
222 
getAudioAttributesForLegacyStreamType(int streamType)223     private @NonNull AudioAttributes getAudioAttributesForLegacyStreamType(int streamType) {
224         for (final AudioProductStrategy productStrategy :
225                 AudioManager.getAudioProductStrategies()) {
226             AudioAttributes aa = productStrategy.getAudioAttributesForLegacyStreamType(streamType);
227             if (aa != null) {
228                 return aa;
229             }
230         }
231         return new AudioAttributes.Builder()
232                 .setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN)
233                 .setUsage(AudioAttributes.USAGE_UNKNOWN).build();
234     }
235 
isNotificationOrRing(int stream)236     private static boolean isNotificationOrRing(int stream) {
237         return stream == AudioManager.STREAM_RING || stream == AudioManager.STREAM_NOTIFICATION;
238     }
239 
isAlarmsStream(int stream)240     private static boolean isAlarmsStream(int stream) {
241         return stream == AudioManager.STREAM_ALARM;
242     }
243 
isMediaStream(int stream)244     private static boolean isMediaStream(int stream) {
245         return stream == AudioManager.STREAM_MUSIC;
246     }
247 
setSeekBar(SeekBar seekBar)248     public void setSeekBar(SeekBar seekBar) {
249         if (mSeekBar != null) {
250             mSeekBar.setOnSeekBarChangeListener(null);
251         }
252         mSeekBar = seekBar;
253         mSeekBar.setOnSeekBarChangeListener(null);
254         mSeekBar.setMax(mMaxStreamVolume);
255         updateSeekBar();
256         mSeekBar.setOnSeekBarChangeListener(this);
257     }
258 
isZenMuted()259     private boolean isZenMuted() {
260         return mNotificationOrRing && mZenMode == Global.ZEN_MODE_ALARMS
261                 || mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS
262                 || (mZenMode == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS
263                     && ((!mAllowAlarms && isAlarmsStream(mStreamType))
264                         || (!mAllowMedia && isMediaStream(mStreamType))
265                         || (!mAllowRinger && isNotificationOrRing(mStreamType))));
266     }
267 
updateSeekBar()268     protected void updateSeekBar() {
269         final boolean zenMuted = isZenMuted();
270         mSeekBar.setEnabled(!zenMuted);
271         if (zenMuted) {
272             mSeekBar.setProgress(mLastAudibleStreamVolume, true);
273         } else if (mNotificationOrRing && mRingerMode == AudioManager.RINGER_MODE_VIBRATE) {
274             mSeekBar.setProgress(0, true);
275         } else if (mMuted) {
276             mSeekBar.setProgress(0, true);
277         } else {
278             mSeekBar.setProgress(mLastProgress > -1 ? mLastProgress : mOriginalStreamVolume, true);
279         }
280     }
281 
282     @Override
handleMessage(Message msg)283     public boolean handleMessage(Message msg) {
284         switch (msg.what) {
285             case MSG_SET_STREAM_VOLUME:
286                 if (mMuted && mLastProgress > 0) {
287                     mAudioManager.adjustStreamVolume(mStreamType, AudioManager.ADJUST_UNMUTE, 0);
288                 } else if (!mMuted && mLastProgress == 0) {
289                     mAudioManager.adjustStreamVolume(mStreamType, AudioManager.ADJUST_MUTE, 0);
290                 }
291                 mAudioManager.setStreamVolume(mStreamType, mLastProgress,
292                         AudioManager.FLAG_SHOW_UI_WARNINGS);
293                 break;
294             case MSG_START_SAMPLE:
295                 if (mPlaySample) {
296                     onStartSample();
297                 }
298                 break;
299             case MSG_STOP_SAMPLE:
300                 if (mPlaySample) {
301                     onStopSample();
302                 }
303                 break;
304             case MSG_INIT_SAMPLE:
305                 if (mPlaySample) {
306                     onInitSample();
307                 }
308                 break;
309             default:
310                 Log.e(TAG, "invalid SeekBarVolumizer message: "+msg.what);
311         }
312         return true;
313     }
314 
onInitSample()315     private void onInitSample() {
316         synchronized (this) {
317             mRingtone = RingtoneManager.getRingtone(mContext, mDefaultUri);
318             if (mRingtone != null) {
319                 mRingtone.setStreamType(mStreamType);
320             }
321         }
322     }
323 
postStartSample()324     private void postStartSample() {
325         if (mHandler == null) return;
326         mHandler.removeMessages(MSG_START_SAMPLE);
327         mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_START_SAMPLE),
328                 isSamplePlaying() ? CHECK_RINGTONE_PLAYBACK_DELAY_MS
329                         : isDelay() ? START_SAMPLE_DELAY_MS : 0);
330     }
331 
332     // After stop volume it needs to add a small delay when playing volume or set stream.
333     // It is because the call volume is from the earpiece and the alarm/ring/media
334     // is from the speaker. If play the alarm volume or set alarm stream right after stop
335     // call volume, the alarm volume on earpiece is returned then cause the volume value incorrect.
336     // It needs a small delay after stop call volume to get alarm volume on speaker.
337     // e.g. : If the ring volume has adjusted right after call volume stopped in 2 second
338     // then delay 0.5 second to set stream or play volume ringtone.
isDelay()339     private boolean isDelay() {
340         final long durationTime = java.lang.System.currentTimeMillis() - sStopVolumeTime;
341         return durationTime >= 0 && durationTime < DURATION_TO_START_DELAYING;
342     }
343 
setStopVolumeTime()344     private void setStopVolumeTime() {
345         // set the time of stop volume
346         if ((mStreamType == AudioManager.STREAM_VOICE_CALL
347                 || mStreamType == AudioManager.STREAM_RING
348                 || mStreamType == AudioManager.STREAM_ALARM)) {
349             sStopVolumeTime = java.lang.System.currentTimeMillis();
350         }
351     }
352 
onStartSample()353     private void onStartSample() {
354         if (!isSamplePlaying()) {
355             if (mCallback != null) {
356                 mCallback.onSampleStarting(this);
357             }
358 
359             synchronized (this) {
360                 if (mRingtone != null) {
361                     try {
362                         mRingtone.setAudioAttributes(new AudioAttributes.Builder(mRingtone
363                                 .getAudioAttributes())
364                                 .setFlags(AudioAttributes.FLAG_BYPASS_MUTE)
365                                 .build());
366                         mRingtone.play();
367                     } catch (Throwable e) {
368                         Log.w(TAG, "Error playing ringtone, stream " + mStreamType, e);
369                     }
370                 }
371             }
372         }
373     }
374 
postStopSample()375     private void postStopSample() {
376         if (mHandler == null) return;
377         setStopVolumeTime();
378         // remove pending delayed start messages
379         mHandler.removeMessages(MSG_START_SAMPLE);
380         mHandler.removeMessages(MSG_STOP_SAMPLE);
381         mHandler.sendMessage(mHandler.obtainMessage(MSG_STOP_SAMPLE));
382     }
383 
onStopSample()384     private void onStopSample() {
385         synchronized (this) {
386             if (mRingtone != null) {
387                 mRingtone.stop();
388             }
389         }
390     }
391 
392     @UnsupportedAppUsage
stop()393     public void stop() {
394         if (mHandler == null) return;  // already stopped
395         postStopSample();
396         mContext.getContentResolver().unregisterContentObserver(mVolumeObserver);
397         mReceiver.setListening(false);
398         if (hasAudioProductStrategies()) {
399             unregisterVolumeGroupCb();
400         }
401         mSeekBar.setOnSeekBarChangeListener(null);
402         mHandler.getLooper().quitSafely();
403         mHandler = null;
404         mVolumeObserver = null;
405     }
406 
start()407     public void start() {
408         if (mHandler != null) return;  // already started
409         HandlerThread thread = new HandlerThread(TAG + ".CallbackHandler");
410         thread.start();
411         mHandler = new Handler(thread.getLooper(), this);
412         mHandler.sendEmptyMessage(MSG_INIT_SAMPLE);
413         mVolumeObserver = new Observer(mHandler);
414         mContext.getContentResolver().registerContentObserver(
415                 System.getUriFor(System.VOLUME_SETTINGS_INT[mStreamType]),
416                 false, mVolumeObserver);
417         mReceiver.setListening(true);
418         if (hasAudioProductStrategies()) {
419             registerVolumeGroupCb();
420         }
421     }
422 
revertVolume()423     public void revertVolume() {
424         mAudioManager.setStreamVolume(mStreamType, mOriginalStreamVolume, 0);
425     }
426 
onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch)427     public void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) {
428         if (fromTouch) {
429             postSetVolume(progress);
430         }
431         if (mCallback != null) {
432             mCallback.onProgressChanged(seekBar, progress, fromTouch);
433         }
434     }
435 
postSetVolume(int progress)436     private void postSetVolume(int progress) {
437         if (mHandler == null) return;
438         // Do the volume changing separately to give responsive UI
439         mLastProgress = progress;
440         mHandler.removeMessages(MSG_SET_STREAM_VOLUME);
441         mHandler.removeMessages(MSG_START_SAMPLE);
442         mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SET_STREAM_VOLUME),
443                 isDelay() ? SET_STREAM_VOLUME_DELAY_MS : 0);
444     }
445 
onStartTrackingTouch(SeekBar seekBar)446     public void onStartTrackingTouch(SeekBar seekBar) {
447         if (mCallback != null) {
448             mCallback.onStartTrackingTouch(this);
449         }
450     }
451 
onStopTrackingTouch(SeekBar seekBar)452     public void onStopTrackingTouch(SeekBar seekBar) {
453         postStartSample();
454     }
455 
isSamplePlaying()456     public boolean isSamplePlaying() {
457         synchronized (this) {
458             return mRingtone != null && mRingtone.isPlaying();
459         }
460     }
461 
startSample()462     public void startSample() {
463         postStartSample();
464     }
465 
stopSample()466     public void stopSample() {
467         postStopSample();
468     }
469 
getSeekBar()470     public SeekBar getSeekBar() {
471         return mSeekBar;
472     }
473 
changeVolumeBy(int amount)474     public void changeVolumeBy(int amount) {
475         mSeekBar.incrementProgressBy(amount);
476         postSetVolume(mSeekBar.getProgress());
477         postStartSample();
478         mVolumeBeforeMute = -1;
479     }
480 
muteVolume()481     public void muteVolume() {
482         if (mVolumeBeforeMute != -1) {
483             mSeekBar.setProgress(mVolumeBeforeMute, true);
484             postSetVolume(mVolumeBeforeMute);
485             postStartSample();
486             mVolumeBeforeMute = -1;
487         } else {
488             mVolumeBeforeMute = mSeekBar.getProgress();
489             mSeekBar.setProgress(0, true);
490             postStopSample();
491             postSetVolume(0);
492         }
493     }
494 
onSaveInstanceState(VolumeStore volumeStore)495     public void onSaveInstanceState(VolumeStore volumeStore) {
496         if (mLastProgress >= 0) {
497             volumeStore.volume = mLastProgress;
498             volumeStore.originalVolume = mOriginalStreamVolume;
499         }
500     }
501 
onRestoreInstanceState(VolumeStore volumeStore)502     public void onRestoreInstanceState(VolumeStore volumeStore) {
503         if (volumeStore.volume != -1) {
504             mOriginalStreamVolume = volumeStore.originalVolume;
505             mLastProgress = volumeStore.volume;
506             postSetVolume(mLastProgress);
507         }
508     }
509 
510     private final class H extends Handler {
511         private static final int UPDATE_SLIDER = 1;
512 
513         @Override
handleMessage(Message msg)514         public void handleMessage(Message msg) {
515             if (msg.what == UPDATE_SLIDER) {
516                 if (mSeekBar != null) {
517                     mLastProgress = msg.arg1;
518                     mLastAudibleStreamVolume = msg.arg2;
519                     final boolean muted = ((Boolean)msg.obj).booleanValue();
520                     if (muted != mMuted) {
521                         mMuted = muted;
522                         if (mCallback != null) {
523                             mCallback.onMuted(mMuted, isZenMuted());
524                         }
525                     }
526                     updateSeekBar();
527                 }
528             }
529         }
530 
postUpdateSlider(int volume, int lastAudibleVolume, boolean mute)531         public void postUpdateSlider(int volume, int lastAudibleVolume, boolean mute) {
532             obtainMessage(UPDATE_SLIDER, volume, lastAudibleVolume, new Boolean(mute)).sendToTarget();
533         }
534     }
535 
updateSlider()536     private void updateSlider() {
537         if (mSeekBar != null && mAudioManager != null) {
538             final int volume = mAudioManager.getStreamVolume(mStreamType);
539             final int lastAudibleVolume = mAudioManager.getLastAudibleStreamVolume(mStreamType);
540             final boolean mute = mAudioManager.isStreamMute(mStreamType);
541             mUiHandler.postUpdateSlider(volume, lastAudibleVolume, mute);
542         }
543     }
544 
545     private final class Observer extends ContentObserver {
Observer(Handler handler)546         public Observer(Handler handler) {
547             super(handler);
548         }
549 
550         @Override
onChange(boolean selfChange)551         public void onChange(boolean selfChange) {
552             super.onChange(selfChange);
553             updateSlider();
554         }
555     }
556 
557     private final class Receiver extends BroadcastReceiver {
558         private boolean mListening;
559 
setListening(boolean listening)560         public void setListening(boolean listening) {
561             if (mListening == listening) return;
562             mListening = listening;
563             if (listening) {
564                 final IntentFilter filter = new IntentFilter(AudioManager.VOLUME_CHANGED_ACTION);
565                 filter.addAction(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION);
566                 filter.addAction(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED);
567                 filter.addAction(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED);
568                 filter.addAction(AudioManager.STREAM_DEVICES_CHANGED_ACTION);
569                 mContext.registerReceiver(this, filter);
570             } else {
571                 mContext.unregisterReceiver(this);
572             }
573         }
574 
575         @Override
onReceive(Context context, Intent intent)576         public void onReceive(Context context, Intent intent) {
577             final String action = intent.getAction();
578             if (AudioManager.VOLUME_CHANGED_ACTION.equals(action)) {
579                 int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1);
580                 int streamValue = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, -1);
581                 if (hasAudioProductStrategies() && !isDelay()) {
582                     updateVolumeSlider(streamType, streamValue);
583                 }
584             } else if (AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION.equals(action)) {
585                 if (mNotificationOrRing) {
586                     mRingerMode = mAudioManager.getRingerModeInternal();
587                 }
588                 if (mAffectedByRingerMode) {
589                     updateSlider();
590                 }
591             } else if (AudioManager.STREAM_DEVICES_CHANGED_ACTION.equals(action)) {
592                 int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1);
593                 if (hasAudioProductStrategies() && !isDelay()) {
594                     int streamVolume = mAudioManager.getStreamVolume(streamType);
595                     updateVolumeSlider(streamType, streamVolume);
596                 } else {
597                     int volumeGroup = getVolumeGroupIdForLegacyStreamType(streamType);
598                     if (volumeGroup != AudioVolumeGroup.DEFAULT_VOLUME_GROUP
599                             && volumeGroup == mVolumeGroupId) {
600                         int streamVolume = mAudioManager.getStreamVolume(streamType);
601                         if (!isDelay()) {
602                             updateVolumeSlider(streamType, streamVolume);
603                         }
604                     }
605                 }
606             } else if (NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED.equals(action)) {
607                 mZenMode = mNotificationManager.getZenMode();
608                 updateSlider();
609             } else if (NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED.equals(action)) {
610                 mNotificationPolicy = mNotificationManager.getConsolidatedNotificationPolicy();
611                 mAllowAlarms = (mNotificationPolicy.priorityCategories & NotificationManager.Policy
612                         .PRIORITY_CATEGORY_ALARMS) != 0;
613                 mAllowMedia = (mNotificationPolicy.priorityCategories
614                         & NotificationManager.Policy.PRIORITY_CATEGORY_MEDIA) != 0;
615                 mAllowRinger = !ZenModeConfig.areAllPriorityOnlyRingerSoundsMuted(
616                         mNotificationPolicy);
617                 updateSlider();
618             }
619         }
620 
updateVolumeSlider(int streamType, int streamValue)621         private void updateVolumeSlider(int streamType, int streamValue) {
622             final boolean streamMatch = mNotificationOrRing ? isNotificationOrRing(streamType)
623                     : (streamType == mStreamType);
624             if (mSeekBar != null && streamMatch && streamValue != -1) {
625                 final boolean muted = mAudioManager.isStreamMute(mStreamType)
626                         || streamValue == 0;
627                 mUiHandler.postUpdateSlider(streamValue, mLastAudibleStreamVolume, muted);
628             }
629         }
630     }
631 
registerVolumeGroupCb()632     private void registerVolumeGroupCb() {
633         if (mVolumeGroupId != AudioVolumeGroup.DEFAULT_VOLUME_GROUP) {
634             mAudioManager.registerVolumeGroupCallback(Runnable::run, mVolumeGroupCallback);
635             updateSlider();
636         }
637     }
638 
unregisterVolumeGroupCb()639     private void unregisterVolumeGroupCb() {
640         if (mVolumeGroupId != AudioVolumeGroup.DEFAULT_VOLUME_GROUP) {
641             mAudioManager.unregisterVolumeGroupCallback(mVolumeGroupCallback);
642         }
643     }
644 
645     private class VolumeHandler extends Handler {
646         @Override
handleMessage(Message msg)647         public void handleMessage(Message msg) {
648             SomeArgs args = (SomeArgs) msg.obj;
649             switch (msg.what) {
650                 case MSG_GROUP_VOLUME_CHANGED:
651                     int group = (int) args.arg1;
652                     if (mVolumeGroupId != group
653                             || mVolumeGroupId == AudioVolumeGroup.DEFAULT_VOLUME_GROUP) {
654                         return;
655                     }
656                     updateSlider();
657                     break;
658             }
659         }
660     }
661 }
662