1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.settings.notification;
18
19import android.content.ContentResolver;
20import android.content.Context;
21import android.media.AudioManager;
22import android.net.Uri;
23import android.preference.PreferenceManager;
24import android.preference.SeekBarPreference;
25import android.preference.SeekBarVolumizer;
26import android.text.TextUtils;
27import android.util.AttributeSet;
28import android.util.Log;
29import android.view.View;
30import android.widget.ImageView;
31import android.widget.SeekBar;
32import android.widget.TextView;
33
34import com.android.settings.R;
35
36import java.util.Objects;
37
38/** A slider preference that directly controls an audio stream volume (no dialog) **/
39public class VolumeSeekBarPreference extends SeekBarPreference
40        implements PreferenceManager.OnActivityStopListener {
41    private static final String TAG = "VolumeSeekBarPreference";
42
43    private int mStream;
44    private SeekBar mSeekBar;
45    private SeekBarVolumizer mVolumizer;
46    private Callback mCallback;
47    private ImageView mIconView;
48    private TextView mSuppressionTextView;
49    private String mSuppressionText;
50    private boolean mMuted;
51    private int mIconResId;
52    private int mMuteIconResId;
53    private boolean mStopped;
54
55    public VolumeSeekBarPreference(Context context, AttributeSet attrs, int defStyleAttr,
56            int defStyleRes) {
57        super(context, attrs, defStyleAttr, defStyleRes);
58        setLayoutResource(R.layout.preference_volume_slider);
59    }
60
61    public VolumeSeekBarPreference(Context context, AttributeSet attrs, int defStyleAttr) {
62        this(context, attrs, defStyleAttr, 0);
63    }
64
65    public VolumeSeekBarPreference(Context context, AttributeSet attrs) {
66        this(context, attrs, 0);
67    }
68
69    public VolumeSeekBarPreference(Context context) {
70        this(context, null);
71    }
72
73    public void setStream(int stream) {
74        mStream = stream;
75    }
76
77    public void setCallback(Callback callback) {
78        mCallback = callback;
79    }
80
81    public void onActivityResume() {
82        if (mStopped) {
83            init();
84        }
85    }
86
87    @Override
88    public void onActivityStop() {
89        mStopped = true;
90        if (mVolumizer != null) {
91            mVolumizer.stop();
92        }
93    }
94
95    @Override
96    protected void onBindView(View view) {
97        super.onBindView(view);
98        if (mStream == 0) {
99            Log.w(TAG, "No stream found, not binding volumizer");
100            return;
101        }
102        mSeekBar = (SeekBar) view.findViewById(com.android.internal.R.id.seekbar);
103        mIconView = (ImageView) view.findViewById(com.android.internal.R.id.icon);
104        mSuppressionTextView = (TextView) view.findViewById(R.id.suppression_text);
105        init();
106    }
107
108    private void init() {
109        if (mSeekBar == null) return;
110        getPreferenceManager().registerOnActivityStopListener(this);
111        final SeekBarVolumizer.Callback sbvc = new SeekBarVolumizer.Callback() {
112            @Override
113            public void onSampleStarting(SeekBarVolumizer sbv) {
114                if (mCallback != null) {
115                    mCallback.onSampleStarting(sbv);
116                }
117            }
118            @Override
119            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) {
120                if (mCallback != null) {
121                    mCallback.onStreamValueChanged(mStream, progress);
122                }
123            }
124            @Override
125            public void onMuted(boolean muted) {
126                if (mMuted == muted) return;
127                mMuted = muted;
128                updateIconView();
129            }
130        };
131        final Uri sampleUri = mStream == AudioManager.STREAM_MUSIC ? getMediaVolumeUri() : null;
132        if (mVolumizer == null) {
133            mVolumizer = new SeekBarVolumizer(getContext(), mStream, sampleUri, sbvc);
134        }
135        mVolumizer.start();
136        mVolumizer.setSeekBar(mSeekBar);
137        updateIconView();
138        mCallback.onStreamValueChanged(mStream, mSeekBar.getProgress());
139        updateSuppressionText();
140    }
141
142    // during initialization, this preference is the SeekBar listener
143    @Override
144    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) {
145        super.onProgressChanged(seekBar, progress, fromTouch);
146        mCallback.onStreamValueChanged(mStream, progress);
147    }
148
149    private void updateIconView() {
150        if (mIconView == null) return;
151        if (mIconResId != 0) {
152            mIconView.setImageResource(mIconResId);
153        } else if (mMuteIconResId != 0 && mMuted) {
154            mIconView.setImageResource(mMuteIconResId);
155        } else {
156            mIconView.setImageDrawable(getIcon());
157        }
158    }
159
160    public void showIcon(int resId) {
161        // Instead of using setIcon, which will trigger listeners, this just decorates the
162        // preference temporarily with a new icon.
163        if (mIconResId == resId) return;
164        mIconResId = resId;
165        updateIconView();
166    }
167
168    public void setMuteIcon(int resId) {
169        if (mMuteIconResId == resId) return;
170        mMuteIconResId = resId;
171        updateIconView();
172    }
173
174    private Uri getMediaVolumeUri() {
175        return Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://"
176                + getContext().getPackageName()
177                + "/" + R.raw.media_volume);
178    }
179
180    public void setSuppressionText(String text) {
181        if (Objects.equals(text, mSuppressionText)) return;
182        mSuppressionText = text;
183        updateSuppressionText();
184    }
185
186    private void updateSuppressionText() {
187        if (mSuppressionTextView != null && mSeekBar != null) {
188            mSuppressionTextView.setText(mSuppressionText);
189            final boolean showSuppression = !TextUtils.isEmpty(mSuppressionText);
190            mSuppressionTextView.setVisibility(showSuppression ? View.VISIBLE : View.INVISIBLE);
191            mSeekBar.setVisibility(showSuppression ? View.INVISIBLE : View.VISIBLE);
192        }
193    }
194
195    public interface Callback {
196        void onSampleStarting(SeekBarVolumizer sbv);
197        void onStreamValueChanged(int stream, int progress);
198    }
199}
200