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 boolean mZenMuted; 52 private int mIconResId; 53 private int mMuteIconResId; 54 private boolean mStopped; 55 VolumeSeekBarPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)56 public VolumeSeekBarPreference(Context context, AttributeSet attrs, int defStyleAttr, 57 int defStyleRes) { 58 super(context, attrs, defStyleAttr, defStyleRes); 59 setLayoutResource(R.layout.preference_volume_slider); 60 } 61 VolumeSeekBarPreference(Context context, AttributeSet attrs, int defStyleAttr)62 public VolumeSeekBarPreference(Context context, AttributeSet attrs, int defStyleAttr) { 63 this(context, attrs, defStyleAttr, 0); 64 } 65 VolumeSeekBarPreference(Context context, AttributeSet attrs)66 public VolumeSeekBarPreference(Context context, AttributeSet attrs) { 67 this(context, attrs, 0); 68 } 69 VolumeSeekBarPreference(Context context)70 public VolumeSeekBarPreference(Context context) { 71 this(context, null); 72 } 73 setStream(int stream)74 public void setStream(int stream) { 75 mStream = stream; 76 } 77 setCallback(Callback callback)78 public void setCallback(Callback callback) { 79 mCallback = callback; 80 } 81 onActivityResume()82 public void onActivityResume() { 83 if (mStopped) { 84 init(); 85 } 86 } 87 88 @Override onActivityStop()89 public void onActivityStop() { 90 mStopped = true; 91 if (mVolumizer != null) { 92 mVolumizer.stop(); 93 } 94 } 95 96 @Override onBindView(View view)97 protected void onBindView(View view) { 98 super.onBindView(view); 99 if (mStream == 0) { 100 Log.w(TAG, "No stream found, not binding volumizer"); 101 return; 102 } 103 mSeekBar = (SeekBar) view.findViewById(com.android.internal.R.id.seekbar); 104 mIconView = (ImageView) view.findViewById(com.android.internal.R.id.icon); 105 mSuppressionTextView = (TextView) view.findViewById(R.id.suppression_text); 106 init(); 107 } 108 init()109 private void init() { 110 if (mSeekBar == null) return; 111 getPreferenceManager().registerOnActivityStopListener(this); 112 final SeekBarVolumizer.Callback sbvc = new SeekBarVolumizer.Callback() { 113 @Override 114 public void onSampleStarting(SeekBarVolumizer sbv) { 115 if (mCallback != null) { 116 mCallback.onSampleStarting(sbv); 117 } 118 } 119 @Override 120 public void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) { 121 if (mCallback != null) { 122 mCallback.onStreamValueChanged(mStream, progress); 123 } 124 } 125 @Override 126 public void onMuted(boolean muted, boolean zenMuted) { 127 if (mMuted == muted && mZenMuted == zenMuted) return; 128 mMuted = muted; 129 mZenMuted = zenMuted; 130 updateIconView(); 131 } 132 }; 133 final Uri sampleUri = mStream == AudioManager.STREAM_MUSIC ? getMediaVolumeUri() : null; 134 if (mVolumizer == null) { 135 mVolumizer = new SeekBarVolumizer(getContext(), mStream, sampleUri, sbvc); 136 } 137 mVolumizer.start(); 138 mVolumizer.setSeekBar(mSeekBar); 139 updateIconView(); 140 mCallback.onStreamValueChanged(mStream, mSeekBar.getProgress()); 141 updateSuppressionText(); 142 if (!isEnabled()) { 143 mSeekBar.setEnabled(false); 144 mVolumizer.stop(); 145 } 146 } 147 148 // during initialization, this preference is the SeekBar listener 149 @Override onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch)150 public void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) { 151 super.onProgressChanged(seekBar, progress, fromTouch); 152 mCallback.onStreamValueChanged(mStream, progress); 153 } 154 updateIconView()155 private void updateIconView() { 156 if (mIconView == null) return; 157 if (mIconResId != 0) { 158 mIconView.setImageResource(mIconResId); 159 } else if (mMuteIconResId != 0 && mMuted && !mZenMuted) { 160 mIconView.setImageResource(mMuteIconResId); 161 } else { 162 mIconView.setImageDrawable(getIcon()); 163 } 164 } 165 showIcon(int resId)166 public void showIcon(int resId) { 167 // Instead of using setIcon, which will trigger listeners, this just decorates the 168 // preference temporarily with a new icon. 169 if (mIconResId == resId) return; 170 mIconResId = resId; 171 updateIconView(); 172 } 173 setMuteIcon(int resId)174 public void setMuteIcon(int resId) { 175 if (mMuteIconResId == resId) return; 176 mMuteIconResId = resId; 177 updateIconView(); 178 } 179 getMediaVolumeUri()180 private Uri getMediaVolumeUri() { 181 return Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" 182 + getContext().getPackageName() 183 + "/" + R.raw.media_volume); 184 } 185 setSuppressionText(String text)186 public void setSuppressionText(String text) { 187 if (Objects.equals(text, mSuppressionText)) return; 188 mSuppressionText = text; 189 updateSuppressionText(); 190 } 191 updateSuppressionText()192 private void updateSuppressionText() { 193 if (mSuppressionTextView != null && mSeekBar != null) { 194 mSuppressionTextView.setText(mSuppressionText); 195 final boolean showSuppression = !TextUtils.isEmpty(mSuppressionText); 196 mSuppressionTextView.setVisibility(showSuppression ? View.VISIBLE : View.INVISIBLE); 197 mSeekBar.setVisibility(showSuppression ? View.INVISIBLE : View.VISIBLE); 198 } 199 } 200 201 public interface Callback { onSampleStarting(SeekBarVolumizer sbv)202 void onSampleStarting(SeekBarVolumizer sbv); onStreamValueChanged(int stream, int progress)203 void onStreamValueChanged(int stream, int progress); 204 } 205 } 206