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