blob: a67ce170a701fca0e7a31a2a811a20b5906f6f3b [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
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800345 if (mActiveStreamType == -1) {
346 reorderSliders(streamType);
347 }
348
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800349 if ((flags & AudioManager.FLAG_SHOW_UI) != 0) {
350 onShowVolumeChanged(streamType, flags);
351 }
352
Marco Nelissen69f593c2009-07-28 09:55:04 -0700353 if ((flags & AudioManager.FLAG_PLAY_SOUND) != 0 && ! mRingIsSilent) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800354 removeMessages(MSG_PLAY_SOUND);
355 sendMessageDelayed(obtainMessage(MSG_PLAY_SOUND, streamType, flags), PLAY_SOUND_DELAY);
356 }
357
358 if ((flags & AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE) != 0) {
359 removeMessages(MSG_PLAY_SOUND);
360 removeMessages(MSG_VIBRATE);
361 onStopSounds();
362 }
363
364 removeMessages(MSG_FREE_RESOURCES);
365 sendMessageDelayed(obtainMessage(MSG_FREE_RESOURCES), FREE_DELAY);
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800366
367 resetTimeout();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800368 }
369
370 protected void onShowVolumeChanged(int streamType, int flags) {
Eric Laurentd72d51c2011-02-03 18:47:47 -0800371 int index = mAudioService.isStreamMute(streamType) ?
372 mAudioService.getLastAudibleStreamVolume(streamType)
373 : mAudioService.getStreamVolume(streamType);
374
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800375// int message = UNKNOWN_VOLUME_TEXT;
376// int additionalMessage = 0;
Marco Nelissen69f593c2009-07-28 09:55:04 -0700377 mRingIsSilent = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800378
379 if (LOGD) {
380 Log.d(TAG, "onShowVolumeChanged(streamType: " + streamType
381 + ", flags: " + flags + "), index: " + index);
382 }
383
384 // get max volume for progress bar
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800385
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800386 int max = mAudioService.getStreamMaxVolume(streamType);
387
388 switch (streamType) {
389
390 case AudioManager.STREAM_RING: {
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800391// setRingerIcon();
392// message = RINGTONE_VOLUME_TEXT;
Marco Nelissen69f593c2009-07-28 09:55:04 -0700393 Uri ringuri = RingtoneManager.getActualDefaultRingtoneUri(
394 mContext, RingtoneManager.TYPE_RINGTONE);
395 if (ringuri == null) {
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800396// additionalMessage =
397// com.android.internal.R.string.volume_music_hint_silent_ringtone_selected;
Marco Nelissen69f593c2009-07-28 09:55:04 -0700398 mRingIsSilent = true;
399 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800400 break;
401 }
402
403 case AudioManager.STREAM_MUSIC: {
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800404// message = MUSIC_VOLUME_TEXT;
405 // Special case for when Bluetooth is active for music
Glenn Kasten8b4b97a2011-02-04 13:54:26 -0800406 if ((mAudioManager.getDevicesForStream(AudioManager.STREAM_MUSIC) &
407 (AudioManager.DEVICE_OUT_BLUETOOTH_A2DP |
408 AudioManager.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
409 AudioManager.DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER)) != 0) {
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800410// additionalMessage =
411// com.android.internal.R.string.volume_music_hint_playing_through_bluetooth;
412// setLargeIcon(com.android.internal.R.drawable.ic_volume_bluetooth_ad2p);
413 setMusicIcon(R.drawable.ic_audio_bt, R.drawable.ic_audio_bt_mute);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800414 } else {
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800415 setMusicIcon(R.drawable.ic_audio_vol, R.drawable.ic_audio_vol_mute);
416// setSmallIcon(index);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800417 }
418 break;
419 }
420
421 case AudioManager.STREAM_VOICE_CALL: {
422 /*
423 * For in-call voice call volume, there is no inaudible volume.
424 * Rescale the UI control so the progress bar doesn't go all
425 * the way to zero and don't show the mute icon.
426 */
427 index++;
428 max++;
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800429// message = INCALL_VOLUME_TEXT;
430// setSmallIcon(index);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800431 break;
432 }
433
434 case AudioManager.STREAM_ALARM: {
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800435// message = ALARM_VOLUME_TEXT;
436// setSmallIcon(index);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800437 break;
438 }
439
440 case AudioManager.STREAM_NOTIFICATION: {
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800441// message = NOTIFICATION_VOLUME_TEXT;
442// setSmallIcon(index);
Marco Nelissen69f593c2009-07-28 09:55:04 -0700443 Uri ringuri = RingtoneManager.getActualDefaultRingtoneUri(
444 mContext, RingtoneManager.TYPE_NOTIFICATION);
445 if (ringuri == null) {
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800446// additionalMessage =
447// com.android.internal.R.string.volume_music_hint_silent_ringtone_selected;
Marco Nelissen69f593c2009-07-28 09:55:04 -0700448 mRingIsSilent = true;
449 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800450 break;
451 }
452
453 case AudioManager.STREAM_BLUETOOTH_SCO: {
454 /*
455 * For in-call voice call volume, there is no inaudible volume.
456 * Rescale the UI control so the progress bar doesn't go all
457 * the way to zero and don't show the mute icon.
458 */
459 index++;
460 max++;
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800461// message = BLUETOOTH_INCALL_VOLUME_TEXT;
462// setLargeIcon(com.android.internal.R.drawable.ic_volume_bluetooth_in_call);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800463 break;
464 }
465 }
466
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800467// String messageString = Resources.getSystem().getString(message);
468// if (!mMessage.getText().equals(messageString)) {
469// mMessage.setText(messageString);
470// }
471//
472// if (additionalMessage == 0) {
473// mAdditionalMessage.setVisibility(View.GONE);
474// } else {
475// mAdditionalMessage.setVisibility(View.VISIBLE);
476// mAdditionalMessage.setText(Resources.getSystem().getString(additionalMessage));
477// }
478
479// if (max != mLevel.getMax()) {
480// mLevel.setMax(max);
481// }
482// mLevel.setProgress(index);
483
484 StreamControl sc = mStreamControls.get(streamType);
485 if (sc != null) {
486 sc.seekbarView.setProgress(index);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800487 }
488
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800489 if (!mDialog.isShowing()) {
Eric Laurent402f7f22011-02-04 12:30:32 -0800490 mAudioManager.forceVolumeControlStream(streamType);
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800491 mDialog.setContentView(mView);
492 // Showing dialog - use collapsed state
493 collapse();
494 mDialog.show();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800495 }
496
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800497 // Do a little vibrate if applicable (only when going into vibrate mode)
498 if ((flags & AudioManager.FLAG_VIBRATE) != 0 &&
499 mAudioService.isStreamAffectedByRingerMode(streamType) &&
500 mAudioService.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE &&
501 mAudioService.shouldVibrate(AudioManager.VIBRATE_TYPE_RINGER)) {
502 sendMessageDelayed(obtainMessage(MSG_VIBRATE), VIBRATE_DELAY);
503 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800504 }
505
506 protected void onPlaySound(int streamType, int flags) {
507
508 if (hasMessages(MSG_STOP_SOUNDS)) {
509 removeMessages(MSG_STOP_SOUNDS);
510 // Force stop right now
511 onStopSounds();
512 }
513
514 synchronized (this) {
515 ToneGenerator toneGen = getOrCreateToneGenerator(streamType);
Eric Laurent733a42b2011-01-19 10:41:57 -0800516 if (toneGen != null) {
517 toneGen.startTone(ToneGenerator.TONE_PROP_BEEP);
518 sendMessageDelayed(obtainMessage(MSG_STOP_SOUNDS), BEEP_DURATION);
519 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800520 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800521 }
522
523 protected void onStopSounds() {
524
525 synchronized (this) {
526 int numStreamTypes = AudioSystem.getNumStreamTypes();
527 for (int i = numStreamTypes - 1; i >= 0; i--) {
528 ToneGenerator toneGen = mToneGenerators[i];
529 if (toneGen != null) {
530 toneGen.stopTone();
531 }
532 }
533 }
534 }
535
536 protected void onVibrate() {
537
538 // Make sure we ended up in vibrate ringer mode
539 if (mAudioService.getRingerMode() != AudioManager.RINGER_MODE_VIBRATE) {
540 return;
541 }
542
543 mVibrator.vibrate(VIBRATE_DURATION);
544 }
545
546 /**
547 * Lock on this VolumePanel instance as long as you use the returned ToneGenerator.
548 */
549 private ToneGenerator getOrCreateToneGenerator(int streamType) {
550 synchronized (this) {
551 if (mToneGenerators[streamType] == null) {
Eric Laurent733a42b2011-01-19 10:41:57 -0800552 try {
553 mToneGenerators[streamType] = new ToneGenerator(streamType, MAX_VOLUME);
554 } catch (RuntimeException e) {
555 if (LOGD) {
556 Log.d(TAG, "ToneGenerator constructor failed with "
557 + "RuntimeException: " + e);
558 }
559 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800560 }
Eric Laurent733a42b2011-01-19 10:41:57 -0800561 return mToneGenerators[streamType];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800562 }
563 }
564
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800565// /**
566// * Makes the small icon visible, and hides the large icon.
567// *
568// * @param index The volume index, where 0 means muted.
569// */
570// private void setSmallIcon(int index) {
571// mLargeStreamIcon.setVisibility(View.GONE);
572// mSmallStreamIcon.setVisibility(View.VISIBLE);
573//
574// mSmallStreamIcon.setImageResource(index == 0
575// ? com.android.internal.R.drawable.ic_volume_off_small
576// : com.android.internal.R.drawable.ic_volume_small);
577// }
578//
579// /**
580// * Makes the large image view visible with the given icon.
581// *
582// * @param resId The icon to display.
583// */
584// private void setLargeIcon(int resId) {
585// mSmallStreamIcon.setVisibility(View.GONE);
586// mLargeStreamIcon.setVisibility(View.VISIBLE);
587// mLargeStreamIcon.setImageResource(resId);
588// }
589//
590// /**
591// * Makes the ringer icon visible with an icon that is chosen
592// * based on the current ringer mode.
593// */
594// private void setRingerIcon() {
595// mSmallStreamIcon.setVisibility(View.GONE);
596// mLargeStreamIcon.setVisibility(View.VISIBLE);
597//
598// int ringerMode = mAudioService.getRingerMode();
599// int icon;
600//
601// if (LOGD) Log.d(TAG, "setRingerIcon(), ringerMode: " + ringerMode);
602//
603// if (ringerMode == AudioManager.RINGER_MODE_SILENT) {
604// icon = com.android.internal.R.drawable.ic_volume_off;
605// } else if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
606// icon = com.android.internal.R.drawable.ic_vibrate;
607// } else {
608// icon = com.android.internal.R.drawable.ic_volume;
609// }
610// mLargeStreamIcon.setImageResource(icon);
611// }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800612
613 /**
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800614 * Switch between icons because Bluetooth music is same as music volume, but with
615 * different icons.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800616 */
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800617 private void setMusicIcon(int resId, int resMuteId) {
618 StreamControl sc = mStreamControls.get(AudioManager.STREAM_MUSIC);
619 if (sc != null) {
620 sc.iconRes = resId;
621 sc.iconMuteRes = resMuteId;
622 sc.icon.setImageResource(isMuted(sc.streamType) ? sc.iconMuteRes : sc.iconRes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800623 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800624 }
625
626 protected void onFreeResources() {
627 // We'll keep the views, just ditch the cached drawable and hence
628 // bitmaps
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800629// mSmallStreamIcon.setImageDrawable(null);
630// mLargeStreamIcon.setImageDrawable(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800631
632 synchronized (this) {
633 for (int i = mToneGenerators.length - 1; i >= 0; i--) {
634 if (mToneGenerators[i] != null) {
635 mToneGenerators[i].release();
636 }
637 mToneGenerators[i] = null;
638 }
639 }
640 }
641
642 @Override
643 public void handleMessage(Message msg) {
644 switch (msg.what) {
645
646 case MSG_VOLUME_CHANGED: {
647 onVolumeChanged(msg.arg1, msg.arg2);
648 break;
649 }
650
651 case MSG_FREE_RESOURCES: {
652 onFreeResources();
653 break;
654 }
655
656 case MSG_STOP_SOUNDS: {
657 onStopSounds();
658 break;
659 }
660
661 case MSG_PLAY_SOUND: {
662 onPlaySound(msg.arg1, msg.arg2);
663 break;
664 }
665
666 case MSG_VIBRATE: {
667 onVibrate();
668 break;
669 }
670
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800671 case MSG_TIMEOUT: {
672 if (mDialog.isShowing()) {
673 mDialog.dismiss();
674 mActiveStreamType = -1;
675 }
676 break;
677 }
678 case MSG_RINGER_MODE_CHANGED: {
679 if (mDialog.isShowing()) {
680 updateStates();
681 }
682 break;
683 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800684 }
685 }
686
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800687 private void resetTimeout() {
688 removeMessages(MSG_TIMEOUT);
689 sendMessageDelayed(obtainMessage(MSG_TIMEOUT), TIMEOUT_DELAY);
690 }
691
692 public void onProgressChanged(SeekBar seekBar, int progress,
693 boolean fromUser) {
694 final Object tag = seekBar.getTag();
695 if (fromUser && tag instanceof StreamControl) {
696 StreamControl sc = (StreamControl) tag;
697 if (mAudioManager.getStreamVolume(sc.streamType) != progress) {
698 mAudioManager.setStreamVolume(sc.streamType, progress, 0);
699 }
700 }
701 resetTimeout();
702 }
703
704 public void onStartTrackingTouch(SeekBar seekBar) {
705 }
706
707 public void onStopTrackingTouch(SeekBar seekBar) {
708 }
709
710 public void onClick(View v) {
711 if (v == mMoreButton) {
712 expand();
713 } else if (v.getTag() instanceof StreamControl) {
714 StreamControl sc = (StreamControl) v.getTag();
715 mAudioManager.setRingerMode(mAudioManager.isSilentMode()
716 ? AudioManager.RINGER_MODE_NORMAL : AudioManager.RINGER_MODE_SILENT);
717 // Expand the dialog if it hasn't been expanded yet.
718 if (!isExpanded()) expand();
719 }
720 resetTimeout();
721 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800722}