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