Settings: Add effects suppression text to Ring volume.

If the effects are being muted by a notification listener, display
a "Muted by <x>" msg instead of an active slider inside the
Ring/Notification volume setting pref.

Update volume pref design to optimize for this new custom appearance.

Depends on frameworks/base:
  Icdb5f85eb4bcaa1ead7d77c1460e06ad3f0604d5

Bug: 17461563
Change-Id: I6da871e16009370402451a2ff507de4762644a80
This commit is contained in:
John Spurlock
2014-11-14 14:32:01 -05:00
parent c88cdea2bb
commit fdebfc35c4
9 changed files with 183 additions and 115 deletions

View File

@@ -1,20 +0,0 @@
<!--
Copyright (C) 2014 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.
-->
<!-- shrink ic_audio_alarm from 32dp to 24dp using insets -->
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@*android:drawable/ic_audio_alarm"
android:inset="4dp"
/>

View File

@@ -1,20 +0,0 @@
<!--
Copyright (C) 2014 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.
-->
<!-- shrink ic_audio_vol from 32dp to 24dp using insets -->
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@*android:drawable/ic_audio_vol"
android:inset="4dp"
/>

View File

@@ -1,21 +0,0 @@
<!--
Copyright (C) 2014 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.
-->
<!-- shrink ic_audio_ring_notif from 32dp to 24dp using insets -->
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@*android:drawable/ic_audio_ring_notif"
android:inset="4dp"
/>

View File

@@ -1,20 +0,0 @@
<!--
Copyright (C) 2014 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.
-->
<!-- shrink ic_audio_ring_notif_mute from 32dp to 24dp using insets -->
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@*android:drawable/ic_audio_ring_notif_mute"
android:inset="4dp"
/>

View File

@@ -1,20 +0,0 @@
<!--
Copyright (C) 2014 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.
-->
<!-- shrink ic_audio_ring_notif_vibrate from 32dp to 24dp using insets -->
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@*android:drawable/ic_audio_ring_notif_vibrate"
android:inset="4dp"
/>

View File

@@ -0,0 +1,74 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2014 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.
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:gravity="center_vertical"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginTop="8dip"
android:layout_marginBottom="8dip">
<TextView android:id="@android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:textAppearance="@android:style/TextAppearance.Material.Subhead"
android:textColor="?android:attr/textColorPrimary"
android:ellipsize="marquee"
android:fadingEdge="horizontal" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="6dp">
<ImageView
android:id="@android:id/icon"
android:layout_gravity="center_vertical|start"
android:layout_width="24dp"
android:layout_height="24dp" />
<SeekBar android:id="@*android:id/seekbar"
android:layout_marginStart="24dp"
android:layout_gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView android:id="@+id/suppression_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|start"
android:textAlignment="viewStart"
android:layout_marginStart="24dp"
android:paddingStart="14dp"
android:singleLine="true"
android:ellipsize="end"
android:textAppearance="@android:style/TextAppearance.Material.Body1"
android:textColor="?android:attr/textColorSecondary" />
</FrameLayout>
</LinearLayout>
</FrameLayout>

View File

@@ -27,25 +27,25 @@
<!-- Media volume -->
<com.android.settings.notification.VolumeSeekBarPreference
android:key="media_volume"
android:icon="@drawable/ic_audio_vol_24dp"
android:icon="@*android:drawable/ic_audio_vol"
android:title="@string/media_volume_option_title" />
<!-- Alarm volume -->
<com.android.settings.notification.VolumeSeekBarPreference
android:key="alarm_volume"
android:icon="@drawable/ic_audio_alarm_24dp"
android:icon="@*android:drawable/ic_audio_alarm"
android:title="@string/alarm_volume_option_title" />
<!-- Ring volume -->
<com.android.settings.notification.VolumeSeekBarPreference
android:key="ring_volume"
android:icon="@drawable/ring_notif"
android:icon="@*android:drawable/ic_audio_ring_notif"
android:title="@string/ring_volume_option_title" />
<!-- Notification volume -->
<com.android.settings.notification.VolumeSeekBarPreference
android:key="notification_volume"
android:icon="@drawable/ring_notif"
android:icon="@*android:drawable/ic_audio_ring_notif"
android:title="@string/notification_volume_option_title" />
<!-- Also vibrate for calls -->

