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 
17 package com.android.settings.notification;
18 
19 import android.content.ContentResolver;
20 import android.content.Context;
21 import android.media.AudioManager;
22 import android.net.Uri;
23 import android.preference.SeekBarVolumizer;
24 import android.support.v7.preference.PreferenceViewHolder;
25 import android.text.TextUtils;
26 import android.util.AttributeSet;
27 import android.util.Log;
28 import android.view.View;
29 import android.widget.ImageView;
30 import android.widget.SeekBar;
31 import android.widget.TextView;
32 
33 import com.android.settings.R;
34 import com.android.settings.SeekBarPreference;
35 
36 import java.util.Objects;
37 
38 /** A slider preference that directly controls an audio stream volume (no dialog) **/
39 public class VolumeSeekBarPreference extends SeekBarPreference {
40     private static final String TAG = "VolumeSeekBarPreference";
41 
42     private int mStream;
43     private SeekBar mSeekBar;
44     private SeekBarVolumizer mVolumizer;
45     private Callback mCallback;
46     private ImageView mIconView;
47     private TextView mSuppressionTextView;
48     private String mSuppressionText;
49     private boolean mMuted;
50     private boolean mZenMuted;
51     private int mIconResId;
52     private int mMuteIconResId;
53     private boolean mStopped;
54 
VolumeSeekBarPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)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 
VolumeSeekBarPreference(Context context, AttributeSet attrs, int defStyleAttr)61     public VolumeSeekBarPreference(Context context, AttributeSet attrs, int defStyleAttr) {
62         this(context, attrs, defStyleAttr, 0);
63     }
64 
VolumeSeekBarPreference(Context context, AttributeSet attrs)65     public VolumeSeekBarPreference(Context context, AttributeSet attrs) {
66         this(context, attrs, 0);
67     }
68 
VolumeSeekBarPreference(Context context)69     public VolumeSeekBarPreference(Context context) {
70         this(context, null);
71     }
72 
setStream(int stream)73     public void setStream(int stream) {
74         mStream = stream;
75     }
76 
setCallback(Callback callback)77     public void setCallback(Callback callback) {
78         mCallback = callback;
79     }
80 
onActivityResume()81     public void onActivityResume() {
82         if (mStopped) {
83             init();
84         }
85     }
86 
onActivityPause()87     public void onActivityPause() {
88         mStopped = true;
89         if (mVolumizer != null) {
90             mVolumizer.stop();
91         }
92     }
93 
94     @Override
onBindViewHolder(PreferenceViewHolder view)95     public void onBindViewHolder(PreferenceViewHolder view) {
96         super.onBindViewHolder(view);
97         if (mStream == 0) {
98             Log.w(TAG, "No stream found, not binding volumizer");
99             return;
100         }
101         mSeekBar = (SeekBar) view.findViewById(com.android.internal.R.id.seekbar);
102         mIconView = (ImageView) view.findViewById(com.android.internal.R.id.icon);
103         mSuppressionTextView = (TextView) view.findViewById(R.id.suppression_text);
104         init();
105     }
106 
init()107     private void init() {
108         if (mSeekBar == null) return;
109         final SeekBarVolumizer.Callback sbvc = new SeekBarVolumizer.Callback() {
110             @Override
111             public void onSampleStarting(SeekBarVolumizer sbv) {
112                 if (mCallback != null) {
113                     mCallback.onSampleStarting(sbv);
114                 }
115             }
116             @Override
117             public void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) {
118                 if (mCallback != null) {
119                     mCallback.onStreamValueChanged(mStream, progress);
120                 }
121             }
122             @Override
123             public void onMuted(boolean muted, boolean zenMuted) {
124                 if (mMuted == muted && mZenMuted == zenMuted) return;
125                 mMuted = muted;
126                 mZenMuted = zenMuted;
127                 updateIconView();
128             }
129         };
130         final Uri sampleUri = mStream == AudioManager.STREAM_MUSIC ? getMediaVolumeUri() : null;
131         if (mVolumizer == null) {
132             mVolumizer = new SeekBarVolumizer(getContext(), mStream, sampleUri, sbvc);
133         }
134         mVolumizer.start();
135         mVolumizer.setSeekBar(mSeekBar);
136         updateIconView();
137         mCallback.onStreamValueChanged(mStream, mSeekBar.getProgress());
138         updateSuppressionText();
139         if (!isEnabled()) {
140             mSeekBar.setEnabled(false);
141             mVolumizer.stop();
142         }
143     }
144 
145     // during initialization, this preference is the SeekBar listener
146     @Override
onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch)147     public void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) {
148         super.onProgressChanged(seekBar, progress, fromTouch);
149         mCallback.onStreamValueChanged(mStream, progress);
150     }
151 
updateIconView()152     private void updateIconView() {
153         if (mIconView == null) return;
154         if (mIconResId != 0) {
155             mIconView.setImageResource(mIconResId);
156         } else if (mMuteIconResId != 0 && mMuted && !mZenMuted) {
157             mIconView.setImageResource(mMuteIconResId);
158         } else {
159             mIconView.setImageDrawable(getIcon());
160         }
161     }
162 
showIcon(int resId)163     public void showIcon(int resId) {
164         // Instead of using setIcon, which will trigger listeners, this just decorates the
165         // preference temporarily with a new icon.
166         if (mIconResId == resId) return;
167         mIconResId = resId;
168         updateIconView();
169     }
170 
setMuteIcon(int resId)171     public void setMuteIcon(int resId) {
172         if (mMuteIconResId == resId) return;
173         mMuteIconResId = resId;
174         updateIconView();
175     }
176 
getMediaVolumeUri()177     private Uri getMediaVolumeUri() {
178         return Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://"
179                 + getContext().getPackageName()
180                 + "/" + R.raw.media_volume);
181     }
182 
setSuppressionText(String text)183     public void setSuppressionText(String text) {
184         if (Objects.equals(text, mSuppressionText)) return;
185         mSuppressionText = text;
186         updateSuppressionText();
187     }
188 
updateSuppressionText()189     private void updateSuppressionText() {
190         if (mSuppressionTextView != null && mSeekBar != null) {
191             mSuppressionTextView.setText(mSuppressionText);
192             final boolean showSuppression = !TextUtils.isEmpty(mSuppressionText);
193             mSuppressionTextView.setVisibility(showSuppression ? View.VISIBLE : View.INVISIBLE);
194             mSeekBar.setVisibility(showSuppression ? View.INVISIBLE : View.VISIBLE);
195         }
196     }
197 
198     public interface Callback {
onSampleStarting(SeekBarVolumizer sbv)199         void onSampleStarting(SeekBarVolumizer sbv);
onStreamValueChanged(int stream, int progress)200         void onStreamValueChanged(int stream, int progress);
201     }
202 }
203