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;
2439b467482d1bf256a111c757e9b7621c6f523271Jason Monkimport android.support.v7.preference.PreferenceViewHolder;
25fdebfc35c43c445afcd39077f5cbcf72902b1d6eJohn Spurlockimport android.text.TextUtils;
2681bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlockimport android.util.AttributeSet;
2781bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlockimport android.util.Log;
2881bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlockimport android.view.View;
29cb9f35171d14bec1af4bb313aac2e79ac2290facDan Sandlerimport android.widget.ImageView;
3081bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlockimport android.widget.SeekBar;
31fdebfc35c43c445afcd39077f5cbcf72902b1d6eJohn Spurlockimport android.widget.TextView;
3281bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock
3381bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlockimport com.android.settings.R;
3439b467482d1bf256a111c757e9b7621c6f523271Jason Monkimport com.android.settings.SeekBarPreference;
3581bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock
36fdebfc35c43c445afcd39077f5cbcf72902b1d6eJohn Spurlockimport java.util.Objects;
37fdebfc35c43c445afcd39077f5cbcf72902b1d6eJohn Spurlock
3881bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock/** A slider preference that directly controls an audio stream volume (no dialog) **/
3939b467482d1bf256a111c757e9b7621c6f523271Jason Monkpublic class VolumeSeekBarPreference extends SeekBarPreference {
4081bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock    private static final String TAG = "VolumeSeekBarPreference";
4181bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock
4281bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock    private int mStream;
4381bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock    private SeekBar mSeekBar;
4481bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock    private SeekBarVolumizer mVolumizer;
4581bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock    private Callback mCallback;
46cb9f35171d14bec1af4bb313aac2e79ac2290facDan Sandler    private ImageView mIconView;
47fdebfc35c43c445afcd39077f5cbcf72902b1d6eJohn Spurlock    private TextView mSuppressionTextView;
48fdebfc35c43c445afcd39077f5cbcf72902b1d6eJohn Spurlock    private String mSuppressionText;
49c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock    private boolean mMuted;
50f82154de8c5274d41c6ae1cbd0170f9e20462a45John Spurlock    private boolean mZenMuted;
51c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock    private int mIconResId;
52c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock    private int mMuteIconResId;
53aaaa54ec0eaf3b5d1a52161cd426caf13e2c364cJohn Spurlock    private boolean mStopped;
5481bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock
55dbaf080f44c72dcd08136c8b026c782696102df6Fabrice Di Meglio    public VolumeSeekBarPreference(Context context, AttributeSet attrs, int defStyleAttr,
56dbaf080f44c72dcd08136c8b026c782696102df6Fabrice Di Meglio            int defStyleRes) {
57dbaf080f44c72dcd08136c8b026c782696102df6Fabrice Di Meglio        super(context, attrs, defStyleAttr, defStyleRes);
58fdebfc35c43c445afcd39077f5cbcf72902b1d6eJohn Spurlock        setLayoutResource(R.layout.preference_volume_slider);
59dbaf080f44c72dcd08136c8b026c782696102df6Fabrice Di Meglio    }
60dbaf080f44c72dcd08136c8b026c782696102df6Fabrice Di Meglio
61dbaf080f44c72dcd08136c8b026c782696102df6Fabrice Di Meglio    public VolumeSeekBarPreference(Context context, AttributeSet attrs, int defStyleAttr) {
62dbaf080f44c72dcd08136c8b026c782696102df6Fabrice Di Meglio        this(context, attrs, defStyleAttr, 0);
63dbaf080f44c72dcd08136c8b026c782696102df6Fabrice Di Meglio    }
64dbaf080f44c72dcd08136c8b026c782696102df6Fabrice Di Meglio
6581bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock    public VolumeSeekBarPreference(Context context, AttributeSet attrs) {
66dbaf080f44c72dcd08136c8b026c782696102df6Fabrice Di Meglio        this(context, attrs, 0);
67dbaf080f44c72dcd08136c8b026c782696102df6Fabrice Di Meglio    }
68dbaf080f44c72dcd08136c8b026c782696102df6Fabrice Di Meglio
69dbaf080f44c72dcd08136c8b026c782696102df6Fabrice Di Meglio    public VolumeSeekBarPreference(Context context) {
70dbaf080f44c72dcd08136c8b026c782696102df6Fabrice Di Meglio        this(context, null);
7181bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock    }
7281bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock
7381bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock    public void setStream(int stream) {
7481bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock        mStream = stream;
7581bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock    }
7681bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock
7781bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock    public void setCallback(Callback callback) {
7881bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock        mCallback = callback;
7981bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock    }
8081bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock
81aaaa54ec0eaf3b5d1a52161cd426caf13e2c364cJohn Spurlock    public void onActivityResume() {
82aaaa54ec0eaf3b5d1a52161cd426caf13e2c364cJohn Spurlock        if (mStopped) {
83aaaa54ec0eaf3b5d1a52161cd426caf13e2c364cJohn Spurlock            init();
84aaaa54ec0eaf3b5d1a52161cd426caf13e2c364cJohn Spurlock        }
85aaaa54ec0eaf3b5d1a52161cd426caf13e2c364cJohn Spurlock    }
86aaaa54ec0eaf3b5d1a52161cd426caf13e2c364cJohn Spurlock
8739b467482d1bf256a111c757e9b7621c6f523271Jason Monk    public void onActivityPause() {
88aaaa54ec0eaf3b5d1a52161cd426caf13e2c364cJohn Spurlock        mStopped = true;
8981bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock        if (mVolumizer != null) {
9081bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock            mVolumizer.stop();
9181bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock        }
9281bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock    }
9339b467482d1bf256a111c757e9b7621c6f523271Jason Monk
9481bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock    @Override
9539b467482d1bf256a111c757e9b7621c6f523271Jason Monk    public void onBindViewHolder(PreferenceViewHolder view) {
9639b467482d1bf256a111c757e9b7621c6f523271Jason Monk        super.onBindViewHolder(view);
9781bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock        if (mStream == 0) {
9881bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock            Log.w(TAG, "No stream found, not binding volumizer");
9981bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock            return;
10081bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock        }
101aaaa54ec0eaf3b5d1a52161cd426caf13e2c364cJohn Spurlock        mSeekBar = (SeekBar) view.findViewById(com.android.internal.R.id.seekbar);
102aaaa54ec0eaf3b5d1a52161cd426caf13e2c364cJohn Spurlock        mIconView = (ImageView) view.findViewById(com.android.internal.R.id.icon);
103aaaa54ec0eaf3b5d1a52161cd426caf13e2c364cJohn Spurlock        mSuppressionTextView = (TextView) view.findViewById(R.id.suppression_text);
104aaaa54ec0eaf3b5d1a52161cd426caf13e2c364cJohn Spurlock        init();
105aaaa54ec0eaf3b5d1a52161cd426caf13e2c364cJohn Spurlock    }
106aaaa54ec0eaf3b5d1a52161cd426caf13e2c364cJohn Spurlock
107aaaa54ec0eaf3b5d1a52161cd426caf13e2c364cJohn Spurlock    private void init() {
108aaaa54ec0eaf3b5d1a52161cd426caf13e2c364cJohn Spurlock        if (mSeekBar == null) return;
10981bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock        final SeekBarVolumizer.Callback sbvc = new SeekBarVolumizer.Callback() {
11081bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock            @Override
11181bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock            public void onSampleStarting(SeekBarVolumizer sbv) {
11281bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock                if (mCallback != null) {
11381bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock                    mCallback.onSampleStarting(sbv);
11481bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock                }
11581bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock            }
116c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock            @Override
117c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) {
118c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock                if (mCallback != null) {
119c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock                    mCallback.onStreamValueChanged(mStream, progress);
120c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock                }
121c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock            }
122c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock            @Override
123f82154de8c5274d41c6ae1cbd0170f9e20462a45John Spurlock            public void onMuted(boolean muted, boolean zenMuted) {
124f82154de8c5274d41c6ae1cbd0170f9e20462a45John Spurlock                if (mMuted == muted && mZenMuted == zenMuted) return;
125c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock                mMuted = muted;
126f82154de8c5274d41c6ae1cbd0170f9e20462a45John Spurlock                mZenMuted = zenMuted;
127c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock                updateIconView();
128c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock            }
12981bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock        };
13081bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock        final Uri sampleUri = mStream == AudioManager.STREAM_MUSIC ? getMediaVolumeUri() : null;
13185315533a19aa61a0c5fc27d3f783c3f21e3878fJohn Spurlock        if (mVolumizer == null) {
132c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock            mVolumizer = new SeekBarVolumizer(getContext(), mStream, sampleUri, sbvc);
13385315533a19aa61a0c5fc27d3f783c3f21e3878fJohn Spurlock        }
134af05fda24d17cb87cd4de35fdb51dd1ea23c79e2John Spurlock        mVolumizer.start();
13585315533a19aa61a0c5fc27d3f783c3f21e3878fJohn Spurlock        mVolumizer.setSeekBar(mSeekBar);
136c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock        updateIconView();
137cb9f35171d14bec1af4bb313aac2e79ac2290facDan Sandler        mCallback.onStreamValueChanged(mStream, mSeekBar.getProgress());
138fdebfc35c43c445afcd39077f5cbcf72902b1d6eJohn Spurlock        updateSuppressionText();
13972965ad53b4c935e115e49fe12189781954a4077Jason Monk        if (!isEnabled()) {
14072965ad53b4c935e115e49fe12189781954a4077Jason Monk            mSeekBar.setEnabled(false);
14172965ad53b4c935e115e49fe12189781954a4077Jason Monk            mVolumizer.stop();
14272965ad53b4c935e115e49fe12189781954a4077Jason Monk        }
143cb9f35171d14bec1af4bb313aac2e79ac2290facDan Sandler    }
144cb9f35171d14bec1af4bb313aac2e79ac2290facDan Sandler
145cb9f35171d14bec1af4bb313aac2e79ac2290facDan Sandler    // during initialization, this preference is the SeekBar listener
146cb9f35171d14bec1af4bb313aac2e79ac2290facDan Sandler    @Override
147fdebfc35c43c445afcd39077f5cbcf72902b1d6eJohn Spurlock    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) {
148cb9f35171d14bec1af4bb313aac2e79ac2290facDan Sandler        super.onProgressChanged(seekBar, progress, fromTouch);
149cb9f35171d14bec1af4bb313aac2e79ac2290facDan Sandler        mCallback.onStreamValueChanged(mStream, progress);
150cb9f35171d14bec1af4bb313aac2e79ac2290facDan Sandler    }
151cb9f35171d14bec1af4bb313aac2e79ac2290facDan Sandler
152c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock    private void updateIconView() {
153c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock        if (mIconView == null) return;
154c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock        if (mIconResId != 0) {
155c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock            mIconView.setImageResource(mIconResId);
156f82154de8c5274d41c6ae1cbd0170f9e20462a45John Spurlock        } else if (mMuteIconResId != 0 && mMuted && !mZenMuted) {
157c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock            mIconView.setImageResource(mMuteIconResId);
158c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock        } else {
159c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock            mIconView.setImageDrawable(getIcon());
160c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock        }
161c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock    }
162c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock
163cb9f35171d14bec1af4bb313aac2e79ac2290facDan Sandler    public void showIcon(int resId) {
164cb9f35171d14bec1af4bb313aac2e79ac2290facDan Sandler        // Instead of using setIcon, which will trigger listeners, this just decorates the
165cb9f35171d14bec1af4bb313aac2e79ac2290facDan Sandler        // preference temporarily with a new icon.
166c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock        if (mIconResId == resId) return;
167c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock        mIconResId = resId;
168c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock        updateIconView();
169c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock    }
170c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock
171c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock    public void setMuteIcon(int resId) {
172c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock        if (mMuteIconResId == resId) return;
173c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock        mMuteIconResId = resId;
174c868f7035a6d05332b3d8afcde2ae27ad0413e79John Spurlock        updateIconView();
17581bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock    }
17681bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock
17781bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock    private Uri getMediaVolumeUri() {
17881bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock        return Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://"
179dbaf080f44c72dcd08136c8b026c782696102df6Fabrice Di Meglio                + getContext().getPackageName()
18081bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock                + "/" + R.raw.media_volume);
18181bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock    }
18281bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock
183fdebfc35c43c445afcd39077f5cbcf72902b1d6eJohn Spurlock    public void setSuppressionText(String text) {
184fdebfc35c43c445afcd39077f5cbcf72902b1d6eJohn Spurlock        if (Objects.equals(text, mSuppressionText)) return;
185fdebfc35c43c445afcd39077f5cbcf72902b1d6eJohn Spurlock        mSuppressionText = text;
186fdebfc35c43c445afcd39077f5cbcf72902b1d6eJohn Spurlock        updateSuppressionText();
187fdebfc35c43c445afcd39077f5cbcf72902b1d6eJohn Spurlock    }
188fdebfc35c43c445afcd39077f5cbcf72902b1d6eJohn Spurlock
189fdebfc35c43c445afcd39077f5cbcf72902b1d6eJohn Spurlock    private void updateSuppressionText() {
190fdebfc35c43c445afcd39077f5cbcf72902b1d6eJohn Spurlock        if (mSuppressionTextView != null && mSeekBar != null) {
191fdebfc35c43c445afcd39077f5cbcf72902b1d6eJohn Spurlock            mSuppressionTextView.setText(mSuppressionText);
192fdebfc35c43c445afcd39077f5cbcf72902b1d6eJohn Spurlock            final boolean showSuppression = !TextUtils.isEmpty(mSuppressionText);
193fdebfc35c43c445afcd39077f5cbcf72902b1d6eJohn Spurlock            mSuppressionTextView.setVisibility(showSuppression ? View.VISIBLE : View.INVISIBLE);
194fdebfc35c43c445afcd39077f5cbcf72902b1d6eJohn Spurlock            mSeekBar.setVisibility(showSuppression ? View.INVISIBLE : View.VISIBLE);
195fdebfc35c43c445afcd39077f5cbcf72902b1d6eJohn Spurlock        }
196fdebfc35c43c445afcd39077f5cbcf72902b1d6eJohn Spurlock    }
197fdebfc35c43c445afcd39077f5cbcf72902b1d6eJohn Spurlock
19881bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock    public interface Callback {
19981bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock        void onSampleStarting(SeekBarVolumizer sbv);
200cb9f35171d14bec1af4bb313aac2e79ac2290facDan Sandler        void onStreamValueChanged(int stream, int progress);
20181bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock    }
20281bef1d74568d623b9db3c5409740dc21c0bbc08John Spurlock}
203