View File

@@ -16,9 +16,15 @@
package com.android.settings.notification;
import android.app.NotificationManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
import android.database.ContentObserver;
import android.database.Cursor;
import android.database.sqlite.SQLiteException;
@@ -42,7 +48,6 @@ import android.provider.SearchIndexableResource;
import android.provider.Settings;
import android.util.Log;
import android.widget.SeekBar;
import com.android.internal.widget.LockPatternUtils;
import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment;
@@ -53,6 +58,7 @@ import com.android.settings.search.Indexable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
public class NotificationSettings extends SettingsPreferenceFragment implements Indexable {
private static final String TAG = "NotificationSettings";
@@ -75,6 +81,7 @@ public class NotificationSettings extends SettingsPreferenceFragment implements
private final VolumePreferenceCallback mVolumeCallback = new VolumePreferenceCallback();
private final H mHandler = new H();
private final SettingsObserver mSettingsObserver = new SettingsObserver();
private final Receiver mReceiver = new Receiver();
private Context mContext;
private PackageManager mPM;
@@ -90,6 +97,8 @@ public class NotificationSettings extends SettingsPreferenceFragment implements
private Preference mNotificationAccess;
private boolean mSecure;
private int mLockscreenSelectedValue;
private ComponentName mSuppressor;
private int mRingOrNotificationProgress;
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -128,6 +137,7 @@ public class NotificationSettings extends SettingsPreferenceFragment implements
mNotificationAccess = findPreference(KEY_NOTIFICATION_ACCESS);
refreshNotificationListeners();
updateEffectsSuppressor();
}
@Override
@@ -136,6 +146,8 @@ public class NotificationSettings extends SettingsPreferenceFragment implements
refreshNotificationListeners();
lookupRingtoneNames();
mSettingsObserver.register(true);
mReceiver.register(true);
updateEffectsSuppressor();
}
@Override
@@ -143,6 +155,7 @@ public class NotificationSettings extends SettingsPreferenceFragment implements
super.onPause();
mVolumeCallback.stopSample();
mSettingsObserver.register(false);
mReceiver.register(false);
}
// === Volumes ===
@@ -154,12 +167,46 @@ public class NotificationSettings extends SettingsPreferenceFragment implements
return volumePref;
}
private void updateRingOrNotificationIcon(int progress) {
mRingOrNotificationPreference.showIcon(progress > 0
? R.drawable.ring_notif
: (mVibrator == null
? R.drawable.ring_notif_mute
: R.drawable.ring_notif_vibrate));
private void updateRingOrNotificationIcon() {
mRingOrNotificationPreference.showIcon(mSuppressor != null
? com.android.internal.R.drawable.ic_audio_ring_notif_mute
: mRingOrNotificationProgress > 0
? com.android.internal.R.drawable.ic_audio_ring_notif
: (mVibrator == null
? com.android.internal.R.drawable.ic_audio_ring_notif_mute
: com.android.internal.R.drawable.ic_audio_ring_notif_vibrate));
}
private void updateEffectsSuppressor() {
final ComponentName suppressor = NotificationManager.from(mContext).getEffectsSuppressor();
if (Objects.equals(suppressor, mSuppressor)) return;
mSuppressor = suppressor;
if (mRingOrNotificationPreference != null) {
final String text = suppressor != null ?
mContext.getString(com.android.internal.R.string.muted_by,
getSuppressorCaption(suppressor)) : null;
mRingOrNotificationPreference.setSuppressionText(text);
}
updateRingOrNotificationIcon();
}
private String getSuppressorCaption(ComponentName suppressor) {
final PackageManager pm = mContext.getPackageManager();
try {
final ServiceInfo info = pm.getServiceInfo(suppressor, 0);
if (info != null) {
final CharSequence seq = info.loadLabel(pm);
if (seq != null) {
final String str = seq.toString().trim();
if (str.length() > 0) {
return str;
}
}
}
} catch (Throwable e) {
Log.w(TAG, "Error loading suppressor caption", e);
}
return suppressor.getPackageName();
}
private final class VolumePreferenceCallback implements VolumeSeekBarPreference.Callback {
@@ -464,6 +511,7 @@ public class NotificationSettings extends SettingsPreferenceFragment implements
private static final int UPDATE_NOTIFICATION_RINGTONE = 2;
private static final int STOP_SAMPLE = 3;
private static final int UPDATE_RINGER_ICON = 4;
private static final int UPDATE_EFFECTS_SUPPRESSOR = 5;
private H() {
super(Looper.getMainLooper());
@@ -482,12 +530,36 @@ public class NotificationSettings extends SettingsPreferenceFragment implements
mVolumeCallback.stopSample();
break;
case UPDATE_RINGER_ICON:
updateRingOrNotificationIcon(msg.arg1);
mRingOrNotificationProgress = msg.arg1;
updateRingOrNotificationIcon();
break;
case UPDATE_EFFECTS_SUPPRESSOR:
updateEffectsSuppressor();
break;
}
}
}
private class Receiver extends BroadcastReceiver {
private boolean mRegistered;
public void register(boolean register) {
if (mRegistered == register) return;
if (register) {
mContext.registerReceiver(this,
new IntentFilter(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED));
} else {
mContext.unregisterReceiver(this);
}
mRegistered = register;
}
@Override
public void onReceive(Context context, Intent intent) {
mHandler.sendEmptyMessage(H.UPDATE_EFFECTS_SUPPRESSOR);
}
}
// === Indexing ===
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =

