diff --git a/core/java/android/preference/SeekBarVolumizer.java b/core/java/android/preference/SeekBarVolumizer.java index 0cdad9f8de934..400b312bb913f 100644 --- a/core/java/android/preference/SeekBarVolumizer.java +++ b/core/java/android/preference/SeekBarVolumizer.java @@ -46,6 +46,8 @@ import android.widget.SeekBar.OnSeekBarChangeListener; import com.android.internal.annotations.GuardedBy; import com.android.internal.os.SomeArgs; +import java.util.concurrent.TimeUnit; + /** * Turns a {@link SeekBar} into a volume control. * @hide @@ -64,9 +66,15 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba void onSampleStarting(SeekBarVolumizer sbv); void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch); void onMuted(boolean muted, boolean zenMuted); + /** + * Callback reporting that the seek bar is start tracking. + * @param sbv - The seek bar that start tracking + */ + void onStartTrackingTouch(SeekBarVolumizer sbv); } private static final int MSG_GROUP_VOLUME_CHANGED = 1; + private static long sStopVolumeTime = 0L; private final Handler mVolumeHandler = new VolumeHandler(); private AudioAttributes mAttributes; private int mVolumeGroupId; @@ -126,6 +134,9 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba private static final int MSG_STOP_SAMPLE = 2; private static final int MSG_INIT_SAMPLE = 3; private static final int CHECK_RINGTONE_PLAYBACK_DELAY_MS = 1000; + private static final long SET_STREAM_VOLUME_DELAY_MS = TimeUnit.MILLISECONDS.toMillis(500); + private static final long START_SAMPLE_DELAY_MS = TimeUnit.MILLISECONDS.toMillis(500); + private static final long DURATION_TO_START_DELAYING = TimeUnit.MILLISECONDS.toMillis(2000); private NotificationManager.Policy mNotificationPolicy; private boolean mAllowAlarms; @@ -314,7 +325,29 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba if (mHandler == null) return; mHandler.removeMessages(MSG_START_SAMPLE); mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_START_SAMPLE), - isSamplePlaying() ? CHECK_RINGTONE_PLAYBACK_DELAY_MS : 0); + isSamplePlaying() ? CHECK_RINGTONE_PLAYBACK_DELAY_MS + : isDelay() ? START_SAMPLE_DELAY_MS : 0); + } + + // After stop volume it needs to add a small delay when playing volume or set stream. + // It is because the call volume is from the earpiece and the alarm/ring/media + // is from the speaker. If play the alarm volume or set alarm stream right after stop + // call volume, the alarm volume on earpiece is returned then cause the volume value incorrect. + // It needs a small delay after stop call volume to get alarm volume on speaker. + // e.g. : If the ring volume has adjusted right after call volume stopped in 2 second + // then delay 0.5 second to set stream or play volume ringtone. + private boolean isDelay() { + final long durationTime = java.lang.System.currentTimeMillis() - sStopVolumeTime; + return durationTime >= 0 && durationTime < DURATION_TO_START_DELAYING; + } + + private void setStopVolumeTime() { + // set the time of stop volume + if ((mStreamType == AudioManager.STREAM_VOICE_CALL + || mStreamType == AudioManager.STREAM_RING + || mStreamType == AudioManager.STREAM_ALARM)) { + sStopVolumeTime = java.lang.System.currentTimeMillis(); + } } private void onStartSample() { @@ -341,6 +374,7 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba private void postStopSample() { if (mHandler == null) return; + setStopVolumeTime(); // remove pending delayed start messages mHandler.removeMessages(MSG_START_SAMPLE); mHandler.removeMessages(MSG_STOP_SAMPLE); @@ -404,10 +438,15 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba // Do the volume changing separately to give responsive UI mLastProgress = progress; mHandler.removeMessages(MSG_SET_STREAM_VOLUME); - mHandler.sendMessage(mHandler.obtainMessage(MSG_SET_STREAM_VOLUME)); + mHandler.removeMessages(MSG_START_SAMPLE); + mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SET_STREAM_VOLUME), + isDelay() ? SET_STREAM_VOLUME_DELAY_MS : 0); } public void onStartTrackingTouch(SeekBar seekBar) { + if (mCallback != null) { + mCallback.onStartTrackingTouch(this); + } } public void onStopTrackingTouch(SeekBar seekBar) { @@ -539,7 +578,7 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba if (AudioManager.VOLUME_CHANGED_ACTION.equals(action)) { int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1); int streamValue = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, -1); - if (hasAudioProductStrategies()) { + if (hasAudioProductStrategies() && !isDelay()) { updateVolumeSlider(streamType, streamValue); } } else if (AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION.equals(action)) { @@ -551,7 +590,7 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba } } else if (AudioManager.STREAM_DEVICES_CHANGED_ACTION.equals(action)) { int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1); - if (hasAudioProductStrategies()) { + if (hasAudioProductStrategies() && !isDelay()) { int streamVolume = mAudioManager.getStreamVolume(streamType); updateVolumeSlider(streamType, streamVolume); } else { @@ -559,7 +598,9 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba if (volumeGroup != AudioVolumeGroup.DEFAULT_VOLUME_GROUP && volumeGroup == mVolumeGroupId) { int streamVolume = mAudioManager.getStreamVolume(streamType); - updateVolumeSlider(streamType, streamVolume); + if (!isDelay()) { + updateVolumeSlider(streamType, streamVolume); + } } } } else if (NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED.equals(action)) { diff --git a/core/java/android/preference/VolumePreference.java b/core/java/android/preference/VolumePreference.java index 6eb524a3886cd..563bc463e5a30 100644 --- a/core/java/android/preference/VolumePreference.java +++ b/core/java/android/preference/VolumePreference.java @@ -175,6 +175,11 @@ public class VolumePreference extends SeekBarDialogPreference implements // noop } + @Override + public void onStartTrackingTouch(SeekBarVolumizer sbv) { + // noop + } + @Override protected Parcelable onSaveInstanceState() { final Parcelable superState = super.onSaveInstanceState();