Fix 3419077: implement new volume control in Settings.
Change-Id: Ia4b803315382d59ae231c26187afaceb69397952
diff --git a/res/layout/preference_dialog_ringervolume.xml b/res/layout/preference_dialog_ringervolume.xml
index 6d494c1..5aebedc 100644
--- a/res/layout/preference_dialog_ringervolume.xml
+++ b/res/layout/preference_dialog_ringervolume.xml
@@ -17,91 +17,119 @@
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
-
+
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center_horizontal"
- android:paddingBottom="20dip">
-
+ android:paddingBottom="12dip"
+ android:paddingTop="12dip">
+
<ImageView android:id="@android:id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:paddingTop="20dip" />
-
+ android:paddingTop="20dip"
+ android:visibility="gone"/>
+
<TextView
android:id="@+id/ringtone_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/incoming_call_volume_title"
android:paddingTop="10dip"
- android:paddingLeft="20dip"
+ android:paddingLeft="20dip"
android:paddingRight="20dip" />
-
+
<!-- Used for the ring volume. This is what the superclass VolumePreference uses. -->
+ <!-- TODO - is this used? -->
<SeekBar android:id="@*android:id/seekbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="2dip"
- android:paddingLeft="20dip"
- android:paddingRight="20dip" />
-
- <!-- Used for the media volume -->
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/media_volume_title"
- android:paddingTop="10dip"
- android:paddingLeft="20dip"
- android:paddingRight="20dip" />
- <SeekBar android:id="@+id/media_volume_seekbar"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingTop="2dip"
android:paddingLeft="20dip"
android:paddingRight="20dip" />
- <!-- Used for the alarm volume -->
- <TextView
+ <!-- Used for the media volume -->
+ <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:text="@string/alarm_volume_title"
- android:paddingTop="10dip"
- android:paddingLeft="20dip"
- android:paddingRight="20dip" />
- <SeekBar android:id="@+id/alarm_volume_seekbar"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingTop="2dip"
- android:paddingLeft="20dip"
- android:paddingRight="20dip" />
+ android:orientation="horizontal"
+ android:gravity="center_vertical">
+ <ImageView android:id="@+id/volume_mute_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
+
+ <SeekBar android:id="@+id/media_volume_seekbar"
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:paddingTop="2dip"
+ android:paddingLeft="20dip"
+ android:paddingRight="20dip" />
+ </LinearLayout>
+
+ <!-- TODO - is this used? -->
<CheckBox android:id="@+id/same_notification_volume"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/checkbox_notification_same_as_incoming_call"
android:textAppearance="?android:attr/textAppearanceSmall"
android:layout_marginTop="6dip"
- android:layout_marginLeft="20dip"
+ android:layout_marginLeft="20dip"
android:layout_marginRight="20dip" />
-
- <TextView android:id="@+id/notification_volume_title"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/notification_volume_title"
- android:paddingTop="6dip"
- android:paddingLeft="20dip"
- android:paddingRight="20dip" />
-
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1px"
+ android:background="#1bffffff"
+ android:layout_marginTop="16dip"
+ android:layout_marginBottom="16dip"/>
+
<!-- Used for the notification volume -->
- <SeekBar android:id="@+id/notification_volume_seekbar"
+ <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingTop="2dip"
- android:paddingLeft="20dip"
- android:paddingRight="20dip" />
-
+ android:orientation="horizontal">
+
+ <ImageView android:id="@+id/notification_mute_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
+
+ <SeekBar android:id="@+id/notification_volume_seekbar"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="2dip"
+ android:paddingLeft="20dip"
+ android:paddingRight="20dip" />
+ </LinearLayout>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1px"
+ android:background="#1bffffff"
+ android:layout_marginTop="16dip"
+ android:layout_marginBottom="16dip"/>
+
+ <!-- Used for the alarm volume -->
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <ImageView android:id="@+id/alarm_mute_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
+
+ <SeekBar android:id="@+id/alarm_volume_seekbar"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="2dip"
+ android:paddingLeft="20dip"
+ android:paddingRight="20dip" />
+ </LinearLayout>
+
</LinearLayout>
-
-</ScrollView>
\ No newline at end of file
+
+</ScrollView>
\ No newline at end of file
diff --git a/src/com/android/settings/RingerVolumePreference.java b/src/com/android/settings/RingerVolumePreference.java
index daae1a7..b546265 100644
--- a/src/com/android/settings/RingerVolumePreference.java
+++ b/src/com/android/settings/RingerVolumePreference.java
@@ -16,20 +16,34 @@
package com.android.settings;
+import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN;
+import static android.provider.Telephony.Intents.SPN_STRINGS_UPDATED_ACTION;
+
+import com.android.internal.telephony.TelephonyIntents;
+
import android.app.Dialog;
+import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.media.AudioManager;
import android.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
import android.os.Parcel;
import android.os.Parcelable;
import android.preference.VolumePreference;
import android.provider.Settings;
import android.util.AttributeSet;
+import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
+import android.view.View.OnClickListener;
import android.widget.CheckBox;
import android.widget.CompoundButton;
+import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.TextView;
@@ -38,12 +52,15 @@
* notification volume.
*/
public class RingerVolumePreference extends VolumePreference implements
- CheckBox.OnCheckedChangeListener {
+ CheckBox.OnCheckedChangeListener, OnClickListener {
private static final String TAG = "RingerVolumePreference";
+ private static final int MSG_RINGER_MODE_CHANGED = 101;
private CheckBox mNotificationsUseRingVolumeCheckbox;
private SeekBarVolumizer [] mSeekBarVolumizer;
private boolean mIgnoreVolumeKeys;
+
+ // These arrays must all match in length and order
private static final int[] SEEKBAR_ID = new int[] {
R.id.notification_volume_seekbar,
R.id.media_volume_seekbar,
@@ -51,9 +68,9 @@
};
private static final int[] NEED_VOICE_CAPABILITY_ID = new int[] {
- R.id.ringtone_label,
- com.android.internal.R.id.seekbar,
- R.id.same_notification_volume
+ R.id.ringtone_label,
+ com.android.internal.R.id.seekbar,
+ R.id.same_notification_volume
};
private static final int[] SEEKBAR_TYPE = new int[] {
@@ -61,8 +78,63 @@
AudioManager.STREAM_MUSIC,
AudioManager.STREAM_ALARM
};
+
+ private static final int[] CHECKBOX_VIEW_ID = new int[] {
+ R.id.notification_mute_button,
+ R.id.volume_mute_button,
+ R.id.alarm_mute_button
+ };
+
+ private static final int[] SEEKBAR_MUTED_RES_ID = new int[] {
+ com.android.internal.R.drawable.ic_audio_notification_mute,
+ com.android.internal.R.drawable.ic_audio_vol_mute,
+ com.android.internal.R.drawable.ic_audio_alarm_mute
+ };
+
+ private static final int[] SEEKBAR_UNMUTED_RES_ID = new int[] {
+ com.android.internal.R.drawable.ic_audio_notification,
+ com.android.internal.R.drawable.ic_audio_vol,
+ com.android.internal.R.drawable.ic_audio_alarm
+ };
+
+ private ImageView[] mCheckBoxes = new ImageView[SEEKBAR_MUTED_RES_ID.length];
+ private SeekBar[] mSeekBars = new SeekBar[SEEKBAR_ID.length];
+
+ private Handler mHandler = new Handler() {
+ public void handleMessage(Message msg) {
+ updateSlidersAndMutedStates();
+ }
+ };
+
+ @Override
+ public void createActionButtons() {
+ setPositiveButtonText(android.R.string.ok);
+ setNegativeButtonText(null);
+ }
+
+ private void updateSlidersAndMutedStates() {
+ for (int i = 0; i < SEEKBAR_TYPE.length; i++) {
+ int streamType = SEEKBAR_TYPE[i];
+ boolean muted = mAudioManager.isStreamMute(streamType);
+
+ if (mCheckBoxes[i] != null) {
+ mCheckBoxes[i].setImageResource(
+ muted ? SEEKBAR_MUTED_RES_ID[i] : SEEKBAR_UNMUTED_RES_ID[i]);
+ }
+ if (mSeekBars[i] != null) {
+ mSeekBars[i].setEnabled(!muted);
+ final int volume = muted ? mAudioManager.getLastAudibleStreamVolume(streamType)
+ : mAudioManager.getStreamVolume(streamType);
+ mSeekBars[i].setProgress(volume);
+ }
+ }
+ }
+
+ private BroadcastReceiver mRingModeChangedReceiver;
+ private AudioManager mAudioManager;
+
//private SeekBarVolumizer mNotificationSeekBarVolumizer;
- private TextView mNotificationVolumeTitle;
+ //private TextView mNotificationVolumeTitle;
public RingerVolumePreference(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -71,10 +143,12 @@
setStreamType(AudioManager.STREAM_RING);
setDialogLayoutResource(R.layout.preference_dialog_ringervolume);
- setDialogIcon(R.drawable.ic_settings_sound);
+ //setDialogIcon(R.drawable.ic_settings_sound);
mSeekBarVolumizer = new SeekBarVolumizer[SEEKBAR_ID.length];
mIgnoreVolumeKeys = !Utils.isVoiceCapable(context);
+
+ mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
}
@Override
@@ -83,6 +157,7 @@
for (int i = 0; i < SEEKBAR_ID.length; i++) {
SeekBar seekBar = (SeekBar) view.findViewById(SEEKBAR_ID[i]);
+ mSeekBars[i] = seekBar;
if (SEEKBAR_TYPE[i] == AudioManager.STREAM_MUSIC) {
mSeekBarVolumizer[i] = new SeekBarVolumizer(getContext(), seekBar,
SEEKBAR_TYPE[i], getMediaVolumeUri(getContext()));
@@ -92,7 +167,7 @@
}
}
- mNotificationVolumeTitle = (TextView) view.findViewById(R.id.notification_volume_title);
+ //mNotificationVolumeTitle = (TextView) view.findViewById(R.id.notification_volume_title);
mNotificationsUseRingVolumeCheckbox =
(CheckBox) view.findViewById(R.id.same_notification_volume);
mNotificationsUseRingVolumeCheckbox.setOnCheckedChangeListener(this);
@@ -103,6 +178,32 @@
Settings.System.NOTIFICATIONS_USE_RING_VOLUME, 1) == 1);
setNotificationVolumeVisibility(!mNotificationsUseRingVolumeCheckbox.isChecked());
disableSettingsThatNeedVoice(view);
+
+ // Register callbacks for mute/unmute buttons
+ for (int i = 0; i < mCheckBoxes.length; i++) {
+ ImageView checkbox = (ImageView) view.findViewById(CHECKBOX_VIEW_ID[i]);
+ checkbox.setOnClickListener(this);
+ mCheckBoxes[i] = checkbox;
+ }
+
+ // Load initial states from AudioManager
+ updateSlidersAndMutedStates();
+
+ // Listen for updates from AudioManager
+ if (mRingModeChangedReceiver == null) {
+ final IntentFilter filter = new IntentFilter();
+ filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
+ mRingModeChangedReceiver = new BroadcastReceiver() {
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ if (AudioManager.RINGER_MODE_CHANGED_ACTION.equals(action)) {
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_RINGER_MODE_CHANGED,
+ intent.getIntExtra(AudioManager.EXTRA_RINGER_MODE, -1), 0));
+ }
+ }
+ };
+ getContext().registerReceiver(mRingModeChangedReceiver, filter);
+ }
}
private Uri getMediaVolumeUri(Context context) {
@@ -147,10 +248,8 @@
if (isChecked) {
// The user wants the notification to be same as ring, so do a
// one-time sync right now
- AudioManager audioManager = (AudioManager) getContext()
- .getSystemService(Context.AUDIO_SERVICE);
- audioManager.setStreamVolume(AudioManager.STREAM_NOTIFICATION,
- audioManager.getStreamVolume(AudioManager.STREAM_RING), 0);
+ mAudioManager.setStreamVolume(AudioManager.STREAM_NOTIFICATION,
+ mAudioManager.getStreamVolume(AudioManager.STREAM_RING), 0);
}
}
@@ -184,7 +283,7 @@
mSeekBarVolumizer[0].getSeekBar().setVisibility(
visible ? View.VISIBLE : View.GONE);
}
- mNotificationVolumeTitle.setVisibility(visible ? View.VISIBLE : View.GONE);
+ // mNotificationVolumeTitle.setVisibility(visible ? View.VISIBLE : View.GONE);
}
private void cleanup() {
@@ -199,6 +298,10 @@
mSeekBarVolumizer[i] = null;
}
}
+ if (mRingModeChangedReceiver != null) {
+ getContext().unregisterReceiver(mRingModeChangedReceiver);
+ mRingModeChangedReceiver = null;
+ }
}
@Override
@@ -286,4 +389,17 @@
}
};
}
+
+ public void onClick(View v) {
+ // Touching any of the mute buttons causes us to get the state from the system and toggle it
+ switch(mAudioManager.getRingerMode()) {
+ case AudioManager.RINGER_MODE_NORMAL:
+ mAudioManager.setRingerMode(AudioManager.RINGER_MODE_SILENT);
+ break;
+ case AudioManager.RINGER_MODE_VIBRATE:
+ case AudioManager.RINGER_MODE_SILENT:
+ mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
+ break;
+ }
+ }
}