181bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock/* 281bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock * Copyright (C) 2014 The Android Open Source Project 381bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock * 481bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock * Licensed under the Apache License, Version 2.0 (the "License"); 581bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock * you may not use this file except in compliance with the License. 681bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock * You may obtain a copy of the License at 781bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock * 881bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock * http://www.apache.org/licenses/LICENSE-2.0 981bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock * 1081bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock * Unless required by applicable law or agreed to in writing, software 1181bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock * distributed under the License is distributed on an "AS IS" BASIS, 1281bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1381bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock * See the License for the specific language governing permissions and 1481bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock * limitations under the License. 1581bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock */ 1681bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock 1781bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlockpackage com.android.settings.notification; 1881bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock 1981bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlockimport android.content.ContentResolver; 2081bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlockimport android.content.Context; 2181bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlockimport android.media.AudioManager; 2281bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlockimport android.net.Uri; 2381bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlockimport android.preference.SeekBarVolumizer; 24b7490bea28cb28d301fe4ec0275cef7129621206Doris Lingimport android.support.annotation.VisibleForTesting; 2539b467482d1bf256a111c757e9b7621c6f523271Jason Monkimport android.support.v7.preference.PreferenceViewHolder; 26fdebfc35c43c445afcd39077f5cbcf72902b1d6eJohn Spurlockimport android.text.TextUtils; 2781bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlockimport android.util.AttributeSet; 2881bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlockimport android.util.Log; 2981bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlockimport android.view.View; 30cb9f35171d14bec1af4bb313aac2e79ac2290facDan Sandlerimport android.widget.ImageView; 3181bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlockimport android.widget.SeekBar; 32fdebfc35c43c445afcd39077f5cbcf72902b1d6eJohn Spurlockimport android.widget.TextView; 3381bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock 3481bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlockimport com.android.settings.R; 35cbfe1eb881028d06aee9720634bbdbc4ef17e71aFan Zhangimport com.android.settings.widget.SeekBarPreference; 3681bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock 37fdebfc35c43c445afcd39077f5cbcf72902b1d6eJohn Spurlockimport java.util.Objects; 38fdebfc35c43c445afcd39077f5cbcf72902b1d6eJohn Spurlock 3981bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock/** A slider preference that directly controls an audio stream volume (no dialog) **/ 4039b467482d1bf256a111c757e9b7621c6f523271Jason Monkpublic class VolumeSeekBarPreference extends SeekBarPreference { 4181bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock private static final String TAG = "VolumeSeekBarPreference"; 4281bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock 4381bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock private int mStream; 4481bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock private SeekBar mSeekBar; 4581bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock private SeekBarVolumizer mVolumizer; 4681bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock private Callback mCallback; 47cb9f35171d14bec1af4bb313aac2e79ac2290facDan Sandler private ImageView mIconView; 48fdebfc35c43c445afcd39077f5cbcf72902b1d6eJohn Spurlock private TextView mSuppressionTextView; 49fdebfc35c43c445afcd39077f5cbcf72902b1d6eJohn Spurlock private String mSuppressionText; 50c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock private boolean mMuted; 51f82154de8c5274d41c6ae1cbd0170f9e20462a45John Spurlock private boolean mZenMuted; 52c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock private int mIconResId; 53c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock private int mMuteIconResId; 54aaaa54ec0eaf3b5d1a52161cd426caf13e2c364cJohn Spurlock private boolean mStopped; 55b7490bea28cb28d301fe4ec0275cef7129621206Doris Ling @VisibleForTesting 56b7490bea28cb28d301fe4ec0275cef7129621206Doris Ling AudioManager mAudioManager; 5781bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock 58dbaf080f44c72dcd08136c8b026c782696102df6Fabrice Di Meglio public VolumeSeekBarPreference(Context context, AttributeSet attrs, int defStyleAttr, 59dbaf080f44c72dcd08136c8b026c782696102df6Fabrice Di Meglio int defStyleRes) { 60dbaf080f44c72dcd08136c8b026c782696102df6Fabrice Di Meglio super(context, attrs, defStyleAttr, defStyleRes); 61fdebfc35c43c445afcd39077f5cbcf72902b1d6eJohn Spurlock setLayoutResource(R.layout.preference_volume_slider); 62b7490bea28cb28d301fe4ec0275cef7129621206Doris Ling mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); 63dbaf080f44c72dcd08136c8b026c782696102df6Fabrice Di Meglio } 64dbaf080f44c72dcd08136c8b026c782696102df6Fabrice Di Meglio 65dbaf080f44c72dcd08136c8b026c782696102df6Fabrice Di Meglio public VolumeSeekBarPreference(Context context, AttributeSet attrs, int defStyleAttr) { 66bfb006aa323ea66f81d8f00f6b0081668f6b4fc9Fan Zhang super(context, attrs, defStyleAttr); 67bfb006aa323ea66f81d8f00f6b0081668f6b4fc9Fan Zhang setLayoutResource(R.layout.preference_volume_slider); 68b7490bea28cb28d301fe4ec0275cef7129621206Doris Ling mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); 69dbaf080f44c72dcd08136c8b026c782696102df6Fabrice Di Meglio } 70dbaf080f44c72dcd08136c8b026c782696102df6Fabrice Di Meglio 7181bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock public VolumeSeekBarPreference(Context context, AttributeSet attrs) { 72bfb006aa323ea66f81d8f00f6b0081668f6b4fc9Fan Zhang super(context, attrs); 73bfb006aa323ea66f81d8f00f6b0081668f6b4fc9Fan Zhang setLayoutResource(R.layout.preference_volume_slider); 74b7490bea28cb28d301fe4ec0275cef7129621206Doris Ling mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); 75dbaf080f44c72dcd08136c8b026c782696102df6Fabrice Di Meglio } 76dbaf080f44c72dcd08136c8b026c782696102df6Fabrice Di Meglio 77dbaf080f44c72dcd08136c8b026c782696102df6Fabrice Di Meglio public VolumeSeekBarPreference(Context context) { 78bfb006aa323ea66f81d8f00f6b0081668f6b4fc9Fan Zhang super(context); 79bfb006aa323ea66f81d8f00f6b0081668f6b4fc9Fan Zhang setLayoutResource(R.layout.preference_volume_slider); 80b7490bea28cb28d301fe4ec0275cef7129621206Doris Ling mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); 8181bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock } 8281bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock 8381bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock public void setStream(int stream) { 8481bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock mStream = stream; 85b7490bea28cb28d301fe4ec0275cef7129621206Doris Ling setMax(mAudioManager.getStreamMaxVolume(mStream)); 86156fd91fbd1ae1eb601a51432a13767fb244669eryanywlin // Use getStreamMinVolumeInt for non-public stream type 87156fd91fbd1ae1eb601a51432a13767fb244669eryanywlin // eg: AudioManager.STREAM_BLUETOOTH_SCO 88156fd91fbd1ae1eb601a51432a13767fb244669eryanywlin setMin(mAudioManager.getStreamMinVolumeInt(mStream)); 89b7490bea28cb28d301fe4ec0275cef7129621206Doris Ling setProgress(mAudioManager.getStreamVolume(mStream)); 9081bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock } 9181bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock 9281bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock public void setCallback(Callback callback) { 9381bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock mCallback = callback; 9481bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock } 9581bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock 96aaaa54ec0eaf3b5d1a52161cd426caf13e2c364cJohn Spurlock public void onActivityResume() { 97aaaa54ec0eaf3b5d1a52161cd426caf13e2c364cJohn Spurlock if (mStopped) { 98aaaa54ec0eaf3b5d1a52161cd426caf13e2c364cJohn Spurlock init(); 99aaaa54ec0eaf3b5d1a52161cd426caf13e2c364cJohn Spurlock } 100aaaa54ec0eaf3b5d1a52161cd426caf13e2c364cJohn Spurlock } 101aaaa54ec0eaf3b5d1a52161cd426caf13e2c364cJohn Spurlock 10239b467482d1bf256a111c757e9b7621c6f523271Jason Monk public void onActivityPause() { 103aaaa54ec0eaf3b5d1a52161cd426caf13e2c364cJohn Spurlock mStopped = true; 10481bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock if (mVolumizer != null) { 10581bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock mVolumizer.stop(); 106176ee343b4cb32cb0899b3740711fda1d4a5024bSheng Wang mVolumizer = null; 10781bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock } 10881bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock } 109176ee343b4cb32cb0899b3740711fda1d4a5024bSheng Wang 11081bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock @Override 11139b467482d1bf256a111c757e9b7621c6f523271Jason Monk public void onBindViewHolder(PreferenceViewHolder view) { 11239b467482d1bf256a111c757e9b7621c6f523271Jason Monk super.onBindViewHolder(view); 113aaaa54ec0eaf3b5d1a52161cd426caf13e2c364cJohn Spurlock mSeekBar = (SeekBar) view.findViewById(com.android.internal.R.id.seekbar); 114aaaa54ec0eaf3b5d1a52161cd426caf13e2c364cJohn Spurlock mIconView = (ImageView) view.findViewById(com.android.internal.R.id.icon); 115aaaa54ec0eaf3b5d1a52161cd426caf13e2c364cJohn Spurlock mSuppressionTextView = (TextView) view.findViewById(R.id.suppression_text); 116aaaa54ec0eaf3b5d1a52161cd426caf13e2c364cJohn Spurlock init(); 117aaaa54ec0eaf3b5d1a52161cd426caf13e2c364cJohn Spurlock } 118aaaa54ec0eaf3b5d1a52161cd426caf13e2c364cJohn Spurlock 119aaaa54ec0eaf3b5d1a52161cd426caf13e2c364cJohn Spurlock private void init() { 120aaaa54ec0eaf3b5d1a52161cd426caf13e2c364cJohn Spurlock if (mSeekBar == null) return; 12181bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock final SeekBarVolumizer.Callback sbvc = new SeekBarVolumizer.Callback() { 12281bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock @Override 12381bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock public void onSampleStarting(SeekBarVolumizer sbv) { 12481bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock if (mCallback != null) { 12581bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock mCallback.onSampleStarting(sbv); 12681bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock } 12781bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock } 128c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock @Override 129c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock public void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) { 130c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock if (mCallback != null) { 131c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock mCallback.onStreamValueChanged(mStream, progress); 132c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock } 133c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock } 134c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock @Override 135f82154de8c5274d41c6ae1cbd0170f9e20462a45John Spurlock public void onMuted(boolean muted, boolean zenMuted) { 136f82154de8c5274d41c6ae1cbd0170f9e20462a45John Spurlock if (mMuted == muted && mZenMuted == zenMuted) return; 137c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock mMuted = muted; 138f82154de8c5274d41c6ae1cbd0170f9e20462a45John Spurlock mZenMuted = zenMuted; 139c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock updateIconView(); 140c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock } 14181bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock }; 14281bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock final Uri sampleUri = mStream == AudioManager.STREAM_MUSIC ? getMediaVolumeUri() : null; 14385315533a19aa61a0c5fc27d3f783c3f21e3878fJohn Spurlock if (mVolumizer == null) { 144c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock mVolumizer = new SeekBarVolumizer(getContext(), mStream, sampleUri, sbvc); 14585315533a19aa61a0c5fc27d3f783c3f21e3878fJohn Spurlock } 146af05fda24d17cb87cd4de35fdb51dd1ea23c79e2John Spurlock mVolumizer.start(); 14785315533a19aa61a0c5fc27d3f783c3f21e3878fJohn Spurlock mVolumizer.setSeekBar(mSeekBar); 148c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock updateIconView(); 149fdebfc35c43c445afcd39077f5cbcf72902b1d6eJohn Spurlock updateSuppressionText(); 15072965ad53b4c935e115e49fe12189781954a4077Jason Monk if (!isEnabled()) { 15172965ad53b4c935e115e49fe12189781954a4077Jason Monk mSeekBar.setEnabled(false); 15272965ad53b4c935e115e49fe12189781954a4077Jason Monk mVolumizer.stop(); 15372965ad53b4c935e115e49fe12189781954a4077Jason Monk } 154cb9f35171d14bec1af4bb313aac2e79ac2290facDan Sandler } 155cb9f35171d14bec1af4bb313aac2e79ac2290facDan Sandler 156c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock private void updateIconView() { 157c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock if (mIconView == null) return; 158c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock if (mIconResId != 0) { 159c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock mIconView.setImageResource(mIconResId); 160f82154de8c5274d41c6ae1cbd0170f9e20462a45John Spurlock } else if (mMuteIconResId != 0 && mMuted && !mZenMuted) { 161c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock mIconView.setImageResource(mMuteIconResId); 162c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock } else { 163c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock mIconView.setImageDrawable(getIcon()); 164c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock } 165c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock } 166c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock 167cb9f35171d14bec1af4bb313aac2e79ac2290facDan Sandler public void showIcon(int resId) { 168cb9f35171d14bec1af4bb313aac2e79ac2290facDan Sandler // Instead of using setIcon, which will trigger listeners, this just decorates the 169cb9f35171d14bec1af4bb313aac2e79ac2290facDan Sandler // preference temporarily with a new icon. 170c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock if (mIconResId == resId) return; 171c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock mIconResId = resId; 172c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock updateIconView(); 173c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock } 174c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock 175c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock public void setMuteIcon(int resId) { 176c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock if (mMuteIconResId == resId) return; 177c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock mMuteIconResId = resId; 178c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock updateIconView(); 17981bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock } 18081bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock 18181bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock private Uri getMediaVolumeUri() { 18281bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock return Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" 183dbaf080f44c72dcd08136c8b026c782696102df6Fabrice Di Meglio + getContext().getPackageName() 18481bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock + "/" + R.raw.media_volume); 18581bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock } 18681bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock 187fdebfc35c43c445afcd39077f5cbcf72902b1d6eJohn Spurlock public void setSuppressionText(String text) { 188fdebfc35c43c445afcd39077f5cbcf72902b1d6eJohn Spurlock if (Objects.equals(text, mSuppressionText)) return; 189fdebfc35c43c445afcd39077f5cbcf72902b1d6eJohn Spurlock mSuppressionText = text; 190fdebfc35c43c445afcd39077f5cbcf72902b1d6eJohn Spurlock updateSuppressionText(); 191fdebfc35c43c445afcd39077f5cbcf72902b1d6eJohn Spurlock } 192fdebfc35c43c445afcd39077f5cbcf72902b1d6eJohn Spurlock 193fdebfc35c43c445afcd39077f5cbcf72902b1d6eJohn Spurlock private void updateSuppressionText() { 194fdebfc35c43c445afcd39077f5cbcf72902b1d6eJohn Spurlock if (mSuppressionTextView != null && mSeekBar != null) { 195fdebfc35c43c445afcd39077f5cbcf72902b1d6eJohn Spurlock mSuppressionTextView.setText(mSuppressionText); 196fdebfc35c43c445afcd39077f5cbcf72902b1d6eJohn Spurlock final boolean showSuppression = !TextUtils.isEmpty(mSuppressionText); 1970ddba4c119d2d1c35fa4c4038e5192bf5761be2cJulia Reynolds mSuppressionTextView.setVisibility(showSuppression ? View.VISIBLE : View.GONE); 198fdebfc35c43c445afcd39077f5cbcf72902b1d6eJohn Spurlock } 199fdebfc35c43c445afcd39077f5cbcf72902b1d6eJohn Spurlock } 200fdebfc35c43c445afcd39077f5cbcf72902b1d6eJohn Spurlock 20181bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock public interface Callback { 20281bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock void onSampleStarting(SeekBarVolumizer sbv); 203cb9f35171d14bec1af4bb313aac2e79ac2290facDan Sandler void onStreamValueChanged(int stream, int progress); 20481bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock } 20581bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock} 206