View File

@@ -23,14 +23,18 @@ import android.net.Uri;
import android.preference.PreferenceManager;
import android.preference.SeekBarPreference;
import android.preference.SeekBarVolumizer;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.TextView;
import com.android.settings.R;
import java.util.Objects;
/** A slider preference that directly controls an audio stream volume (no dialog) **/
public class VolumeSeekBarPreference extends SeekBarPreference
implements PreferenceManager.OnActivityStopListener {
@@ -41,10 +45,13 @@ public class VolumeSeekBarPreference extends SeekBarPreference
private SeekBarVolumizer mVolumizer;
private Callback mCallback;
private ImageView mIconView;
private TextView mSuppressionTextView;
private String mSuppressionText;
public VolumeSeekBarPreference(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
setLayoutResource(R.layout.preference_volume_slider);
}
public VolumeSeekBarPreference(Context context, AttributeSet attrs, int defStyleAttr) {
@@ -108,13 +115,14 @@ public class VolumeSeekBarPreference extends SeekBarPreference
mVolumizer.start();
mVolumizer.setSeekBar(mSeekBar);
mIconView = (ImageView) view.findViewById(com.android.internal.R.id.icon);
mSuppressionTextView = (TextView) view.findViewById(R.id.suppression_text);
mCallback.onStreamValueChanged(mStream, mSeekBar.getProgress());
updateSuppressionText();
}
// during initialization, this preference is the SeekBar listener
@Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromTouch) {
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) {
super.onProgressChanged(seekBar, progress, fromTouch);
mCallback.onStreamValueChanged(mStream, progress);
}
@@ -133,6 +141,21 @@ public class VolumeSeekBarPreference extends SeekBarPreference
+ "/" + R.raw.media_volume);
}
public void setSuppressionText(String text) {
if (Objects.equals(text, mSuppressionText)) return;
mSuppressionText = text;
updateSuppressionText();
}
private void updateSuppressionText() {
if (mSuppressionTextView != null && mSeekBar != null) {
mSuppressionTextView.setText(mSuppressionText);
final boolean showSuppression = !TextUtils.isEmpty(mSuppressionText);
mSuppressionTextView.setVisibility(showSuppression ? View.VISIBLE : View.INVISIBLE);
mSeekBar.setVisibility(showSuppression ? View.INVISIBLE : View.VISIBLE);
}
}
public interface Callback {
void onSampleStarting(SeekBarVolumizer sbv);
void onStreamValueChanged(int stream, int progress);