Add notification volume controller in settings

Separate notification and ring controllers based on the ring/volume
stream alias boolean in config.xml.

For both ring and volume controller: Not show vibrate icon when vibration is not supported on device. Show
silent icon instead.

Known issue: Add the notification volume slider only in Settings, and
not in VolumePanelDialog. When the alias is set to false and the streams
separated, the ring volume slider in VolumePanelDialog keeps its title
of "Ring & notification volume" instead of changing to "Ring volume".

Bug: b/38477228

Test: make DEBUG_ROBOLECTRIC=1 ROBOTEST_FILTER=NotificationVolumePreferenceControllerTest RunSettingsRoboTests -j40
      make DEBUG_ROBOLECTRIC=1 ROBOTEST_FILTER=RingVolumePreferenceControllerTest RunSettingsRoboTests -j40
      make DEBUG_ROBOLECTRIC=1 ROBOTEST_FILTER=SoundSettingsTest RunSettingsRoboTests

Change-Id: Id17523f49b291a5cf612b90f93c3b2ab6486c62f
This commit is contained in:
Behnam Heydarshahi
2022-09-06 22:12:37 +00:00
parent 6ecbe4c18e
commit 3ac6aaf796
11 changed files with 590 additions and 36 deletions

View File

@@ -22,10 +22,14 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.res.Resources;
import android.media.AudioManager;
import android.os.Vibrator;
import android.service.notification.NotificationListenerService;
import android.telephony.TelephonyManager;
import com.android.internal.R;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -46,6 +50,8 @@ public class NotificationVolumePreferenceControllerTest {
private AudioManager mAudioManager;
@Mock
private Vibrator mVibrator;
@Mock
private Resources mResources;
private Context mContext;
private NotificationVolumePreferenceController mController;
@@ -57,6 +63,8 @@ public class NotificationVolumePreferenceControllerTest {
when(mContext.getSystemService(Context.TELEPHONY_SERVICE)).thenReturn(mTelephonyManager);
when(mContext.getSystemService(Context.AUDIO_SERVICE)).thenReturn(mAudioManager);
when(mContext.getSystemService(Context.VIBRATOR_SERVICE)).thenReturn(mVibrator);
when(mContext.getResources()).thenReturn(mResources);
mController = new NotificationVolumePreferenceController(mContext);
mController.setAudioHelper(mHelper);
}
@@ -76,15 +84,50 @@ public class NotificationVolumePreferenceControllerTest {
}
@Test
public void isAvailable_voiceCapable_shouldReturnFalse() {
public void isAvailable_voiceCapable_aliasedWithRing_shouldReturnFalse() {
when(mResources.getBoolean(
com.android.settings.R.bool.config_show_notification_volume)).thenReturn(true);
when(mResources.getBoolean(R.bool.config_alias_ring_notif_stream_types)).thenReturn(true);
NotificationVolumePreferenceController controller =
new NotificationVolumePreferenceController(mContext);
when(mHelper.isSingleVolume()).thenReturn(false);
when(mTelephonyManager.isVoiceCapable()).thenReturn(true);
assertThat(controller.isAvailable()).isFalse();
}
/**
* With the introduction of ring-notification volume separation, voice-capable devices could now
* display the notification volume slider.
*/
@Test
public void isAvailable_voiceCapable_separatedFromRing_shouldReturnTrue() {
when(mResources.getBoolean(
com.android.settings.R.bool.config_show_notification_volume)).thenReturn(true);
when(mResources.getBoolean(R.bool.config_alias_ring_notif_stream_types)).thenReturn(false);
NotificationVolumePreferenceController controller =
new NotificationVolumePreferenceController(mContext);
when(mHelper.isSingleVolume()).thenReturn(false);
when(mTelephonyManager.isVoiceCapable()).thenReturn(true);
assertThat(controller.isAvailable()).isTrue();
}
@Test
public void isAvailable_notShowNotificationVolume_shouldReturnFalse() {
when(mResources.getBoolean(
com.android.settings.R.bool.config_show_notification_volume)).thenReturn(false);
assertThat(mController.isAvailable()).isFalse();
}
@Test
public void isAvailable_notSingleVolume_notVoiceCapable_shouldReturnTrue() {
when(mResources.getBoolean(
com.android.settings.R.bool.config_show_notification_volume)).thenReturn(true);
when(mHelper.isSingleVolume()).thenReturn(false);
when(mTelephonyManager.isVoiceCapable()).thenReturn(false);
@@ -107,4 +150,24 @@ public class NotificationVolumePreferenceControllerTest {
public void isPublicSlice_returnTrue() {
assertThat(mController.isPublicSlice()).isTrue();
}
@Test
public void setHintsRing_DoesNotMatch() {
assertThat(mController.hintsMatch(
NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS)).isFalse();
}
@Test
public void setHintsAll_Matches() {
assertThat(mController.hintsMatch(NotificationListenerService.HINT_HOST_DISABLE_EFFECTS))
.isTrue();
}
@Test
public void setHintNotification_Matches() {
assertThat(mController
.hintsMatch(NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS))
.isTrue();
}
}

View File

@@ -18,15 +18,20 @@ package com.android.settings.notification;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.app.NotificationManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.res.Resources;
import android.media.AudioManager;
import android.os.Vibrator;
import android.service.notification.NotificationListenerService;
import android.telephony.TelephonyManager;
import com.android.settings.R;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -51,8 +56,13 @@ public class RingVolumePreferenceControllerTest {
private NotificationManager mNotificationManager;
@Mock
private ComponentName mSuppressor;
@Mock
private Resources mResources;
@Mock
private VolumeSeekBarPreference mPreference;
private Context mContext;
private RingVolumePreferenceController mController;
@Before
@@ -63,8 +73,9 @@ public class RingVolumePreferenceControllerTest {
shadowContext.setSystemService(Context.AUDIO_SERVICE, mAudioManager);
shadowContext.setSystemService(Context.VIBRATOR_SERVICE, mVibrator);
shadowContext.setSystemService(Context.NOTIFICATION_SERVICE, mNotificationManager);
mContext = RuntimeEnvironment.application;
mContext = spy(RuntimeEnvironment.application);
when(mNotificationManager.getEffectsSuppressor()).thenReturn(mSuppressor);
when(mContext.getResources()).thenReturn(mResources);
mController = new RingVolumePreferenceController(mContext);
mController.setAudioHelper(mHelper);
}
@@ -109,4 +120,92 @@ public class RingVolumePreferenceControllerTest {
public void isPublicSlice_returnTrue() {
assertThat(mController.isPublicSlice()).isTrue();
}
// todo: verify that the title change is displayed, by examining the underlying preference
@Test
public void ringNotificationStreamsNotAliased_sliderTitleSetToRingOnly() {
when(mResources.getBoolean(
com.android.internal.R.bool.config_alias_ring_notif_stream_types))
.thenReturn(false);
final RingVolumePreferenceController controller =
new RingVolumePreferenceController(mContext);
int expectedTitleId = R.string.separate_ring_volume_option_title;
assertThat(controller.mTitleId).isEqualTo(expectedTitleId);
}
@Test
public void ringNotificationStreamsAliased_sliderTitleIncludesBothRingNotification() {
when(mResources.getBoolean(
com.android.internal.R.bool.config_alias_ring_notif_stream_types)).thenReturn(true);
final RingVolumePreferenceController control = new RingVolumePreferenceController(mContext);
int expectedTitleId = R.string.ring_volume_option_title;
assertThat(control.mTitleId).isEqualTo(expectedTitleId);
}
@Test
public void setHintsRing_aliased_Matches() {
assertThat(mController.hintsMatch(
NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS, true)).isTrue();
}
@Test
public void setHintsRingNotification_aliased_Matches() {
assertThat(mController.hintsMatch(NotificationListenerService.HINT_HOST_DISABLE_EFFECTS,
true)).isTrue();
}
@Test
public void setHintNotification_aliased_Matches() {
assertThat(mController
.hintsMatch(NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS,
true)).isTrue();
}
@Test
public void setHintsRing_unaliased_Matches() {
assertThat(mController.hintsMatch(
NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS, false)).isTrue();
}
@Test
public void setHintsRingNotification_unaliased_Matches() {
assertThat(mController.hintsMatch(NotificationListenerService.HINT_HOST_DISABLE_EFFECTS,
false)).isTrue();
}
@Test
public void setHintNotification_unaliased_doesNotMatch() {
assertThat(mController
.hintsMatch(NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS,
false)).isFalse();
}
@Test
public void setRingerModeToVibrate_butNoVibratorAvailable_iconIsSilent() {
when(mHelper.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
mController.setPreference(mPreference);
mController.setVibrator(null);
mController.updateRingerMode();
assertThat(mController.getMuteIcon()).isEqualTo(mController.mSilentIconId);
}
@Test
public void setRingerModeToVibrate_VibratorAvailable_iconIsVibrate() {
when(mHelper.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
when(mVibrator.hasVibrator()).thenReturn(true);
mController.setPreference(mPreference);
mController.setVibrator(mVibrator);
mController.updateRingerMode();
assertThat(mController.getMuteIcon()).isEqualTo(mController.mVibrateIconId);
}
}

View File

@@ -35,6 +35,7 @@ import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
import com.android.settings.testutils.shadow.ShadowDeviceConfig;
import com.android.settings.testutils.shadow.ShadowUserManager;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
@@ -44,8 +45,6 @@ import org.robolectric.util.ReflectionHelpers;
import java.util.List;
import org.junit.Ignore;
@RunWith(RobolectricTestRunner.class)
public class SoundSettingsTest {
@@ -86,4 +85,19 @@ public class SoundSettingsTest {
assertThat(settings.mHandler.hasMessages(SoundSettings.STOP_SAMPLE)).isTrue();
}
@Test
public void notificationVolume_isBetweenRingAndAlarm() {
final Context context = spy(RuntimeEnvironment.application);
final SoundSettings settings = new SoundSettings();
final int xmlId = settings.getPreferenceScreenResId();
final List<String> keys = XmlTestUtils.getKeysFromPreferenceXml(context, xmlId);
int ring = keys.indexOf("ring_volume");
int notification = keys.indexOf("notification_volume");
int alarm = keys.indexOf("alarm_volume");
assertThat(ring < notification).isTrue();
assertThat(notification < alarm).isTrue();
}
}