blob: 89b7aaadd2d89aff078428b5573c486cb3a0d149 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007 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
17package android.view;
18
Amith Yamasani2bbdd772011-02-02 18:54:13 -080019import com.android.internal.R;
20
21import android.app.Dialog;
22import android.content.DialogInterface.OnDismissListener;
23import android.content.BroadcastReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080024import android.content.Context;
Amith Yamasani2bbdd772011-02-02 18:54:13 -080025import android.content.DialogInterface;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080026import android.content.Intent;
Amith Yamasani2bbdd772011-02-02 18:54:13 -080027import android.content.IntentFilter;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028import android.content.res.Resources;
Amith Yamasani2bbdd772011-02-02 18:54:13 -080029import android.graphics.drawable.Drawable;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080030import android.media.AudioManager;
31import android.media.AudioService;
32import android.media.AudioSystem;
Marco Nelissen69f593c2009-07-28 09:55:04 -070033import android.media.RingtoneManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.media.ToneGenerator;
Marco Nelissen69f593c2009-07-28 09:55:04 -070035import android.net.Uri;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.os.Handler;
37import android.os.Message;
38import android.os.Vibrator;
Amith Yamasani2bbdd772011-02-02 18:54:13 -080039import android.telephony.TelephonyManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040import android.util.Log;
41import android.widget.ImageView;
42import android.widget.ProgressBar;
Amith Yamasani2bbdd772011-02-02 18:54:13 -080043import android.widget.SeekBar;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044import android.widget.TextView;
45import android.widget.Toast;
Amith Yamasani2bbdd772011-02-02 18:54:13 -080046import android.widget.SeekBar.OnSeekBarChangeListener;
47
48import java.util.HashMap;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049
50/**
51 * Handle the volume up and down keys.
52 *
53 * This code really should be moved elsewhere.
54 *
55 * @hide
56 */
Amith Yamasani2bbdd772011-02-02 18:54:13 -080057public class VolumePanel extends Handler implements OnSeekBarChangeListener, View.OnClickListener
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058{
59 private static final String TAG = "VolumePanel";
Marco Nelissen69f593c2009-07-28 09:55:04 -070060 private static boolean LOGD = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080061
62 /**
63 * The delay before playing a sound. This small period exists so the user
64 * can press another key (non-volume keys, too) to have it NOT be audible.
65 * <p>
66 * PhoneWindow will implement this part.
67 */
68 public static final int PLAY_SOUND_DELAY = 300;
69
70 /**
71 * The delay before vibrating. This small period exists so if the user is
72 * moving to silent mode, it will not emit a short vibrate (it normally
73 * would since vibrate is between normal mode and silent mode using hardware
74 * keys).
75 */
76 public static final int VIBRATE_DELAY = 300;
77
78 private static final int VIBRATE_DURATION = 300;
79 private static final int BEEP_DURATION = 150;
80 private static final int MAX_VOLUME = 100;
81 private static final int FREE_DELAY = 10000;
Amith Yamasani2bbdd772011-02-02 18:54:13 -080082 private static final int TIMEOUT_DELAY = 3000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080083
84 private static final int MSG_VOLUME_CHANGED = 0;
85 private static final int MSG_FREE_RESOURCES = 1;
86 private static final int MSG_PLAY_SOUND = 2;
87 private static final int MSG_STOP_SOUNDS = 3;
88 private static final int MSG_VIBRATE = 4;
Amith Yamasani2bbdd772011-02-02 18:54:13 -080089 private static final int MSG_TIMEOUT = 5;
90 private static final int MSG_RINGER_MODE_CHANGED = 6;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091
Amith Yamasani2bbdd772011-02-02 18:54:13 -080092// private static final int RINGTONE_VOLUME_TEXT = com.android.internal.R.string.volume_ringtone;
93// private static final int MUSIC_VOLUME_TEXT = com.android.internal.R.string.volume_music;
94// private static final int INCALL_VOLUME_TEXT = com.android.internal.R.string.volume_call;
95// private static final int ALARM_VOLUME_TEXT = com.android.internal.R.string.volume_alarm;
96// private static final int UNKNOWN_VOLUME_TEXT = com.android.internal.R.string.volume_unknown;
97// private static final int NOTIFICATION_VOLUME_TEXT =
98// com.android.internal.R.string.volume_notification;
99// private static final int BLUETOOTH_INCALL_VOLUME_TEXT =
100// com.android.internal.R.string.volume_bluetooth_call;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800101
102 protected Context mContext;
103 private AudioManager mAudioManager;
104 protected AudioService mAudioService;
Marco Nelissen69f593c2009-07-28 09:55:04 -0700105 private boolean mRingIsSilent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800107 /** Dialog containing all the sliders */
108 private final Dialog mDialog;
109 /** Dialog's content view */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800110 private final View mView;
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800111// private final TextView mMessage;
112// private final TextView mAdditionalMessage;
113// private final ImageView mSmallStreamIcon;
114// private final ImageView mLargeStreamIcon;
115// private final ProgressBar mLevel;
116
117 /** Contains the sliders and their touchable icons */
118 private final ViewGroup mSliderGroup;
119 /** The button that expands the dialog to show all sliders */
120 private final View mMoreButton;
121 /** Dummy divider icon that needs to vanish with the more button */
122 private final View mDivider;
123
124 /** Currently active stream that shows up at the top of the list of sliders */
125 private int mActiveStreamType = -1;
126 /** All the slider controls mapped by stream type */
127 private HashMap<Integer,StreamControl> mStreamControls;
128
129 // List of stream types and their order
130 // RING and VOICE_CALL are hidden unless explicitly requested
131 private static final int [] STREAM_TYPES = {
132 AudioManager.STREAM_RING,
133 AudioManager.STREAM_VOICE_CALL,
134 AudioManager.STREAM_MUSIC,
135 AudioManager.STREAM_NOTIFICATION
136 };
137
138 // These icons need to correspond to the ones above.
139 private static final int [] STREAM_ICONS_NORMAL = {
140 R.drawable.ic_audio_phone,
141 R.drawable.ic_audio_phone,
142 R.drawable.ic_audio_vol,
143 R.drawable.ic_audio_notification,
144 };
145
146 // These icons need to correspond to the ones above.
147 private static final int [] STREAM_ICONS_MUTED = {
148 R.drawable.ic_audio_phone,
149 R.drawable.ic_audio_phone,
150 R.drawable.ic_audio_vol_mute,
151 R.drawable.ic_audio_notification_mute,
152 };
153
154 /** Object that contains data for each slider */
155 private class StreamControl {
156 int streamType;
157 ViewGroup group;
158 ImageView icon;
159 SeekBar seekbarView;
160 int iconRes;
161 int iconMuteRes;
162 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800163
164 // Synchronize when accessing this
165 private ToneGenerator mToneGenerators[];
166 private Vibrator mVibrator;
167
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800168 public VolumePanel(final Context context, AudioService volumeService) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800169 mContext = context;
170 mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
171 mAudioService = volumeService;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800172
173 LayoutInflater inflater = (LayoutInflater) context
174 .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800175 View view = mView = inflater.inflate(R.layout.volume_adjust, null);
176 mView.setOnTouchListener(new View.OnTouchListener() {
177 public boolean onTouch(View v, MotionEvent event) {
178 resetTimeout();
179 return true;
180 }
181 });
182 mSliderGroup = (ViewGroup) mView.findViewById(R.id.slider_group);
183 mMoreButton = (ImageView) mView.findViewById(R.id.expand_button);
184 mMoreButton.setOnClickListener(this);
185 mDivider = (ImageView) mView.findViewById(R.id.expand_button_divider);
186
187 mDialog = new Dialog(context, R.style.Theme_Panel_Volume);
188 mDialog.setTitle("Volume control"); // No need to localize
189 mDialog.setContentView(mView);
190 mDialog.setOnDismissListener(new OnDismissListener() {
191 public void onDismiss(DialogInterface dialog) {
192 mActiveStreamType = -1;
Eric Laurent402f7f22011-02-04 12:30:32 -0800193 mAudioManager.forceVolumeControlStream(mActiveStreamType);
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800194 }
195 });
196 // Change some window properties
197 Window window = mDialog.getWindow();
198 window.setGravity(Gravity.TOP);
199 WindowManager.LayoutParams lp = window.getAttributes();
200 lp.token = null;
201 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
202 window.setAttributes(lp);
203 window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
204
205// mMessage = (TextView) view.findViewById(com.android.internal.R.id.message);
206// mAdditionalMessage =
207// (TextView) view.findViewById(com.android.internal.R.id.additional_message);
208// mSmallStreamIcon = (ImageView) view.findViewById(com.android.internal.R.id.other_stream_icon);
209// mLargeStreamIcon = (ImageView) view.findViewById(com.android.internal.R.id.ringer_stream_icon);
210// mLevel = (ProgressBar) view.findViewById(com.android.internal.R.id.level);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800211
212 mToneGenerators = new ToneGenerator[AudioSystem.getNumStreamTypes()];
213 mVibrator = new Vibrator();
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800214
215 listenToRingerMode();
216 }
217
218 private void listenToRingerMode() {
219 final IntentFilter filter = new IntentFilter();
220 filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
221 mContext.registerReceiver(new BroadcastReceiver() {
222
223 public void onReceive(Context context, Intent intent) {
224 final String action = intent.getAction();
225
226 if (AudioManager.RINGER_MODE_CHANGED_ACTION.equals(action)) {
227 removeMessages(MSG_RINGER_MODE_CHANGED);
228 sendMessage(obtainMessage(MSG_RINGER_MODE_CHANGED));
229 }
230 }
231 }, filter);
232 }
233
234 private boolean isMuted(int streamType) {
235 return mAudioManager.isStreamMute(streamType);
236 }
237
238 private void createSliders() {
239 LayoutInflater inflater = (LayoutInflater) mContext
240 .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
241 mStreamControls = new HashMap<Integer,StreamControl>(STREAM_TYPES.length);
242 for (int i = 0; i < STREAM_TYPES.length; i++) {
243 StreamControl sc = new StreamControl();
244 sc.streamType = STREAM_TYPES[i];
245 sc.group = (ViewGroup) inflater.inflate(R.layout.volume_adjust_item, null);
246 sc.group.setTag(sc);
247 sc.icon = (ImageView) sc.group.findViewById(R.id.stream_icon);
248 sc.icon.setOnClickListener(this);
249 sc.icon.setTag(sc);
250 sc.iconRes = STREAM_ICONS_NORMAL[i];
251 sc.iconMuteRes = STREAM_ICONS_MUTED[i];
252 sc.icon.setImageResource(sc.iconRes);
253 sc.seekbarView = (SeekBar) sc.group.findViewById(R.id.seekbar);
254 sc.seekbarView.setMax(mAudioManager.getStreamMaxVolume(STREAM_TYPES[i]));
255 sc.seekbarView.setOnSeekBarChangeListener(this);
256 sc.seekbarView.setTag(sc);
257 mStreamControls.put(STREAM_TYPES[i], sc);
258 }
259 }
260
261 private void reorderSliders(int activeStreamType) {
262 mSliderGroup.removeAllViews();
263
264 StreamControl active = mStreamControls.get(activeStreamType);
265 if (active == null) {
266 Log.e("VolumePanel", "Missing stream type! - " + activeStreamType);
267 mActiveStreamType = -1;
268 } else {
269 mSliderGroup.addView(active.group);
270 mActiveStreamType = activeStreamType;
271 active.group.setVisibility(View.VISIBLE);
272 updateSlider(active);
273 }
274
275 for (int i = 0; i < STREAM_TYPES.length; i++) {
276 // Skip the phone specific ones and the active one
277 final int streamType = STREAM_TYPES[i];
278 if (streamType == AudioManager.STREAM_RING
279 || streamType == AudioManager.STREAM_VOICE_CALL
280 || streamType == activeStreamType) {
281 continue;
282 }
283 StreamControl sc = mStreamControls.get(streamType);
284 mSliderGroup.addView(sc.group);
285 updateSlider(sc);
286 }
287 }
288
289 /** Update the mute and progress state of a slider */
290 private void updateSlider(StreamControl sc) {
291 sc.seekbarView.setProgress(mAudioManager.getLastAudibleStreamVolume(sc.streamType));
292 final boolean muted = isMuted(sc.streamType);
293 sc.icon.setImageResource(muted ? sc.iconMuteRes : sc.iconRes);
294 sc.seekbarView.setEnabled(!muted);
295 }
296
297 private boolean isExpanded() {
298 return mMoreButton.getVisibility() != View.VISIBLE;
299 }
300
301 private void expand() {
302 final int count = mSliderGroup.getChildCount();
303 for (int i = 0; i < count; i++) {
304 mSliderGroup.getChildAt(i).setVisibility(View.VISIBLE);
305 }
306 mMoreButton.setVisibility(View.INVISIBLE);
307 mDivider.setVisibility(View.INVISIBLE);
308 }
309
310 private void collapse() {
311 mMoreButton.setVisibility(View.VISIBLE);
312 mDivider.setVisibility(View.VISIBLE);
313 final int count = mSliderGroup.getChildCount();
314 for (int i = 1; i < count; i++) {
315 mSliderGroup.getChildAt(i).setVisibility(View.GONE);
316 }
317 }
318
319 private void updateStates() {
320 final int count = mSliderGroup.getChildCount();
321 for (int i = 0; i < count; i++) {
322 StreamControl sc = (StreamControl) mSliderGroup.getChildAt(i).getTag();
323 updateSlider(sc);
324 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800325 }
326
327 public void postVolumeChanged(int streamType, int flags) {
328 if (hasMessages(MSG_VOLUME_CHANGED)) return;
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800329 if (mStreamControls == null) {
330 createSliders();
331 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800332 removeMessages(MSG_FREE_RESOURCES);
333 obtainMessage(MSG_VOLUME_CHANGED, streamType, flags).sendToTarget();
334 }
335
336 /**
337 * Override this if you have other work to do when the volume changes (for
338 * example, vibrating, playing a sound, etc.). Make sure to call through to
339 * the superclass implementation.
340 */
341 protected void onVolumeChanged(int streamType, int flags) {
342
343 if (LOGD) Log.d(TAG, "onVolumeChanged(streamType: " + streamType + ", flags: " + flags + ")");
344
345 if ((flags & AudioManager.FLAG_SHOW_UI) != 0) {
Amith Yamasanie3361b82011-02-10 18:20:50 -0800346 if (mActiveStreamType == -1) {
347 reorderSliders(streamType);
348 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800349 onShowVolumeChanged(streamType, flags);
350 }
351
Marco Nelissen69f593c2009-07-28 09:55:04 -0700352 if ((flags & AudioManager.FLAG_PLAY_SOUND) != 0 && ! mRingIsSilent) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800353 removeMessages(MSG_PLAY_SOUND);
354 sendMessageDelayed(obtainMessage(MSG_PLAY_SOUND, streamType, flags), PLAY_SOUND_DELAY);
355 }
356
357 if ((flags & AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE) != 0) {
358 removeMessages(MSG_PLAY_SOUND);
359 removeMessages(MSG_VIBRATE);
360 onStopSounds();
361 }
362
363 removeMessages(MSG_FREE_RESOURCES);
364 sendMessageDelayed(obtainMessage(MSG_FREE_RESOURCES), FREE_DELAY);
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800365
366 resetTimeout();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800367 }
368
369 protected void onShowVolumeChanged(int streamType, int flags) {
Eric Laurentd72d51c2011-02-03 18:47:47 -0800370 int index = mAudioService.isStreamMute(streamType) ?
371 mAudioService.getLastAudibleStreamVolume(streamType)
372 : mAudioService.getStreamVolume(streamType);
373
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800374// int message = UNKNOWN_VOLUME_TEXT;
375// int additionalMessage = 0;
Marco Nelissen69f593c2009-07-28 09:55:04 -0700376 mRingIsSilent = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800377
378 if (LOGD) {
379 Log.d(TAG, "onShowVolumeChanged(streamType: " + streamType
380 + ", flags: " + flags + "), index: " + index);
381 }
382
383 // get max volume for progress bar
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800384
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800385 int max = mAudioService.getStreamMaxVolume(streamType);
386
387 switch (streamType) {
388
389 case AudioManager.STREAM_RING: {
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800390// setRingerIcon();
391// message = RINGTONE_VOLUME_TEXT;
Marco Nelissen69f593c2009-07-28 09:55:04 -0700392 Uri ringuri = RingtoneManager.getActualDefaultRingtoneUri(
393 mContext, RingtoneManager.TYPE_RINGTONE);
394 if (ringuri == null) {
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800395// additionalMessage =
396// com.android.internal.R.string.volume_music_hint_silent_ringtone_selected;
Marco Nelissen69f593c2009-07-28 09:55:04 -0700397 mRingIsSilent = true;
398 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800399 break;
400 }
401
402 case AudioManager.STREAM_MUSIC: {
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800403// message = MUSIC_VOLUME_TEXT;
404 // Special case for when Bluetooth is active for music
Glenn Kasten8b4b97a2011-02-04 13:54:26 -0800405 if ((mAudioManager.getDevicesForStream(AudioManager.STREAM_MUSIC) &
406 (AudioManager.DEVICE_OUT_BLUETOOTH_A2DP |
407 AudioManager.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
408 AudioManager.DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER)) != 0) {
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800409// additionalMessage =
410// com.android.internal.R.string.volume_music_hint_playing_through_bluetooth;
411// setLargeIcon(com.android.internal.R.drawable.ic_volume_bluetooth_ad2p);
412 setMusicIcon(R.drawable.ic_audio_bt, R.drawable.ic_audio_bt_mute);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800413 } else {
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800414 setMusicIcon(R.drawable.ic_audio_vol, R.drawable.ic_audio_vol_mute);
415// setSmallIcon(index);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800416 }
417 break;
418 }
419
420 case AudioManager.STREAM_VOICE_CALL: {
421 /*
422 * For in-call voice call volume, there is no inaudible volume.
423 * Rescale the UI control so the progress bar doesn't go all
424 * the way to zero and don't show the mute icon.
425 */
426 index++;
427 max++;
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800428// message = INCALL_VOLUME_TEXT;
429// setSmallIcon(index);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800430 break;
431 }
432
433 case AudioManager.STREAM_ALARM: {
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800434// message = ALARM_VOLUME_TEXT;
435// setSmallIcon(index);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800436 break;
437 }
438
439 case AudioManager.STREAM_NOTIFICATION: {
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800440// message = NOTIFICATION_VOLUME_TEXT;
441// setSmallIcon(index);
Marco Nelissen69f593c2009-07-28 09:55:04 -0700442 Uri ringuri = RingtoneManager.getActualDefaultRingtoneUri(
443 mContext, RingtoneManager.TYPE_NOTIFICATION);
444 if (ringuri == null) {
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800445// additionalMessage =
446// com.android.internal.R.string.volume_music_hint_silent_ringtone_selected;
Marco Nelissen69f593c2009-07-28 09:55:04 -0700447 mRingIsSilent = true;
448 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800449 break;
450 }
451
452 case AudioManager.STREAM_BLUETOOTH_SCO: {
453 /*
454 * For in-call voice call volume, there is no inaudible volume.
455 * Rescale the UI control so the progress bar doesn't go all
456 * the way to zero and don't show the mute icon.
457 */
458 index++;
459 max++;
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800460// message = BLUETOOTH_INCALL_VOLUME_TEXT;
461// setLargeIcon(com.android.internal.R.drawable.ic_volume_bluetooth_in_call);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800462 break;
463 }
464 }
465
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800466// String messageString = Resources.getSystem().getString(message);
467// if (!mMessage.getText().equals(messageString)) {
468// mMessage.setText(messageString);
469// }
470//
471// if (additionalMessage == 0) {
472// mAdditionalMessage.setVisibility(View.GONE);
473// } else {
474// mAdditionalMessage.setVisibility(View.VISIBLE);
475// mAdditionalMessage.setText(Resources.getSystem().getString(additionalMessage));
476// }
477
478// if (max != mLevel.getMax()) {
479// mLevel.setMax(max);
480// }
481// mLevel.setProgress(index);
482
483 StreamControl sc = mStreamControls.get(streamType);
484 if (sc != null) {
485 sc.seekbarView.setProgress(index);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800486 }
487
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800488 if (!mDialog.isShowing()) {
Eric Laurent402f7f22011-02-04 12:30:32 -0800489 mAudioManager.forceVolumeControlStream(streamType);
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800490 mDialog.setContentView(mView);
491 // Showing dialog - use collapsed state
492 collapse();
493 mDialog.show();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800494 }
495
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800496 // Do a little vibrate if applicable (only when going into vibrate mode)
497 if ((flags & AudioManager.FLAG_VIBRATE) != 0 &&
498 mAudioService.isStreamAffectedByRingerMode(streamType) &&
499 mAudioService.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE &&
500 mAudioService.shouldVibrate(AudioManager.VIBRATE_TYPE_RINGER)) {
501 sendMessageDelayed(obtainMessage(MSG_VIBRATE), VIBRATE_DELAY);
502 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800503 }
504
505 protected void onPlaySound(int streamType, int flags) {
506
507 if (hasMessages(MSG_STOP_SOUNDS)) {
508 removeMessages(MSG_STOP_SOUNDS);
509 // Force stop right now
510 onStopSounds();
511 }
512
513 synchronized (this) {
514 ToneGenerator toneGen = getOrCreateToneGenerator(streamType);
Eric Laurent733a42b2011-01-19 10:41:57 -0800515 if (toneGen != null) {
516 toneGen.startTone(ToneGenerator.TONE_PROP_BEEP);
517 sendMessageDelayed(obtainMessage(MSG_STOP_SOUNDS), BEEP_DURATION);
518 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800519 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800520 }
521
522 protected void onStopSounds() {
523
524 synchronized (this) {
525 int numStreamTypes = AudioSystem.getNumStreamTypes();
526 for (int i = numStreamTypes - 1; i >= 0; i--) {
527 ToneGenerator toneGen = mToneGenerators[i];
528 if (toneGen != null) {
529 toneGen.stopTone();
530 }
531 }
532 }
533 }
534
535 protected void onVibrate() {
536
537 // Make sure we ended up in vibrate ringer mode
538 if (mAudioService.getRingerMode() != AudioManager.RINGER_MODE_VIBRATE) {
539 return;
540 }
541
542 mVibrator.vibrate(VIBRATE_DURATION);
543 }
544
545 /**
546 * Lock on this VolumePanel instance as long as you use the returned ToneGenerator.
547 */
548 private ToneGenerator getOrCreateToneGenerator(int streamType) {
549 synchronized (this) {
550 if (mToneGenerators[streamType] == null) {
Eric Laurent733a42b2011-01-19 10:41:57 -0800551 try {
552 mToneGenerators[streamType] = new ToneGenerator(streamType, MAX_VOLUME);
553 } catch (RuntimeException e) {
554 if (LOGD) {
555 Log.d(TAG, "ToneGenerator constructor failed with "
556 + "RuntimeException: " + e);
557 }
558 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800559 }
Eric Laurent733a42b2011-01-19 10:41:57 -0800560 return mToneGenerators[streamType];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800561 }
562 }
563
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800564// /**
565// * Makes the small icon visible, and hides the large icon.
566// *
567// * @param index The volume index, where 0 means muted.
568// */
569// private void setSmallIcon(int index) {
570// mLargeStreamIcon.setVisibility(View.GONE);
571// mSmallStreamIcon.setVisibility(View.VISIBLE);
572//
573// mSmallStreamIcon.setImageResource(index == 0
574// ? com.android.internal.R.drawable.ic_volume_off_small
575// : com.android.internal.R.drawable.ic_volume_small);
576// }
577//
578// /**
579// * Makes the large image view visible with the given icon.
580// *
581// * @param resId The icon to display.
582// */
583// private void setLargeIcon(int resId) {
584// mSmallStreamIcon.setVisibility(View.GONE);
585// mLargeStreamIcon.setVisibility(View.VISIBLE);
586// mLargeStreamIcon.setImageResource(resId);
587// }
588//
589// /**
590// * Makes the ringer icon visible with an icon that is chosen
591// * based on the current ringer mode.
592// */
593// private void setRingerIcon() {
594// mSmallStreamIcon.setVisibility(View.GONE);
595// mLargeStreamIcon.setVisibility(View.VISIBLE);
596//
597// int ringerMode = mAudioService.getRingerMode();
598// int icon;
599//
600// if (LOGD) Log.d(TAG, "setRingerIcon(), ringerMode: " + ringerMode);
601//
602// if (ringerMode == AudioManager.RINGER_MODE_SILENT) {
603// icon = com.android.internal.R.drawable.ic_volume_off;
604// } else if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
605// icon = com.android.internal.R.drawable.ic_vibrate;
606// } else {
607// icon = com.android.internal.R.drawable.ic_volume;
608// }
609// mLargeStreamIcon.setImageResource(icon);
610// }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800611
612 /**
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800613 * Switch between icons because Bluetooth music is same as music volume, but with
614 * different icons.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800615 */
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800616 private void setMusicIcon(int resId, int resMuteId) {
617 StreamControl sc = mStreamControls.get(AudioManager.STREAM_MUSIC);
618 if (sc != null) {
619 sc.iconRes = resId;
620 sc.iconMuteRes = resMuteId;
621 sc.icon.setImageResource(isMuted(sc.streamType) ? sc.iconMuteRes : sc.iconRes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800622 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800623 }
624
625 protected void onFreeResources() {
626 // We'll keep the views, just ditch the cached drawable and hence
627 // bitmaps
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800628// mSmallStreamIcon.setImageDrawable(null);
629// mLargeStreamIcon.setImageDrawable(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800630
631 synchronized (this) {
632 for (int i = mToneGenerators.length - 1; i >= 0; i--) {
633 if (mToneGenerators[i] != null) {
634 mToneGenerators[i].release();
635 }
636 mToneGenerators[i] = null;
637 }
638 }
639 }
640
641 @Override
642 public void handleMessage(Message msg) {
643 switch (msg.what) {
644
645 case MSG_VOLUME_CHANGED: {
646 onVolumeChanged(msg.arg1, msg.arg2);
647 break;
648 }
649
650 case MSG_FREE_RESOURCES: {
651 onFreeResources();
652 break;
653 }
654
655 case MSG_STOP_SOUNDS: {
656 onStopSounds();
657 break;
658 }
659
660 case MSG_PLAY_SOUND: {
661 onPlaySound(msg.arg1, msg.arg2);
662 break;
663 }
664
665 case MSG_VIBRATE: {
666 onVibrate();
667 break;
668 }
669
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800670 case MSG_TIMEOUT: {
671 if (mDialog.isShowing()) {
672 mDialog.dismiss();
673 mActiveStreamType = -1;
674 }
675 break;
676 }
677 case MSG_RINGER_MODE_CHANGED: {
678 if (mDialog.isShowing()) {
679 updateStates();
680 }
681 break;
682 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800683 }
684 }
685
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800686 private void resetTimeout() {
687 removeMessages(MSG_TIMEOUT);
688 sendMessageDelayed(obtainMessage(MSG_TIMEOUT), TIMEOUT_DELAY);
689 }
690
691 public void onProgressChanged(SeekBar seekBar, int progress,
692 boolean fromUser) {
693 final Object tag = seekBar.getTag();
694 if (fromUser && tag instanceof StreamControl) {
695 StreamControl sc = (StreamControl) tag;
696 if (mAudioManager.getStreamVolume(sc.streamType) != progress) {
697 mAudioManager.setStreamVolume(sc.streamType, progress, 0);
698 }
699 }
700 resetTimeout();
701 }
702
703 public void onStartTrackingTouch(SeekBar seekBar) {
704 }
705
706 public void onStopTrackingTouch(SeekBar seekBar) {
707 }
708
709 public void onClick(View v) {
710 if (v == mMoreButton) {
711 expand();
712 } else if (v.getTag() instanceof StreamControl) {
713 StreamControl sc = (StreamControl) v.getTag();
714 mAudioManager.setRingerMode(mAudioManager.isSilentMode()
715 ? AudioManager.RINGER_MODE_NORMAL : AudioManager.RINGER_MODE_SILENT);
716 // Expand the dialog if it hasn't been expanded yet.
717 if (!isExpanded()) expand();
718 }
719 resetTimeout();
720 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800721}