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.PreferenceManager; 24 import android.preference.SeekBarPreference; 25 import android.preference.SeekBarVolumizer; 26 import android.text.TextUtils; 27 import android.util.AttributeSet; 28 import android.util.Log; 29 import android.view.View; 30 import android.widget.ImageView; 31 import android.widget.SeekBar; 32 import android.widget.TextView; 33 34 import com.android.settings.R; 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 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 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 87 @Override onActivityStop()88 public void onActivityStop() { 89 mStopped = true; 90 if (mVolumizer != null) { 91 mVolumizer.stop(); 92 } 93 } 94 95 @Override onBindView(View view)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 init()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 onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch)144 public void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) { 145 super.onProgressChanged(seekBar, progress, fromTouch); 146 mCallback.onStreamValueChanged(mStream, progress); 147 } 148 updateIconView()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 showIcon(int resId)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 setMuteIcon(int resId)168 public void setMuteIcon(int resId) { 169 if (mMuteIconResId == resId) return; 170 mMuteIconResId = resId; 171 updateIconView(); 172 } 173 getMediaVolumeUri()174 private Uri getMediaVolumeUri() { 175 return Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" 176 + getContext().getPackageName() 177 + "/" + R.raw.media_volume); 178 } 179 setSuppressionText(String text)180 public void setSuppressionText(String text) { 181 if (Objects.equals(text, mSuppressionText)) return; 182 mSuppressionText = text; 183 updateSuppressionText(); 184 } 185 updateSuppressionText()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 { onSampleStarting(SeekBarVolumizer sbv)196 void onSampleStarting(SeekBarVolumizer sbv); onStreamValueChanged(int stream, int progress)197 void onStreamValueChanged(int stream, int progress); 198 } 199 } 200