summaryrefslogtreecommitdiff
path: root/core/java/android/view/VolumePanel.java
diff options
context:
space:
mode:
authorJohn Spurlock <jspurlock@google.com>2014-05-20 16:25:37 -0400
committerJohn Spurlock <jspurlock@google.com>2014-05-21 09:58:41 -0400
commit3346a802087f621c6441bc512dfcc17b07143fc6 (patch)
tree8c912d2e1a6e350193ad8565cb7a5ad5957849b5 /core/java/android/view/VolumePanel.java
parentc84947db56ce9e6e11541f055a2cf23332552fb7 (diff)
VolumeZen: SystemUI now hosts the volume dialog.
- Allow SystemUI to set the volume controller interface using a new binder call to audio service. - Remove VolumePanel's dependency on AudioService. - Host the base VolumePanel in the SystemUI process. Change-Id: I095d5a1a579d42b68d0f81abb4087bd0c754b876
Diffstat (limited to 'core/java/android/view/VolumePanel.java')
-rw-r--r--core/java/android/view/VolumePanel.java1076
1 files changed, 0 insertions, 1076 deletions
diff --git a/core/java/android/view/VolumePanel.java b/core/java/android/view/VolumePanel.java
deleted file mode 100644
index 4730e595e347..000000000000
--- a/core/java/android/view/VolumePanel.java
+++ /dev/null
@@ -1,1076 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.view;
-
-import com.android.internal.R;
-
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.content.DialogInterface.OnDismissListener;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.res.Resources;
-import android.media.AudioManager;
-import android.media.AudioService;
-import android.media.AudioSystem;
-import android.media.RingtoneManager;
-import android.media.ToneGenerator;
-import android.media.VolumeController;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.Message;
-import android.os.Vibrator;
-import android.util.Log;
-import android.view.WindowManager.LayoutParams;
-import android.widget.ImageView;
-import android.widget.SeekBar;
-import android.widget.SeekBar.OnSeekBarChangeListener;
-
-import java.util.HashMap;
-
-/**
- * Handle the volume up and down keys.
- *
- * This code really should be moved elsewhere.
- *
- * Seriously, it really really should be moved elsewhere. This is used by
- * android.media.AudioService, which actually runs in the system process, to
- * show the volume dialog when the user changes the volume. What a mess.
- *
- * @hide
- */
-public class VolumePanel extends Handler implements VolumeController {
- private static final String TAG = VolumePanel.class.getSimpleName();
- private static boolean LOGD = false;
-
- /**
- * The delay before playing a sound. This small period exists so the user
- * can press another key (non-volume keys, too) to have it NOT be audible.
- * <p>
- * PhoneWindow will implement this part.
- */
- public static final int PLAY_SOUND_DELAY = 300;
-
- /**
- * The delay before vibrating. This small period exists so if the user is
- * moving to silent mode, it will not emit a short vibrate (it normally
- * would since vibrate is between normal mode and silent mode using hardware
- * keys).
- */
- public static final int VIBRATE_DELAY = 300;
-
- private static final int VIBRATE_DURATION = 300;
- private static final int BEEP_DURATION = 150;
- private static final int MAX_VOLUME = 100;
- private static final int FREE_DELAY = 10000;
- private static final int TIMEOUT_DELAY = 3000;
-
- private static final int MSG_VOLUME_CHANGED = 0;
- private static final int MSG_FREE_RESOURCES = 1;
- private static final int MSG_PLAY_SOUND = 2;
- private static final int MSG_STOP_SOUNDS = 3;
- private static final int MSG_VIBRATE = 4;
- private static final int MSG_TIMEOUT = 5;
- private static final int MSG_RINGER_MODE_CHANGED = 6;
- private static final int MSG_MUTE_CHANGED = 7;
- private static final int MSG_REMOTE_VOLUME_CHANGED = 8;
- private static final int MSG_REMOTE_VOLUME_UPDATE_IF_SHOWN = 9;
- private static final int MSG_SLIDER_VISIBILITY_CHANGED = 10;
- private static final int MSG_DISPLAY_SAFE_VOLUME_WARNING = 11;
-
- // Pseudo stream type for master volume
- private static final int STREAM_MASTER = -100;
- // Pseudo stream type for remote volume is defined in AudioService.STREAM_REMOTE_MUSIC
-
- protected Context mContext;
- private AudioManager mAudioManager;
- protected AudioService mAudioService;
- private boolean mRingIsSilent;
- private boolean mShowCombinedVolumes;
- private boolean mVoiceCapable;
-
- // True if we want to play tones on the system stream when the master stream is specified.
- private final boolean mPlayMasterStreamTones;
-
- /** Dialog containing all the sliders */
- private final Dialog mDialog;
- /** Dialog's content view */
- private final View mView;
-
- /** The visible portion of the volume overlay */
- private final ViewGroup mPanel;
- /** Contains the sliders and their touchable icons */
- private final ViewGroup mSliderGroup;
- /** The button that expands the dialog to show all sliders */
- private final View mMoreButton;
- /** Dummy divider icon that needs to vanish with the more button */
- private final View mDivider;
-
- /** Currently active stream that shows up at the top of the list of sliders */
- private int mActiveStreamType = -1;
- /** All the slider controls mapped by stream type */
- private HashMap<Integer,StreamControl> mStreamControls;
-
- private enum StreamResources {
- BluetoothSCOStream(AudioManager.STREAM_BLUETOOTH_SCO,
- R.string.volume_icon_description_bluetooth,
- R.drawable.ic_audio_bt,
- R.drawable.ic_audio_bt,
- false),
- RingerStream(AudioManager.STREAM_RING,
- R.string.volume_icon_description_ringer,
- R.drawable.ic_audio_ring_notif,
- R.drawable.ic_audio_ring_notif_mute,
- false),
- VoiceStream(AudioManager.STREAM_VOICE_CALL,
- R.string.volume_icon_description_incall,
- R.drawable.ic_audio_phone,
- R.drawable.ic_audio_phone,
- false),
- AlarmStream(AudioManager.STREAM_ALARM,
- R.string.volume_alarm,
- R.drawable.ic_audio_alarm,
- R.drawable.ic_audio_alarm_mute,
- false),
- MediaStream(AudioManager.STREAM_MUSIC,
- R.string.volume_icon_description_media,
- R.drawable.ic_audio_vol,
- R.drawable.ic_audio_vol_mute,
- true),
- NotificationStream(AudioManager.STREAM_NOTIFICATION,
- R.string.volume_icon_description_notification,
- R.drawable.ic_audio_notification,
- R.drawable.ic_audio_notification_mute,
- true),
- // for now, use media resources for master volume
- MasterStream(STREAM_MASTER,
- R.string.volume_icon_description_media, //FIXME should have its own description
- R.drawable.ic_audio_vol,
- R.drawable.ic_audio_vol_mute,
- false),
- RemoteStream(AudioService.STREAM_REMOTE_MUSIC,
- R.string.volume_icon_description_media, //FIXME should have its own description
- R.drawable.ic_media_route_on_holo_dark,
- R.drawable.ic_media_route_disabled_holo_dark,
- false);// will be dynamically updated
-
- int streamType;
- int descRes;
- int iconRes;
- int iconMuteRes;
- // RING, VOICE_CALL & BLUETOOTH_SCO are hidden unless explicitly requested
- boolean show;
-
- StreamResources(int streamType, int descRes, int iconRes, int iconMuteRes, boolean show) {
- this.streamType = streamType;
- this.descRes = descRes;
- this.iconRes = iconRes;
- this.iconMuteRes = iconMuteRes;
- this.show = show;
- }
- }
-
- // List of stream types and their order
- private static final StreamResources[] STREAMS = {
- StreamResources.BluetoothSCOStream,
- StreamResources.RingerStream,
- StreamResources.VoiceStream,
- StreamResources.MediaStream,
- StreamResources.NotificationStream,
- StreamResources.AlarmStream,
- StreamResources.MasterStream,
- StreamResources.RemoteStream
- };
-
- /** Object that contains data for each slider */
- private class StreamControl {
- int streamType;
- ViewGroup group;
- ImageView icon;
- SeekBar seekbarView;
- int iconRes;
- int iconMuteRes;
- }
-
- // Synchronize when accessing this
- private ToneGenerator mToneGenerators[];
- private Vibrator mVibrator;
-
- private static AlertDialog sConfirmSafeVolumeDialog;
- private static Object sConfirmSafeVolumeLock = new Object();
-
- private static class WarningDialogReceiver extends BroadcastReceiver
- implements DialogInterface.OnDismissListener {
- private final Context mContext;
- private final Dialog mDialog;
- private final VolumePanel mVolumePanel;
-
- WarningDialogReceiver(Context context, Dialog dialog, VolumePanel volumePanel) {
- mContext = context;
- mDialog = dialog;
- mVolumePanel = volumePanel;
- IntentFilter filter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
- context.registerReceiver(this, filter);
- }
-
- @Override
- public void onReceive(Context context, Intent intent) {
- mDialog.cancel();
- cleanUp();
- }
-
- @Override
- public void onDismiss(DialogInterface unused) {
- mContext.unregisterReceiver(this);
- cleanUp();
- }
-
- private void cleanUp() {
- synchronized (sConfirmSafeVolumeLock) {
- sConfirmSafeVolumeDialog = null;
- }
- mVolumePanel.forceTimeout();
- mVolumePanel.updateStates();
- }
- }
-
-
- public VolumePanel(Context context, AudioService volumeService) {
- mContext = context;
- mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
- mAudioService = volumeService;
-
- // For now, only show master volume if master volume is supported
- final Resources res = context.getResources();
- final boolean useMasterVolume = res.getBoolean(R.bool.config_useMasterVolume);
- if (useMasterVolume) {
- for (int i = 0; i < STREAMS.length; i++) {
- StreamResources streamRes = STREAMS[i];
- streamRes.show = (streamRes.streamType == STREAM_MASTER);
- }
- }
-
- mDialog = new Dialog(context) {
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- if (isShowing() && event.getAction() == MotionEvent.ACTION_OUTSIDE &&
- sConfirmSafeVolumeDialog == null) {
- forceTimeout();
- return true;
- }
- return false;
- }
- };
-
- // Change some window properties
- final Window window = mDialog.getWindow();
- final LayoutParams lp = window.getAttributes();
- lp.token = null;
- // Offset from the top
- lp.y = res.getDimensionPixelOffset(R.dimen.volume_panel_top);
- lp.type = LayoutParams.TYPE_VOLUME_OVERLAY;
- lp.windowAnimations = R.style.Animation_VolumePanel;
- window.setAttributes(lp);
- window.setGravity(Gravity.TOP);
- window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
- window.requestFeature(Window.FEATURE_NO_TITLE);
- window.addFlags(LayoutParams.FLAG_NOT_FOCUSABLE
- | LayoutParams.FLAG_NOT_TOUCH_MODAL
- | LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH);
-
- mDialog.setCanceledOnTouchOutside(true);
- mDialog.setContentView(R.layout.volume_adjust);
- mDialog.setOnDismissListener(new OnDismissListener() {
- @Override
- public void onDismiss(DialogInterface dialog) {
- mActiveStreamType = -1;
- mAudioManager.forceVolumeControlStream(mActiveStreamType);
- }
- });
-
- mDialog.create();
-
- mView = window.findViewById(R.id.content);
- mView.setOnTouchListener(new View.OnTouchListener() {
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- resetTimeout();
- return false;
- }
- });
-
- mPanel = (ViewGroup) mView.findViewById(R.id.visible_panel);
- mSliderGroup = (ViewGroup) mView.findViewById(R.id.slider_group);
- mMoreButton = mView.findViewById(R.id.expand_button);
- mDivider = mView.findViewById(R.id.expand_button_divider);
-
- mToneGenerators = new ToneGenerator[AudioSystem.getNumStreamTypes()];
- mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
- mVoiceCapable = context.getResources().getBoolean(R.bool.config_voice_capable);
-
- // If we don't want to show multiple volumes, hide the settings button
- // and divider.
- mShowCombinedVolumes = !mVoiceCapable && !useMasterVolume;
- if (!mShowCombinedVolumes) {
- mMoreButton.setVisibility(View.GONE);
- mDivider.setVisibility(View.GONE);
- } else {
- mMoreButton.setOnClickListener(mClickListener);
- }
-
- final boolean masterVolumeOnly = res.getBoolean(R.bool.config_useMasterVolume);
- final boolean masterVolumeKeySounds = res.getBoolean(R.bool.config_useVolumeKeySounds);
- mPlayMasterStreamTones = masterVolumeOnly && masterVolumeKeySounds;
-
- listenToRingerMode();
- }
-
- public void setLayoutDirection(int layoutDirection) {
- mPanel.setLayoutDirection(layoutDirection);
- updateStates();
- }
-
- private void listenToRingerMode() {
- final IntentFilter filter = new IntentFilter();
- filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
- mContext.registerReceiver(new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- final String action = intent.getAction();
-
- if (AudioManager.RINGER_MODE_CHANGED_ACTION.equals(action)) {
- removeMessages(MSG_RINGER_MODE_CHANGED);
- sendMessage(obtainMessage(MSG_RINGER_MODE_CHANGED));
- }
- }
- }, filter);
- }
-
- private boolean isMuted(int streamType) {
- if (streamType == STREAM_MASTER) {
- return mAudioManager.isMasterMute();
- } else if (streamType == AudioService.STREAM_REMOTE_MUSIC) {
- return (mAudioService.getRemoteStreamVolume() <= 0);
- } else {
- return mAudioManager.isStreamMute(streamType);
- }
- }
-
- private int getStreamMaxVolume(int streamType) {
- if (streamType == STREAM_MASTER) {
- return mAudioManager.getMasterMaxVolume();
- } else if (streamType == AudioService.STREAM_REMOTE_MUSIC) {
- return mAudioService.getRemoteStreamMaxVolume();
- } else {
- return mAudioManager.getStreamMaxVolume(streamType);
- }
- }
-
- private int getStreamVolume(int streamType) {
- if (streamType == STREAM_MASTER) {
- return mAudioManager.getMasterVolume();
- } else if (streamType == AudioService.STREAM_REMOTE_MUSIC) {
- return mAudioService.getRemoteStreamVolume();
- } else {
- return mAudioManager.getStreamVolume(streamType);
- }
- }
-
- private void setStreamVolume(int streamType, int index, int flags) {
- if (streamType == STREAM_MASTER) {
- mAudioManager.setMasterVolume(index, flags);
- } else if (streamType == AudioService.STREAM_REMOTE_MUSIC) {
- mAudioService.setRemoteStreamVolume(index);
- } else {
- mAudioManager.setStreamVolume(streamType, index, flags);
- }
- }
-
- private void createSliders() {
- final Resources res = mContext.getResources();
- final LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
- Context.LAYOUT_INFLATER_SERVICE);
-
- mStreamControls = new HashMap<Integer, StreamControl>(STREAMS.length);
-
- for (int i = 0; i < STREAMS.length; i++) {
- StreamResources streamRes = STREAMS[i];
-
- final int streamType = streamRes.streamType;
- if (mVoiceCapable && streamRes == StreamResources.NotificationStream) {
- streamRes = StreamResources.RingerStream;
- }
-
- final StreamControl sc = new StreamControl();
- sc.streamType = streamType;
- sc.group = (ViewGroup) inflater.inflate(R.layout.volume_adjust_item, null);
- sc.group.setTag(sc);
- sc.icon = (ImageView) sc.group.findViewById(R.id.stream_icon);
- sc.icon.setTag(sc);
- sc.icon.setContentDescription(res.getString(streamRes.descRes));
- sc.iconRes = streamRes.iconRes;
- sc.iconMuteRes = streamRes.iconMuteRes;
- sc.icon.setImageResource(sc.iconRes);
- sc.seekbarView = (SeekBar) sc.group.findViewById(R.id.seekbar);
- final int plusOne = (streamType == AudioSystem.STREAM_BLUETOOTH_SCO ||
- streamType == AudioSystem.STREAM_VOICE_CALL) ? 1 : 0;
- sc.seekbarView.setMax(getStreamMaxVolume(streamType) + plusOne);
- sc.seekbarView.setOnSeekBarChangeListener(mSeekListener);
- sc.seekbarView.setTag(sc);
- mStreamControls.put(streamType, sc);
- }
- }
-
- private void reorderSliders(int activeStreamType) {
- mSliderGroup.removeAllViews();
-
- final StreamControl active = mStreamControls.get(activeStreamType);
- if (active == null) {
- Log.e("VolumePanel", "Missing stream type! - " + activeStreamType);
- mActiveStreamType = -1;
- } else {
- mSliderGroup.addView(active.group);
- mActiveStreamType = activeStreamType;
- active.group.setVisibility(View.VISIBLE);
- updateSlider(active);
- }
-
- addOtherVolumes();
- }
-
- private void addOtherVolumes() {
- if (!mShowCombinedVolumes) return;
-
- for (int i = 0; i < STREAMS.length; i++) {
- // Skip the phone specific ones and the active one
- final int streamType = STREAMS[i].streamType;
- if (!STREAMS[i].show || streamType == mActiveStreamType) {
- continue;
- }
- StreamControl sc = mStreamControls.get(streamType);
- mSliderGroup.addView(sc.group);
- updateSlider(sc);
- }
- }
-
- /** Update the mute and progress state of a slider */
- private void updateSlider(StreamControl sc) {
- sc.seekbarView.setProgress(getStreamVolume(sc.streamType));
- final boolean muted = isMuted(sc.streamType);
- // Force reloading the image resource
- sc.icon.setImageDrawable(null);
- sc.icon.setImageResource(muted ? sc.iconMuteRes : sc.iconRes);
- if (((sc.streamType == AudioManager.STREAM_RING) ||
- (sc.streamType == AudioManager.STREAM_NOTIFICATION)) &&
- mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE) {
- sc.icon.setImageResource(R.drawable.ic_audio_ring_notif_vibrate);
- }
- if (sc.streamType == AudioService.STREAM_REMOTE_MUSIC) {
- // never disable touch interactions for remote playback, the muting is not tied to
- // the state of the phone.
- sc.seekbarView.setEnabled(true);
- } else if ((sc.streamType != mAudioManager.getMasterStreamType() && muted) ||
- (sConfirmSafeVolumeDialog != null)) {
- sc.seekbarView.setEnabled(false);
- } else {
- sc.seekbarView.setEnabled(true);
- }
- }
-
- private void expand() {
- final int count = mSliderGroup.getChildCount();
- for (int i = 0; i < count; i++) {
- mSliderGroup.getChildAt(i).setVisibility(View.VISIBLE);
- }
- mMoreButton.setVisibility(View.INVISIBLE);
- mDivider.setVisibility(View.INVISIBLE);
- }
-
- private void collapse() {
- mMoreButton.setVisibility(View.VISIBLE);
- mDivider.setVisibility(View.VISIBLE);
- final int count = mSliderGroup.getChildCount();
- for (int i = 1; i < count; i++) {
- mSliderGroup.getChildAt(i).setVisibility(View.GONE);
- }
- }
-
- public void updateStates() {
- final int count = mSliderGroup.getChildCount();
- for (int i = 0; i < count; i++) {
- StreamControl sc = (StreamControl) mSliderGroup.getChildAt(i).getTag();
- updateSlider(sc);
- }
- }
-
- public void postVolumeChanged(int streamType, int flags) {
- if (hasMessages(MSG_VOLUME_CHANGED)) return;
- synchronized (this) {
- if (mStreamControls == null) {
- createSliders();
- }
- }
- removeMessages(MSG_FREE_RESOURCES);
- obtainMessage(MSG_VOLUME_CHANGED, streamType, flags).sendToTarget();
- }
-
- @Override
- public void postRemoteVolumeChanged(int streamType, int flags) {
- if (hasMessages(MSG_REMOTE_VOLUME_CHANGED)) return;
- synchronized (this) {
- if (mStreamControls == null) {
- createSliders();
- }
- }
- removeMessages(MSG_FREE_RESOURCES);
- obtainMessage(MSG_REMOTE_VOLUME_CHANGED, streamType, flags).sendToTarget();
- }
-
- @Override
- public void postRemoteSliderVisibility(boolean visible) {
- obtainMessage(MSG_SLIDER_VISIBILITY_CHANGED,
- AudioService.STREAM_REMOTE_MUSIC, visible ? 1 : 0).sendToTarget();
- }
-
- /**
- * Called by AudioService when it has received new remote playback information that
- * would affect the VolumePanel display (mainly volumes). The difference with
- * {@link #postRemoteVolumeChanged(int, int)} is that the handling of the posted message
- * (MSG_REMOTE_VOLUME_UPDATE_IF_SHOWN) will only update the volume slider if it is being
- * displayed.
- * This special code path is due to the fact that remote volume updates arrive to AudioService
- * asynchronously. So after AudioService has sent the volume update (which should be treated
- * as a request to update the volume), the application will likely set a new volume. If the UI
- * is still up, we need to refresh the display to show this new value.
- */
- @Override
- public void postHasNewRemotePlaybackInfo() {
- if (hasMessages(MSG_REMOTE_VOLUME_UPDATE_IF_SHOWN)) return;
- // don't create or prevent resources to be freed, if they disappear, this update came too
- // late and shouldn't warrant the panel to be displayed longer
- obtainMessage(MSG_REMOTE_VOLUME_UPDATE_IF_SHOWN).sendToTarget();
- }
-
- public void postMasterVolumeChanged(int flags) {
- postVolumeChanged(STREAM_MASTER, flags);
- }
-
- public void postMuteChanged(int streamType, int flags) {
- if (hasMessages(MSG_VOLUME_CHANGED)) return;
- synchronized (this) {
- if (mStreamControls == null) {
- createSliders();
- }
- }
- removeMessages(MSG_FREE_RESOURCES);
- obtainMessage(MSG_MUTE_CHANGED, streamType, flags).sendToTarget();
- }
-
- public void postMasterMuteChanged(int flags) {
- postMuteChanged(STREAM_MASTER, flags);
- }
-
- public void postDisplaySafeVolumeWarning(int flags) {
- if (hasMessages(MSG_DISPLAY_SAFE_VOLUME_WARNING)) return;
- obtainMessage(MSG_DISPLAY_SAFE_VOLUME_WARNING, flags, 0).sendToTarget();
- }
-
- /**
- * Override this if you have other work to do when the volume changes (for
- * example, vibrating, playing a sound, etc.). Make sure to call through to
- * the superclass implementation.
- */
- protected void onVolumeChanged(int streamType, int flags) {
-
- if (LOGD) Log.d(TAG, "onVolumeChanged(streamType: " + streamType + ", flags: " + flags + ")");
-
- if ((flags & AudioManager.FLAG_SHOW_UI) != 0) {
- synchronized (this) {
- if (mActiveStreamType != streamType) {
- reorderSliders(streamType);
- }
- onShowVolumeChanged(streamType, flags);
- }
- }
-
- if ((flags & AudioManager.FLAG_PLAY_SOUND) != 0 && ! mRingIsSilent) {
- removeMessages(MSG_PLAY_SOUND);
- sendMessageDelayed(obtainMessage(MSG_PLAY_SOUND, streamType, flags), PLAY_SOUND_DELAY);
- }
-
- if ((flags & AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE) != 0) {
- removeMessages(MSG_PLAY_SOUND);
- removeMessages(MSG_VIBRATE);
- onStopSounds();
- }
-
- removeMessages(MSG_FREE_RESOURCES);
- sendMessageDelayed(obtainMessage(MSG_FREE_RESOURCES), FREE_DELAY);
- resetTimeout();
- }
-
- protected void onMuteChanged(int streamType, int flags) {
-
- if (LOGD) Log.d(TAG, "onMuteChanged(streamType: " + streamType + ", flags: " + flags + ")");
-
- StreamControl sc = mStreamControls.get(streamType);
- if (sc != null) {
- sc.icon.setImageResource(isMuted(sc.streamType) ? sc.iconMuteRes : sc.iconRes);
- }
-
- onVolumeChanged(streamType, flags);
- }
-
- protected void onShowVolumeChanged(int streamType, int flags) {
- int index = getStreamVolume(streamType);
-
- mRingIsSilent = false;
-
- if (LOGD) {
- Log.d(TAG, "onShowVolumeChanged(streamType: " + streamType
- + ", flags: " + flags + "), index: " + index);
- }
-
- // get max volume for progress bar
-
- int max = getStreamMaxVolume(streamType);
-
- switch (streamType) {
-
- case AudioManager.STREAM_RING: {
-// setRingerIcon();
- Uri ringuri = RingtoneManager.getActualDefaultRingtoneUri(
- mContext, RingtoneManager.TYPE_RINGTONE);
- if (ringuri == null) {
- mRingIsSilent = true;
- }
- break;
- }
-
- case AudioManager.STREAM_MUSIC: {
- // Special case for when Bluetooth is active for music
- if ((mAudioManager.getDevicesForStream(AudioManager.STREAM_MUSIC) &
- (AudioManager.DEVICE_OUT_BLUETOOTH_A2DP |
- AudioManager.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
- AudioManager.DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER)) != 0) {
- setMusicIcon(R.drawable.ic_audio_bt, R.drawable.ic_audio_bt_mute);
- } else {
- setMusicIcon(R.drawable.ic_audio_vol, R.drawable.ic_audio_vol_mute);
- }
- break;
- }
-
- case AudioManager.STREAM_VOICE_CALL: {
- /*
- * For in-call voice call volume, there is no inaudible volume.
- * Rescale the UI control so the progress bar doesn't go all
- * the way to zero and don't show the mute icon.
- */
- index++;
- max++;
- break;
- }
-
- case AudioManager.STREAM_ALARM: {
- break;
- }
-
- case AudioManager.STREAM_NOTIFICATION: {
- Uri ringuri = RingtoneManager.getActualDefaultRingtoneUri(
- mContext, RingtoneManager.TYPE_NOTIFICATION);
- if (ringuri == null) {
- mRingIsSilent = true;
- }
- break;
- }
-
- case AudioManager.STREAM_BLUETOOTH_SCO: {
- /*
- * For in-call voice call volume, there is no inaudible volume.
- * Rescale the UI control so the progress bar doesn't go all
- * the way to zero and don't show the mute icon.
- */
- index++;
- max++;
- break;
- }
-
- case AudioService.STREAM_REMOTE_MUSIC: {
- if (LOGD) { Log.d(TAG, "showing remote volume "+index+" over "+ max); }
- break;
- }
- }
-
- StreamControl sc = mStreamControls.get(streamType);
- if (sc != null) {
- if (sc.seekbarView.getMax() != max) {
- sc.seekbarView.setMax(max);
- }
-
- sc.seekbarView.setProgress(index);
- if (((flags & AudioManager.FLAG_FIXED_VOLUME) != 0) ||
- (streamType != mAudioManager.getMasterStreamType() &&
- streamType != AudioService.STREAM_REMOTE_MUSIC &&
- isMuted(streamType)) ||
- sConfirmSafeVolumeDialog != null) {
- sc.seekbarView.setEnabled(false);
- } else {
- sc.seekbarView.setEnabled(true);
- }
- }
-
- if (!mDialog.isShowing()) {
- int stream = (streamType == AudioService.STREAM_REMOTE_MUSIC) ? -1 : streamType;
- // when the stream is for remote playback, use -1 to reset the stream type evaluation
- mAudioManager.forceVolumeControlStream(stream);
-
- // Showing dialog - use collapsed state
- if (mShowCombinedVolumes) {
- collapse();
- }
- mDialog.show();
- }
-
- // Do a little vibrate if applicable (only when going into vibrate mode)
- if ((streamType != AudioService.STREAM_REMOTE_MUSIC) &&
- ((flags & AudioManager.FLAG_VIBRATE) != 0) &&
- mAudioService.isStreamAffectedByRingerMode(streamType) &&
- mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE) {
- sendMessageDelayed(obtainMessage(MSG_VIBRATE), VIBRATE_DELAY);
- }
- }
-
- protected void onPlaySound(int streamType, int flags) {
-
- if (hasMessages(MSG_STOP_SOUNDS)) {
- removeMessages(MSG_STOP_SOUNDS);
- // Force stop right now
- onStopSounds();
- }
-
- synchronized (this) {
- ToneGenerator toneGen = getOrCreateToneGenerator(streamType);
- if (toneGen != null) {
- toneGen.startTone(ToneGenerator.TONE_PROP_BEEP);
- sendMessageDelayed(obtainMessage(MSG_STOP_SOUNDS), BEEP_DURATION);
- }
- }
- }
-
- protected void onStopSounds() {
-
- synchronized (this) {
- int numStreamTypes = AudioSystem.getNumStreamTypes();
- for (int i = numStreamTypes - 1; i >= 0; i--) {
- ToneGenerator toneGen = mToneGenerators[i];
- if (toneGen != null) {
- toneGen.stopTone();
- }
- }
- }
- }
-
- protected void onVibrate() {
-
- // Make sure we ended up in vibrate ringer mode
- if (mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_VIBRATE) {
- return;
- }
-
- mVibrator.vibrate(VIBRATE_DURATION, AudioManager.STREAM_SYSTEM);
- }
-
- protected void onRemoteVolumeChanged(int streamType, int flags) {
- // streamType is the real stream type being affected, but for the UI sliders, we
- // refer to AudioService.STREAM_REMOTE_MUSIC. We still play the beeps on the real
- // stream type.
- if (LOGD) Log.d(TAG, "onRemoteVolumeChanged(stream:"+streamType+", flags: " + flags + ")");
-
- if (((flags & AudioManager.FLAG_SHOW_UI) != 0) || mDialog.isShowing()) {
- synchronized (this) {
- if (mActiveStreamType != AudioService.STREAM_REMOTE_MUSIC) {
- reorderSliders(AudioService.STREAM_REMOTE_MUSIC);
- }
- onShowVolumeChanged(AudioService.STREAM_REMOTE_MUSIC, flags);
- }
- } else {
- if (LOGD) Log.d(TAG, "not calling onShowVolumeChanged(), no FLAG_SHOW_UI or no UI");
- }
-
- if ((flags & AudioManager.FLAG_PLAY_SOUND) != 0 && ! mRingIsSilent) {
- removeMessages(MSG_PLAY_SOUND);
- sendMessageDelayed(obtainMessage(MSG_PLAY_SOUND, streamType, flags), PLAY_SOUND_DELAY);
- }
-
- if ((flags & AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE) != 0) {
- removeMessages(MSG_PLAY_SOUND);
- removeMessages(MSG_VIBRATE);
- onStopSounds();
- }
-
- removeMessages(MSG_FREE_RESOURCES);
- sendMessageDelayed(obtainMessage(MSG_FREE_RESOURCES), FREE_DELAY);
- resetTimeout();
- }
-
- protected void onRemoteVolumeUpdateIfShown() {
- if (LOGD) Log.d(TAG, "onRemoteVolumeUpdateIfShown()");
- if (mDialog.isShowing()
- && (mActiveStreamType == AudioService.STREAM_REMOTE_MUSIC)
- && (mStreamControls != null)) {
- onShowVolumeChanged(AudioService.STREAM_REMOTE_MUSIC, 0);
- }
- }
-
-
- /**
- * Handler for MSG_SLIDER_VISIBILITY_CHANGED
- * Hide or show a slider
- * @param streamType can be a valid stream type value, or VolumePanel.STREAM_MASTER,
- * or AudioService.STREAM_REMOTE_MUSIC
- * @param visible
- */
- synchronized protected void onSliderVisibilityChanged(int streamType, int visible) {
- if (LOGD) Log.d(TAG, "onSliderVisibilityChanged(stream="+streamType+", visi="+visible+")");
- boolean isVisible = (visible == 1);
- for (int i = STREAMS.length - 1 ; i >= 0 ; i--) {
- StreamResources streamRes = STREAMS[i];
- if (streamRes.streamType == streamType) {
- streamRes.show = isVisible;
- if (!isVisible && (mActiveStreamType == streamType)) {
- mActiveStreamType = -1;
- }
- break;
- }
- }
- }
-
- protected void onDisplaySafeVolumeWarning(int flags) {
- if ((flags & AudioManager.FLAG_SHOW_UI) != 0 || mDialog.isShowing()) {
- synchronized (sConfirmSafeVolumeLock) {
- if (sConfirmSafeVolumeDialog != null) {
- return;
- }
- sConfirmSafeVolumeDialog = new AlertDialog.Builder(mContext)
- .setMessage(com.android.internal.R.string.safe_media_volume_warning)
- .setPositiveButton(com.android.internal.R.string.yes,
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- mAudioService.disableSafeMediaVolume();
- }
- })
- .setNegativeButton(com.android.internal.R.string.no, null)
- .setIconAttribute(android.R.attr.alertDialogIcon)
- .create();
- final WarningDialogReceiver warning = new WarningDialogReceiver(mContext,
- sConfirmSafeVolumeDialog, this);
-
- sConfirmSafeVolumeDialog.setOnDismissListener(warning);
- sConfirmSafeVolumeDialog.getWindow().setType(
- WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
- sConfirmSafeVolumeDialog.show();
- }
- updateStates();
- }
- resetTimeout();
- }
-
- /**
- * Lock on this VolumePanel instance as long as you use the returned ToneGenerator.
- */
- private ToneGenerator getOrCreateToneGenerator(int streamType) {
- if (streamType == STREAM_MASTER) {
- // For devices that use the master volume setting only but still want to
- // play a volume-changed tone, direct the master volume pseudostream to
- // the system stream's tone generator.
- if (mPlayMasterStreamTones) {
- streamType = AudioManager.STREAM_SYSTEM;
- } else {
- return null;
- }
- }
- synchronized (this) {
- if (mToneGenerators[streamType] == null) {
- try {
- mToneGenerators[streamType] = new ToneGenerator(streamType, MAX_VOLUME);
- } catch (RuntimeException e) {
- if (LOGD) {
- Log.d(TAG, "ToneGenerator constructor failed with "
- + "RuntimeException: " + e);
- }
- }
- }
- return mToneGenerators[streamType];
- }
- }
-
-
- /**
- * Switch between icons because Bluetooth music is same as music volume, but with
- * different icons.
- */
- private void setMusicIcon(int resId, int resMuteId) {
- StreamControl sc = mStreamControls.get(AudioManager.STREAM_MUSIC);
- if (sc != null) {
- sc.iconRes = resId;
- sc.iconMuteRes = resMuteId;
- sc.icon.setImageResource(isMuted(sc.streamType) ? sc.iconMuteRes : sc.iconRes);
- }
- }
-
- protected void onFreeResources() {
- synchronized (this) {
- for (int i = mToneGenerators.length - 1; i >= 0; i--) {
- if (mToneGenerators[i] != null) {
- mToneGenerators[i].release();
- }
- mToneGenerators[i] = null;
- }
- }
- }
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
-
- case MSG_VOLUME_CHANGED: {
- onVolumeChanged(msg.arg1, msg.arg2);
- break;
- }
-
- case MSG_MUTE_CHANGED: {
- onMuteChanged(msg.arg1, msg.arg2);
- break;
- }
-
- case MSG_FREE_RESOURCES: {
- onFreeResources();
- break;
- }
-
- case MSG_STOP_SOUNDS: {
- onStopSounds();
- break;
- }
-
- case MSG_PLAY_SOUND: {
- onPlaySound(msg.arg1, msg.arg2);
- break;
- }
-
- case MSG_VIBRATE: {
- onVibrate();
- break;
- }
-
- case MSG_TIMEOUT: {
- if (mDialog.isShowing()) {
- mDialog.dismiss();
- mActiveStreamType = -1;
- }
- synchronized (sConfirmSafeVolumeLock) {
- if (sConfirmSafeVolumeDialog != null) {
- sConfirmSafeVolumeDialog.dismiss();
- }
- }
- break;
- }
- case MSG_RINGER_MODE_CHANGED: {
- if (mDialog.isShowing()) {
- updateStates();
- }
- break;
- }
-
- case MSG_REMOTE_VOLUME_CHANGED: {
- onRemoteVolumeChanged(msg.arg1, msg.arg2);
- break;
- }
-
- case MSG_REMOTE_VOLUME_UPDATE_IF_SHOWN:
- onRemoteVolumeUpdateIfShown();
- break;
-
- case MSG_SLIDER_VISIBILITY_CHANGED:
- onSliderVisibilityChanged(msg.arg1, msg.arg2);
- break;
-
- case MSG_DISPLAY_SAFE_VOLUME_WARNING:
- onDisplaySafeVolumeWarning(msg.arg1);
- break;
- }
- }
-
- private void resetTimeout() {
- removeMessages(MSG_TIMEOUT);
- sendMessageDelayed(obtainMessage(MSG_TIMEOUT), TIMEOUT_DELAY);
- }
-
- private void forceTimeout() {
- removeMessages(MSG_TIMEOUT);
- sendMessage(obtainMessage(MSG_TIMEOUT));
- }
-
- private final OnSeekBarChangeListener mSeekListener = new OnSeekBarChangeListener() {
- @Override
- public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
- final Object tag = seekBar.getTag();
- if (fromUser && tag instanceof StreamControl) {
- StreamControl sc = (StreamControl) tag;
- if (getStreamVolume(sc.streamType) != progress) {
- setStreamVolume(sc.streamType, progress, 0);
- }
- }
- resetTimeout();
- }
-
- @Override
- public void onStartTrackingTouch(SeekBar seekBar) {
- }
-
- @Override
- public void onStopTrackingTouch(SeekBar seekBar) {
- final Object tag = seekBar.getTag();
- if (tag instanceof StreamControl) {
- StreamControl sc = (StreamControl) tag;
- // Because remote volume updates are asynchronous, AudioService
- // might have received a new remote volume value since the
- // finger adjusted the slider. So when the progress of the
- // slider isn't being tracked anymore, adjust the slider to the
- // last "published" remote volume value, so the UI reflects the
- // actual volume.
- if (sc.streamType == AudioService.STREAM_REMOTE_MUSIC) {
- seekBar.setProgress(getStreamVolume(AudioService.STREAM_REMOTE_MUSIC));
- }
- }
- }
- };
-
- private final View.OnClickListener mClickListener = new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- if (v == mMoreButton) {
- expand();
- }
- resetTimeout();
- }
- };
-}