174a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock/* 274a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock * Copyright (C) 2014 The Android Open Source Project 374a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock * 474a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock * Licensed under the Apache License, Version 2.0 (the "License"); 574a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock * you may not use this file except in compliance with the License. 674a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock * You may obtain a copy of the License at 774a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock * 874a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock * http://www.apache.org/licenses/LICENSE-2.0 974a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock * 1074a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock * Unless required by applicable law or agreed to in writing, software 1174a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock * distributed under the License is distributed on an "AS IS" BASIS, 1274a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1374a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock * See the License for the specific language governing permissions and 1474a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock * limitations under the License. 1574a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock */ 1674a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock 1774a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlockpackage android.preference; 1874a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock 1996d4a9ec394975818b073b537ccb6220ef0949baJohn Spurlockimport android.app.NotificationManager; 200dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlockimport android.content.BroadcastReceiver; 2174a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlockimport android.content.Context; 220dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlockimport android.content.Intent; 230dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlockimport android.content.IntentFilter; 2474a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlockimport android.database.ContentObserver; 25bbfd31a5d4f126167e20fa8bd256c810cf8c2c85John Spurlockimport android.media.AudioAttributes; 2674a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlockimport android.media.AudioManager; 2774a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlockimport android.media.Ringtone; 2874a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlockimport android.media.RingtoneManager; 2974a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlockimport android.net.Uri; 3074a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlockimport android.os.Handler; 3174a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlockimport android.os.HandlerThread; 3274a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlockimport android.os.Message; 3374a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlockimport android.preference.VolumePreference.VolumeStore; 3474a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlockimport android.provider.Settings; 3596d4a9ec394975818b073b537ccb6220ef0949baJohn Spurlockimport android.provider.Settings.Global; 3674a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlockimport android.provider.Settings.System; 3774a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlockimport android.util.Log; 3874a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlockimport android.widget.SeekBar; 3974a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlockimport android.widget.SeekBar.OnSeekBarChangeListener; 4074a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock 4174a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock/** 4274a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock * Turns a {@link SeekBar} into a volume control. 4374a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock * @hide 4474a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock */ 4574a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlockpublic class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callback { 4695caba127051845ff1e26d7e64909db89408e8e7John Spurlock private static final String TAG = "SeekBarVolumizer"; 4774a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock 4874a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock public interface Callback { 4974a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock void onSampleStarting(SeekBarVolumizer sbv); 50bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch); 5196d4a9ec394975818b073b537ccb6220ef0949baJohn Spurlock void onMuted(boolean muted, boolean zenMuted); 5274a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock } 5374a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock 5495caba127051845ff1e26d7e64909db89408e8e7John Spurlock private final Context mContext; 550dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock private final H mUiHandler = new H(); 5674a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock private final Callback mCallback; 5795caba127051845ff1e26d7e64909db89408e8e7John Spurlock private final Uri mDefaultUri; 5895caba127051845ff1e26d7e64909db89408e8e7John Spurlock private final AudioManager mAudioManager; 5996d4a9ec394975818b073b537ccb6220ef0949baJohn Spurlock private final NotificationManager mNotificationManager; 6095caba127051845ff1e26d7e64909db89408e8e7John Spurlock private final int mStreamType; 6195caba127051845ff1e26d7e64909db89408e8e7John Spurlock private final int mMaxStreamVolume; 62bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock private boolean mAffectedByRingerMode; 63bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock private boolean mNotificationOrRing; 640dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock private final Receiver mReceiver = new Receiver(); 6574a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock 660e588ea8e1746f3335b2b5c8a51fdd9a96167b59John Spurlock private Handler mHandler; 670e588ea8e1746f3335b2b5c8a51fdd9a96167b59John Spurlock private Observer mVolumeObserver; 6874a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock private int mOriginalStreamVolume; 6996d4a9ec394975818b073b537ccb6220ef0949baJohn Spurlock private int mLastAudibleStreamVolume; 7074a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock private Ringtone mRingtone; 7174a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock private int mLastProgress = -1; 72bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock private boolean mMuted; 7374a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock private SeekBar mSeekBar; 7474a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock private int mVolumeBeforeMute = -1; 75bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock private int mRingerMode; 7696d4a9ec394975818b073b537ccb6220ef0949baJohn Spurlock private int mZenMode; 7774a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock 7874a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock private static final int MSG_SET_STREAM_VOLUME = 0; 7974a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock private static final int MSG_START_SAMPLE = 1; 8074a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock private static final int MSG_STOP_SAMPLE = 2; 8195caba127051845ff1e26d7e64909db89408e8e7John Spurlock private static final int MSG_INIT_SAMPLE = 3; 8274a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock private static final int CHECK_RINGTONE_PLAYBACK_DELAY_MS = 1000; 8374a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock 84bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock public SeekBarVolumizer(Context context, int streamType, Uri defaultUri, Callback callback) { 8574a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock mContext = context; 8696d4a9ec394975818b073b537ccb6220ef0949baJohn Spurlock mAudioManager = context.getSystemService(AudioManager.class); 8796d4a9ec394975818b073b537ccb6220ef0949baJohn Spurlock mNotificationManager = context.getSystemService(NotificationManager.class); 8874a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock mStreamType = streamType; 89bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock mAffectedByRingerMode = mAudioManager.isStreamAffectedByRingerMode(mStreamType); 90bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock mNotificationOrRing = isNotificationOrRing(mStreamType); 91bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock if (mNotificationOrRing) { 92bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock mRingerMode = mAudioManager.getRingerModeInternal(); 93bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock } 9496d4a9ec394975818b073b537ccb6220ef0949baJohn Spurlock mZenMode = mNotificationManager.getZenMode(); 9595caba127051845ff1e26d7e64909db89408e8e7John Spurlock mMaxStreamVolume = mAudioManager.getStreamMaxVolume(mStreamType); 9674a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock mCallback = callback; 9774a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock mOriginalStreamVolume = mAudioManager.getStreamVolume(mStreamType); 9896d4a9ec394975818b073b537ccb6220ef0949baJohn Spurlock mLastAudibleStreamVolume = mAudioManager.getLastAudibleStreamVolume(mStreamType); 99bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock mMuted = mAudioManager.isStreamMute(mStreamType); 100bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock if (mCallback != null) { 10196d4a9ec394975818b073b537ccb6220ef0949baJohn Spurlock mCallback.onMuted(mMuted, isZenMuted()); 102bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock } 10374a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock if (defaultUri == null) { 10474a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock if (mStreamType == AudioManager.STREAM_RING) { 10574a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock defaultUri = Settings.System.DEFAULT_RINGTONE_URI; 10674a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock } else if (mStreamType == AudioManager.STREAM_NOTIFICATION) { 10774a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock defaultUri = Settings.System.DEFAULT_NOTIFICATION_URI; 10874a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock } else { 10974a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock defaultUri = Settings.System.DEFAULT_ALARM_ALERT_URI; 11074a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock } 11174a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock } 11295caba127051845ff1e26d7e64909db89408e8e7John Spurlock mDefaultUri = defaultUri; 11395caba127051845ff1e26d7e64909db89408e8e7John Spurlock } 11474a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock 115bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock private static boolean isNotificationOrRing(int stream) { 116bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock return stream == AudioManager.STREAM_RING || stream == AudioManager.STREAM_NOTIFICATION; 117bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock } 118bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock 11995caba127051845ff1e26d7e64909db89408e8e7John Spurlock public void setSeekBar(SeekBar seekBar) { 1200dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock if (mSeekBar != null) { 1210dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock mSeekBar.setOnSeekBarChangeListener(null); 1220dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock } 12395caba127051845ff1e26d7e64909db89408e8e7John Spurlock mSeekBar = seekBar; 12495caba127051845ff1e26d7e64909db89408e8e7John Spurlock mSeekBar.setOnSeekBarChangeListener(null); 12595caba127051845ff1e26d7e64909db89408e8e7John Spurlock mSeekBar.setMax(mMaxStreamVolume); 126bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock updateSeekBar(); 12795caba127051845ff1e26d7e64909db89408e8e7John Spurlock mSeekBar.setOnSeekBarChangeListener(this); 12874a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock } 12974a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock 13096d4a9ec394975818b073b537ccb6220ef0949baJohn Spurlock private boolean isZenMuted() { 13196d4a9ec394975818b073b537ccb6220ef0949baJohn Spurlock return mNotificationOrRing && mZenMode == Global.ZEN_MODE_ALARMS 13296d4a9ec394975818b073b537ccb6220ef0949baJohn Spurlock || mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS; 13396d4a9ec394975818b073b537ccb6220ef0949baJohn Spurlock } 13496d4a9ec394975818b073b537ccb6220ef0949baJohn Spurlock 135bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock protected void updateSeekBar() { 13696d4a9ec394975818b073b537ccb6220ef0949baJohn Spurlock final boolean zenMuted = isZenMuted(); 13796d4a9ec394975818b073b537ccb6220ef0949baJohn Spurlock mSeekBar.setEnabled(!zenMuted); 13896d4a9ec394975818b073b537ccb6220ef0949baJohn Spurlock if (zenMuted) { 13996d4a9ec394975818b073b537ccb6220ef0949baJohn Spurlock mSeekBar.setProgress(mLastAudibleStreamVolume); 14096d4a9ec394975818b073b537ccb6220ef0949baJohn Spurlock } else if (mNotificationOrRing && mRingerMode == AudioManager.RINGER_MODE_VIBRATE) { 141bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock mSeekBar.setProgress(0); 142bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock } else if (mMuted) { 143bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock mSeekBar.setProgress(0); 144bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock } else { 145bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock mSeekBar.setProgress(mLastProgress > -1 ? mLastProgress : mOriginalStreamVolume); 146bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock } 147bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock } 148bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock 14974a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock @Override 15074a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock public boolean handleMessage(Message msg) { 15174a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock switch (msg.what) { 15274a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock case MSG_SET_STREAM_VOLUME: 153721d457685cc83785d0d0aad259e3218af899fc9John Spurlock if (mMuted && mLastProgress > 0) { 154721d457685cc83785d0d0aad259e3218af899fc9John Spurlock mAudioManager.adjustStreamVolume(mStreamType, AudioManager.ADJUST_UNMUTE, 0); 155721d457685cc83785d0d0aad259e3218af899fc9John Spurlock } else if (!mMuted && mLastProgress == 0) { 156721d457685cc83785d0d0aad259e3218af899fc9John Spurlock mAudioManager.adjustStreamVolume(mStreamType, AudioManager.ADJUST_MUTE, 0); 157721d457685cc83785d0d0aad259e3218af899fc9John Spurlock } 158351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock mAudioManager.setStreamVolume(mStreamType, mLastProgress, 159351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock AudioManager.FLAG_SHOW_UI_WARNINGS); 16074a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock break; 16174a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock case MSG_START_SAMPLE: 16274a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock onStartSample(); 16374a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock break; 16474a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock case MSG_STOP_SAMPLE: 16574a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock onStopSample(); 16674a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock break; 16795caba127051845ff1e26d7e64909db89408e8e7John Spurlock case MSG_INIT_SAMPLE: 16895caba127051845ff1e26d7e64909db89408e8e7John Spurlock onInitSample(); 16995caba127051845ff1e26d7e64909db89408e8e7John Spurlock break; 17074a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock default: 17195caba127051845ff1e26d7e64909db89408e8e7John Spurlock Log.e(TAG, "invalid SeekBarVolumizer message: "+msg.what); 17274a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock } 17374a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock return true; 17474a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock } 17574a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock 17695caba127051845ff1e26d7e64909db89408e8e7John Spurlock private void onInitSample() { 17795caba127051845ff1e26d7e64909db89408e8e7John Spurlock mRingtone = RingtoneManager.getRingtone(mContext, mDefaultUri); 17895caba127051845ff1e26d7e64909db89408e8e7John Spurlock if (mRingtone != null) { 17995caba127051845ff1e26d7e64909db89408e8e7John Spurlock mRingtone.setStreamType(mStreamType); 18095caba127051845ff1e26d7e64909db89408e8e7John Spurlock } 18195caba127051845ff1e26d7e64909db89408e8e7John Spurlock } 18295caba127051845ff1e26d7e64909db89408e8e7John Spurlock 18374a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock private void postStartSample() { 184735f9ebc188e1cb225533e1f5f9ef925d1f0b20eJohn Spurlock if (mHandler == null) return; 18574a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock mHandler.removeMessages(MSG_START_SAMPLE); 18674a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_START_SAMPLE), 18774a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock isSamplePlaying() ? CHECK_RINGTONE_PLAYBACK_DELAY_MS : 0); 18874a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock } 18974a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock 19074a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock private void onStartSample() { 19174a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock if (!isSamplePlaying()) { 19274a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock if (mCallback != null) { 19374a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock mCallback.onSampleStarting(this); 19474a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock } 19574a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock if (mRingtone != null) { 1960dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock try { 197bbfd31a5d4f126167e20fa8bd256c810cf8c2c85John Spurlock mRingtone.setAudioAttributes(new AudioAttributes.Builder(mRingtone 198bbfd31a5d4f126167e20fa8bd256c810cf8c2c85John Spurlock .getAudioAttributes()) 199bbfd31a5d4f126167e20fa8bd256c810cf8c2c85John Spurlock .setFlags(AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY | 200bbfd31a5d4f126167e20fa8bd256c810cf8c2c85John Spurlock AudioAttributes.FLAG_BYPASS_MUTE) 201bbfd31a5d4f126167e20fa8bd256c810cf8c2c85John Spurlock .build()); 2020dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock mRingtone.play(); 2030dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock } catch (Throwable e) { 2040dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock Log.w(TAG, "Error playing ringtone, stream " + mStreamType, e); 2050dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock } 20674a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock } 20774a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock } 20874a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock } 20974a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock 210735f9ebc188e1cb225533e1f5f9ef925d1f0b20eJohn Spurlock private void postStopSample() { 211735f9ebc188e1cb225533e1f5f9ef925d1f0b20eJohn Spurlock if (mHandler == null) return; 21274a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock // remove pending delayed start messages 21374a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock mHandler.removeMessages(MSG_START_SAMPLE); 21474a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock mHandler.removeMessages(MSG_STOP_SAMPLE); 21574a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock mHandler.sendMessage(mHandler.obtainMessage(MSG_STOP_SAMPLE)); 21674a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock } 21774a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock 21874a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock private void onStopSample() { 21974a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock if (mRingtone != null) { 22074a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock mRingtone.stop(); 22174a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock } 22274a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock } 22374a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock 22474a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock public void stop() { 2250e588ea8e1746f3335b2b5c8a51fdd9a96167b59John Spurlock if (mHandler == null) return; // already stopped 22674a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock postStopSample(); 22774a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock mContext.getContentResolver().unregisterContentObserver(mVolumeObserver); 2280dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock mReceiver.setListening(false); 2290e588ea8e1746f3335b2b5c8a51fdd9a96167b59John Spurlock mSeekBar.setOnSeekBarChangeListener(null); 2300dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock mHandler.getLooper().quitSafely(); 2310e588ea8e1746f3335b2b5c8a51fdd9a96167b59John Spurlock mHandler = null; 2320e588ea8e1746f3335b2b5c8a51fdd9a96167b59John Spurlock mVolumeObserver = null; 2330e588ea8e1746f3335b2b5c8a51fdd9a96167b59John Spurlock } 2340e588ea8e1746f3335b2b5c8a51fdd9a96167b59John Spurlock 2350e588ea8e1746f3335b2b5c8a51fdd9a96167b59John Spurlock public void start() { 2360e588ea8e1746f3335b2b5c8a51fdd9a96167b59John Spurlock if (mHandler != null) return; // already started 2370e588ea8e1746f3335b2b5c8a51fdd9a96167b59John Spurlock HandlerThread thread = new HandlerThread(TAG + ".CallbackHandler"); 2380e588ea8e1746f3335b2b5c8a51fdd9a96167b59John Spurlock thread.start(); 2390e588ea8e1746f3335b2b5c8a51fdd9a96167b59John Spurlock mHandler = new Handler(thread.getLooper(), this); 2400e588ea8e1746f3335b2b5c8a51fdd9a96167b59John Spurlock mHandler.sendEmptyMessage(MSG_INIT_SAMPLE); 2410e588ea8e1746f3335b2b5c8a51fdd9a96167b59John Spurlock mVolumeObserver = new Observer(mHandler); 2420e588ea8e1746f3335b2b5c8a51fdd9a96167b59John Spurlock mContext.getContentResolver().registerContentObserver( 2430e588ea8e1746f3335b2b5c8a51fdd9a96167b59John Spurlock System.getUriFor(System.VOLUME_SETTINGS[mStreamType]), 2440e588ea8e1746f3335b2b5c8a51fdd9a96167b59John Spurlock false, mVolumeObserver); 2450e588ea8e1746f3335b2b5c8a51fdd9a96167b59John Spurlock mReceiver.setListening(true); 24674a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock } 24774a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock 24874a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock public void revertVolume() { 24974a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock mAudioManager.setStreamVolume(mStreamType, mOriginalStreamVolume, 0); 25074a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock } 25174a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock 252bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock public void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) { 253bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock if (fromTouch) { 254bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock postSetVolume(progress); 255bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock } 256bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock if (mCallback != null) { 257bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock mCallback.onProgressChanged(seekBar, progress, fromTouch); 25874a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock } 25974a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock } 26074a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock 261735f9ebc188e1cb225533e1f5f9ef925d1f0b20eJohn Spurlock private void postSetVolume(int progress) { 262735f9ebc188e1cb225533e1f5f9ef925d1f0b20eJohn Spurlock if (mHandler == null) return; 26374a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock // Do the volume changing separately to give responsive UI 26474a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock mLastProgress = progress; 26574a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock mHandler.removeMessages(MSG_SET_STREAM_VOLUME); 26674a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock mHandler.sendMessage(mHandler.obtainMessage(MSG_SET_STREAM_VOLUME)); 26774a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock } 26874a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock 26974a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock public void onStartTrackingTouch(SeekBar seekBar) { 27074a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock } 27174a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock 27274a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock public void onStopTrackingTouch(SeekBar seekBar) { 27374a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock postStartSample(); 27474a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock } 27574a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock 27674a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock public boolean isSamplePlaying() { 27774a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock return mRingtone != null && mRingtone.isPlaying(); 27874a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock } 27974a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock 28074a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock public void startSample() { 28174a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock postStartSample(); 28274a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock } 28374a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock 28474a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock public void stopSample() { 28574a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock postStopSample(); 28674a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock } 28774a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock 28874a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock public SeekBar getSeekBar() { 28974a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock return mSeekBar; 29074a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock } 29174a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock 29274a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock public void changeVolumeBy(int amount) { 29374a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock mSeekBar.incrementProgressBy(amount); 29474a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock postSetVolume(mSeekBar.getProgress()); 29574a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock postStartSample(); 29674a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock mVolumeBeforeMute = -1; 29774a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock } 29874a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock 29974a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock public void muteVolume() { 30074a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock if (mVolumeBeforeMute != -1) { 30174a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock mSeekBar.setProgress(mVolumeBeforeMute); 30274a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock postSetVolume(mVolumeBeforeMute); 30374a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock postStartSample(); 30474a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock mVolumeBeforeMute = -1; 30574a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock } else { 30674a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock mVolumeBeforeMute = mSeekBar.getProgress(); 30774a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock mSeekBar.setProgress(0); 30874a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock postStopSample(); 30974a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock postSetVolume(0); 31074a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock } 31174a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock } 31274a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock 31374a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock public void onSaveInstanceState(VolumeStore volumeStore) { 31474a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock if (mLastProgress >= 0) { 31574a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock volumeStore.volume = mLastProgress; 31674a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock volumeStore.originalVolume = mOriginalStreamVolume; 31774a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock } 31874a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock } 31974a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock 32074a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock public void onRestoreInstanceState(VolumeStore volumeStore) { 32174a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock if (volumeStore.volume != -1) { 32274a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock mOriginalStreamVolume = volumeStore.originalVolume; 32374a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock mLastProgress = volumeStore.volume; 32474a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock postSetVolume(mLastProgress); 32574a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock } 32674a2e06d831432f27ebd17cf6f1d0086356e7ee0John Spurlock } 3270dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock 3280dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock private final class H extends Handler { 3290dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock private static final int UPDATE_SLIDER = 1; 3300dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock 3310dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock @Override 3320dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock public void handleMessage(Message msg) { 3330dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock if (msg.what == UPDATE_SLIDER) { 3340dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock if (mSeekBar != null) { 335bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock mLastProgress = msg.arg1; 33696d4a9ec394975818b073b537ccb6220ef0949baJohn Spurlock mLastAudibleStreamVolume = Math.abs(msg.arg2); 33796d4a9ec394975818b073b537ccb6220ef0949baJohn Spurlock final boolean muted = msg.arg2 < 0; 338bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock if (muted != mMuted) { 339bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock mMuted = muted; 340bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock if (mCallback != null) { 34196d4a9ec394975818b073b537ccb6220ef0949baJohn Spurlock mCallback.onMuted(mMuted, isZenMuted()); 342bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock } 343bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock } 344bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock updateSeekBar(); 3450dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock } 3460dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock } 3470dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock } 3480dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock 34996d4a9ec394975818b073b537ccb6220ef0949baJohn Spurlock public void postUpdateSlider(int volume, int lastAudibleVolume, boolean mute) { 35096d4a9ec394975818b073b537ccb6220ef0949baJohn Spurlock final int arg2 = lastAudibleVolume * (mute ? -1 : 1); 35196d4a9ec394975818b073b537ccb6220ef0949baJohn Spurlock obtainMessage(UPDATE_SLIDER, volume, arg2).sendToTarget(); 352bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock } 353bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock } 354bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock 355bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock private void updateSlider() { 356bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock if (mSeekBar != null && mAudioManager != null) { 357bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock final int volume = mAudioManager.getStreamVolume(mStreamType); 35896d4a9ec394975818b073b537ccb6220ef0949baJohn Spurlock final int lastAudibleVolume = mAudioManager.getLastAudibleStreamVolume(mStreamType); 359bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock final boolean mute = mAudioManager.isStreamMute(mStreamType); 36096d4a9ec394975818b073b537ccb6220ef0949baJohn Spurlock mUiHandler.postUpdateSlider(volume, lastAudibleVolume, mute); 3610dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock } 3620dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock } 3630dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock 3640dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock private final class Observer extends ContentObserver { 3650dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock public Observer(Handler handler) { 3660dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock super(handler); 3670dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock } 3680dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock 3690dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock @Override 3700dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock public void onChange(boolean selfChange) { 3710dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock super.onChange(selfChange); 372bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock updateSlider(); 3730dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock } 3740dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock } 3750dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock 3760dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock private final class Receiver extends BroadcastReceiver { 3770dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock private boolean mListening; 3780dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock 3790dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock public void setListening(boolean listening) { 3800dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock if (mListening == listening) return; 3810dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock mListening = listening; 3820dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock if (listening) { 3830dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock final IntentFilter filter = new IntentFilter(AudioManager.VOLUME_CHANGED_ACTION); 384bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock filter.addAction(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION); 38596d4a9ec394975818b073b537ccb6220ef0949baJohn Spurlock filter.addAction(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED); 3860dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock mContext.registerReceiver(this, filter); 3870dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock } else { 3880dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock mContext.unregisterReceiver(this); 3890dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock } 3900dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock } 3910dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock 3920dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock @Override 3930dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock public void onReceive(Context context, Intent intent) { 394bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock final String action = intent.getAction(); 395bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock if (AudioManager.VOLUME_CHANGED_ACTION.equals(action)) { 396bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1); 397bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock int streamValue = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, -1); 398bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock final boolean streamMatch = mNotificationOrRing ? isNotificationOrRing(streamType) 399bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock : (streamType == mStreamType); 400bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock if (mSeekBar != null && streamMatch && streamValue != -1) { 401721d457685cc83785d0d0aad259e3218af899fc9John Spurlock final boolean muted = mAudioManager.isStreamMute(mStreamType) 402721d457685cc83785d0d0aad259e3218af899fc9John Spurlock || streamValue == 0; 40396d4a9ec394975818b073b537ccb6220ef0949baJohn Spurlock mUiHandler.postUpdateSlider(streamValue, mLastAudibleStreamVolume, muted); 404bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock } 405bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock } else if (AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION.equals(action)) { 406bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock if (mNotificationOrRing) { 407bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock mRingerMode = mAudioManager.getRingerModeInternal(); 408bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock } 409bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock if (mAffectedByRingerMode) { 410bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock updateSlider(); 411bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock } 41296d4a9ec394975818b073b537ccb6220ef0949baJohn Spurlock } else if (NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED.equals(action)) { 41396d4a9ec394975818b073b537ccb6220ef0949baJohn Spurlock mZenMode = mNotificationManager.getZenMode(); 41496d4a9ec394975818b073b537ccb6220ef0949baJohn Spurlock updateSlider(); 4150dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock } 4160dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock } 4170dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock } 4180dbf1a6be21bb8947aa716fc40c6e288178b1803John Spurlock} 419