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