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