2 * Copyright (C) 2014 CyanogenMod Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.settings.notification;
19 import android.content.ContentResolver;
20 import android.content.Context;
21 import android.media.AudioAttributes;
22 import android.media.AudioManager;
23 import android.media.Ringtone;
24 import android.media.RingtoneManager;
25 import android.os.Handler;
26 import android.os.HandlerThread;
27 import android.os.Message;
28 import android.preference.PreferenceManager;
29 import android.preference.Preference;
30 import android.provider.Settings;
31 import android.text.format.Formatter;
32 import android.util.AttributeSet;
33 import android.util.Log;
34 import android.view.View;
35 import android.widget.SeekBar;
36 import android.widget.TextView;
38 import com.android.settings.R;
39 import cyanogenmod.providers.CMSettings;
41 public class IncreasingRingVolumePreference extends Preference implements
42 PreferenceManager.OnActivityStopListener, Handler.Callback,
43 SeekBar.OnSeekBarChangeListener {
44 private static final String TAG = "IncreasingRingMinVolumePreference";
46 public interface Callback {
47 void onStartingSample();
50 private SeekBar mStartVolumeSeekBar;
51 private SeekBar mRampUpTimeSeekBar;
52 private TextView mRampUpTimeValue;
54 private Ringtone mRingtone;
55 private Callback mCallback;
57 private Handler mHandler;
58 private final Handler mMainHandler = new Handler(this);
60 private static final int MSG_START_SAMPLE = 1;
61 private static final int MSG_STOP_SAMPLE = 2;
62 private static final int MSG_INIT_SAMPLE = 3;
63 private static final int MSG_SET_VOLUME = 4;
64 private static final int CHECK_RINGTONE_PLAYBACK_DELAY_MS = 1000;
66 public IncreasingRingVolumePreference(Context context) {
70 public IncreasingRingVolumePreference(Context context, AttributeSet attrs) {
71 this(context, attrs, 0);
74 public IncreasingRingVolumePreference(Context context, AttributeSet attrs,
76 this(context, attrs, defStyleAttr, 0);
79 public IncreasingRingVolumePreference(Context context, AttributeSet attrs,
80 int defStyleAttr, int defStyleRes) {
81 super(context, attrs, defStyleAttr, defStyleRes);
82 setLayoutResource(R.layout.preference_increasing_ring);
86 public void setCallback(Callback callback) {
90 public void onActivityResume() {
95 public void onActivityStop() {
96 if (mHandler != null) {
98 mHandler.getLooper().quitSafely();
104 public boolean handleMessage(Message msg) {
106 case MSG_START_SAMPLE:
107 onStartSample((float) msg.arg1 / 1000F);
109 case MSG_STOP_SAMPLE:
112 case MSG_INIT_SAMPLE:
116 onSetVolume((float) msg.arg1 / 1000F);
123 protected void onBindView(View view) {
124 super.onBindView(view);
125 getPreferenceManager().registerOnActivityStopListener(this);
129 final SeekBar seekBar = (SeekBar) view.findViewById(R.id.start_volume);
130 if (seekBar == mStartVolumeSeekBar) return;
132 mStartVolumeSeekBar = seekBar;
133 mRampUpTimeSeekBar = (SeekBar) view.findViewById(R.id.ramp_up_time);
134 mRampUpTimeValue = (TextView) view.findViewById(R.id.ramp_up_time_value);
136 final ContentResolver cr = getContext().getContentResolver();
137 float startVolume = CMSettings.System.getFloat(cr,
138 CMSettings.System.INCREASING_RING_START_VOLUME, 0.1f);
139 int rampUpTime = CMSettings.System.getInt(cr,
140 CMSettings.System.INCREASING_RING_RAMP_UP_TIME, 10);
142 mStartVolumeSeekBar.setProgress(Math.round(startVolume * 1000F));
143 mStartVolumeSeekBar.setOnSeekBarChangeListener(this);
144 mRampUpTimeSeekBar.setOnSeekBarChangeListener(this);
145 mRampUpTimeSeekBar.setProgress((rampUpTime / 5) - 1);
146 mRampUpTimeValue.setText(
147 Formatter.formatShortElapsedTime(getContext(), rampUpTime * 1000));
151 public void onStartTrackingTouch(SeekBar seekBar) {
155 public void onStopTrackingTouch(SeekBar seekBar) {
156 if (seekBar == mStartVolumeSeekBar) {
157 postStartSample(seekBar.getProgress());
162 public void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) {
163 ContentResolver cr = getContext().getContentResolver();
164 if (fromTouch && seekBar == mStartVolumeSeekBar) {
165 CMSettings.System.putFloat(cr, CMSettings.System.INCREASING_RING_START_VOLUME,
166 (float) progress / 1000F);
167 } else if (seekBar == mRampUpTimeSeekBar) {
168 int seconds = (progress + 1) * 5;
169 mRampUpTimeValue.setText(
170 Formatter.formatShortElapsedTime(getContext(), seconds * 1000));
172 CMSettings.System.putInt(cr,
173 CMSettings.System.INCREASING_RING_RAMP_UP_TIME, seconds);
178 private void initHandler() {
179 if (mHandler != null) return;
181 HandlerThread thread = new HandlerThread(TAG + ".CallbackHandler");
184 mHandler = new Handler(thread.getLooper(), this);
185 mHandler.sendEmptyMessage(MSG_INIT_SAMPLE);
188 private void onInitSample() {
189 mRingtone = RingtoneManager.getRingtone(getContext(),
190 Settings.System.DEFAULT_RINGTONE_URI);
191 if (mRingtone != null) {
192 mRingtone.setStreamType(AudioManager.STREAM_RING);
193 mRingtone.setAudioAttributes(
194 new AudioAttributes.Builder(mRingtone.getAudioAttributes())
195 .setFlags(AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY |
196 AudioAttributes.FLAG_BYPASS_MUTE)
201 private void postStartSample(int progress) {
202 boolean playing = isSamplePlaying();
203 mHandler.removeMessages(MSG_START_SAMPLE);
204 mHandler.removeMessages(MSG_SET_VOLUME);
205 mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_START_SAMPLE, progress, 0),
206 playing ? CHECK_RINGTONE_PLAYBACK_DELAY_MS : 0);
208 mHandler.sendMessage(mHandler.obtainMessage(MSG_SET_VOLUME, progress, 0));
212 private void onStartSample(float volume) {
213 if (mRingtone == null) {
216 if (!isSamplePlaying()) {
217 if (mCallback != null) {
218 mCallback.onStartingSample();
222 } catch (Throwable e) {
223 Log.w(TAG, "Error playing ringtone", e);
226 mRingtone.setVolume(volume);
229 private void onSetVolume(float volume) {
230 if (mRingtone != null) {
231 mRingtone.setVolume(volume);
235 private boolean isSamplePlaying() {
236 return mRingtone != null && mRingtone.isPlaying();
239 public void stopSample() {
240 if (mHandler != null) {
245 private void postStopSample() {
246 // remove pending delayed start messages
247 mHandler.removeMessages(MSG_START_SAMPLE);
248 mHandler.removeMessages(MSG_STOP_SAMPLE);
249 mHandler.sendEmptyMessage(MSG_STOP_SAMPLE);
252 private void onStopSample() {
253 if (mRingtone != null) {