diff --git a/res/values/strings.xml b/res/values/strings.xml index d2871ea3040..ecf378d5bd6 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -8828,6 +8828,9 @@ Notification volume + + Unavailable because ring is muted + Phone ringtone diff --git a/res/xml/sound_settings.xml b/res/xml/sound_settings.xml index a84b0aefcd2..7181e80b658 100644 --- a/res/xml/sound_settings.xml +++ b/res/xml/sound_settings.xml @@ -86,8 +86,8 @@ android:icon="@drawable/ic_notifications" android:title="@string/notification_volume_option_title" android:order="-150" - settings:controller= - "com.android.settings.notification.NotificationVolumePreferenceController"/> + settings:controller="com.android.settings.notification.NotificationVolumePreferenceController" + settings:unavailableSliceSubtitle="@string/notification_volume_disabled_summary"/> activityFilters, Intent intent) { activityFilters.add(new ActivityFilter(COMPONENT_NAME_WILDCARD, intent.getAction())); } - private void addActivityFilter(Set activityFilters, + private void addActivityFilter(Collection activityFilters, Class activityClass) { activityFilters.add(new ActivityFilter(new ComponentName(mContext, activityClass), null /* intentAction */)); diff --git a/src/com/android/settings/activityembedding/ActivityEmbeddingUtils.java b/src/com/android/settings/activityembedding/ActivityEmbeddingUtils.java index fdf13142cb8..63ea9cd519d 100644 --- a/src/com/android/settings/activityembedding/ActivityEmbeddingUtils.java +++ b/src/com/android/settings/activityembedding/ActivityEmbeddingUtils.java @@ -30,29 +30,25 @@ import com.android.settings.R; /** An util class collecting all common methods for the embedding activity features. */ public class ActivityEmbeddingUtils { // The smallest value of current width of the window when the split should be used. - private static final float MIN_CURRENT_SCREEN_SPLIT_WIDTH_DP = 720f; + private static final int MIN_CURRENT_SCREEN_SPLIT_WIDTH_DP = 720; // The smallest value of the smallest-width (sw) of the window in any rotation when // the split should be used. - private static final float MIN_SMALLEST_SCREEN_SPLIT_WIDTH_DP = 600f; + private static final int MIN_SMALLEST_SCREEN_SPLIT_WIDTH_DP = 600; // The minimum width of the activity to show the regular homepage layout. private static final float MIN_REGULAR_HOMEPAGE_LAYOUT_WIDTH_DP = 380f; private static final String TAG = "ActivityEmbeddingUtils"; - /** Get the smallest pixel value of width of the window when the split should be used. */ - public static int getMinCurrentScreenSplitWidthPx(Context context) { - final DisplayMetrics dm = context.getResources().getDisplayMetrics(); - return (int) TypedValue.applyDimension( - TypedValue.COMPLEX_UNIT_DIP, MIN_CURRENT_SCREEN_SPLIT_WIDTH_DP, dm); + /** Get the smallest width dp of the window when the split should be used. */ + public static int getMinCurrentScreenSplitWidthDp() { + return MIN_CURRENT_SCREEN_SPLIT_WIDTH_DP; } /** - * Get the smallest pixel value of the smallest-width (sw) of the window in any rotation when + * Get the smallest dp value of the smallest-width (sw) of the window in any rotation when * the split should be used. */ - public static int getMinSmallestScreenSplitWidthPx(Context context) { - final DisplayMetrics dm = context.getResources().getDisplayMetrics(); - return (int) TypedValue.applyDimension( - TypedValue.COMPLEX_UNIT_DIP, MIN_SMALLEST_SCREEN_SPLIT_WIDTH_DP, dm); + public static int getMinSmallestScreenSplitWidthDp() { + return MIN_SMALLEST_SCREEN_SPLIT_WIDTH_DP; } /** @@ -67,7 +63,7 @@ public class ActivityEmbeddingUtils { public static boolean isEmbeddingActivityEnabled(Context context) { final boolean isFlagEnabled = FeatureFlagUtils.isEnabled(context, FeatureFlagUtils.SETTINGS_SUPPORT_LARGE_SCREEN); - final boolean isSplitSupported = SplitController.getInstance().isSplitSupported(); + final boolean isSplitSupported = SplitController.getInstance(context).isSplitSupported(); Log.d(TAG, "isFlagEnabled = " + isFlagEnabled); Log.d(TAG, "isSplitSupported = " + isSplitSupported); diff --git a/src/com/android/settings/homepage/SettingsHomepageActivity.java b/src/com/android/settings/homepage/SettingsHomepageActivity.java index 2961abbd895..b27f5cc8b66 100644 --- a/src/com/android/settings/homepage/SettingsHomepageActivity.java +++ b/src/com/android/settings/homepage/SettingsHomepageActivity.java @@ -56,6 +56,7 @@ import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentTransaction; +import androidx.window.embedding.ActivityEmbeddingController; import androidx.window.embedding.SplitController; import androidx.window.embedding.SplitRule; @@ -102,7 +103,7 @@ public class SettingsHomepageActivity extends FragmentActivity implements private View mTwoPaneSuggestionView; private CategoryMixin mCategoryMixin; private Set mLoadedListeners; - private SplitController mSplitController; + private ActivityEmbeddingController mActivityEmbeddingController; private boolean mIsEmbeddingActivityEnabled; private boolean mIsTwoPane; // A regular layout shows icons on homepage, whereas a simplified layout doesn't. @@ -190,8 +191,8 @@ public class SettingsHomepageActivity extends FragmentActivity implements setupEdgeToEdge(); setContentView(R.layout.settings_homepage_container); - mSplitController = SplitController.getInstance(); - mIsTwoPane = mSplitController.isActivityEmbedded(this); + mActivityEmbeddingController = ActivityEmbeddingController.getInstance(this); + mIsTwoPane = mActivityEmbeddingController.isActivityEmbedded(this); updateAppBarMinHeight(); initHomepageContainer(); @@ -266,7 +267,7 @@ public class SettingsHomepageActivity extends FragmentActivity implements @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); - final boolean newTwoPaneState = mSplitController.isActivityEmbedded(this); + final boolean newTwoPaneState = mActivityEmbeddingController.isActivityEmbedded(this); if (mIsTwoPane != newTwoPaneState) { mIsTwoPane = newTwoPaneState; updateHomepageAppBar(); @@ -518,15 +519,15 @@ public class SettingsHomepageActivity extends FragmentActivity implements new ComponentName(getApplicationContext(), getClass()), targetComponentName, targetIntent.getAction(), - SplitRule.FINISH_ALWAYS, - SplitRule.FINISH_ALWAYS, + SplitRule.FinishBehavior.ALWAYS, + SplitRule.FinishBehavior.ALWAYS, true /* clearTop */); ActivityEmbeddingRulesController.registerTwoPanePairRule(this, new ComponentName(getApplicationContext(), Settings.class), targetComponentName, targetIntent.getAction(), - SplitRule.FINISH_ALWAYS, - SplitRule.FINISH_ALWAYS, + SplitRule.FinishBehavior.ALWAYS, + SplitRule.FinishBehavior.ALWAYS, true /* clearTop */); final UserHandle user = intent.getParcelableExtra(EXTRA_USER_HANDLE, UserHandle.class); diff --git a/src/com/android/settings/homepage/TopLevelSettings.java b/src/com/android/settings/homepage/TopLevelSettings.java index 8c122ef2ad6..af553d6393c 100644 --- a/src/com/android/settings/homepage/TopLevelSettings.java +++ b/src/com/android/settings/homepage/TopLevelSettings.java @@ -35,7 +35,7 @@ import androidx.preference.Preference; import androidx.preference.PreferenceFragmentCompat; import androidx.preference.PreferenceScreen; import androidx.recyclerview.widget.RecyclerView; -import androidx.window.embedding.SplitController; +import androidx.window.embedding.ActivityEmbeddingController; import com.android.settings.R; import com.android.settings.Utils; @@ -65,6 +65,7 @@ public class TopLevelSettings extends DashboardFragment implements SplitLayoutLi private int mPaddingHorizontal; private boolean mScrollNeeded = true; private boolean mFirstStarted = true; + private ActivityEmbeddingController mActivityEmbeddingController; public TopLevelSettings() { final Bundle args = new Bundle(); @@ -143,7 +144,7 @@ public class TopLevelSettings extends DashboardFragment implements SplitLayoutLi return; } - boolean activityEmbedded = SplitController.getInstance().isActivityEmbedded(getActivity()); + boolean activityEmbedded = isActivityEmbedded(); if (icicle != null) { mHighlightMixin = icicle.getParcelable(SAVED_HIGHLIGHT_MIXIN); mScrollNeeded = !mHighlightMixin.isActivityEmbedded() && activityEmbedded; @@ -154,6 +155,14 @@ public class TopLevelSettings extends DashboardFragment implements SplitLayoutLi } } + /** Wrap ActivityEmbeddingController#isActivityEmbedded for testing. */ + public boolean isActivityEmbedded() { + if (mActivityEmbeddingController == null) { + mActivityEmbeddingController = ActivityEmbeddingController.getInstance(getActivity()); + } + return mActivityEmbeddingController.isActivityEmbedded(getActivity()); + } + @Override public void onStart() { if (mFirstStarted) { @@ -161,7 +170,7 @@ public class TopLevelSettings extends DashboardFragment implements SplitLayoutLi FeatureFactory.getFactory(getContext()).getSearchFeatureProvider().sendPreIndexIntent( getContext()); } else if (mIsEmbeddingActivityEnabled && isOnlyOneActivityInTask() - && !SplitController.getInstance().isActivityEmbedded(getActivity())) { + && !isActivityEmbedded()) { // Set default highlight menu key for 1-pane homepage since it will show the placeholder // page once changing back to 2-pane. Log.i(TAG, "Set default menu key"); @@ -286,7 +295,7 @@ public class TopLevelSettings extends DashboardFragment implements SplitLayoutLi * 3. the current activity is embedded */ return mHighlightMixin != null && TextUtils.equals(pref.getKey(), mHighlightMixin.getHighlightPreferenceKey()) - && SplitController.getInstance().isActivityEmbedded(getActivity()); + && isActivityEmbedded(); } /** Show/hide the highlight on the menu entry for the search page presence */ diff --git a/src/com/android/settings/notification/NotificationVolumePreferenceController.java b/src/com/android/settings/notification/NotificationVolumePreferenceController.java index 4fd2341265f..54d78547d83 100644 --- a/src/com/android/settings/notification/NotificationVolumePreferenceController.java +++ b/src/com/android/settings/notification/NotificationVolumePreferenceController.java @@ -51,7 +51,6 @@ public class NotificationVolumePreferenceController extends private final RingReceiver mReceiver = new RingReceiver(); private final H mHandler = new H(); - public NotificationVolumePreferenceController(Context context) { this(context, KEY_NOTIFICATION_VOLUME); } @@ -63,7 +62,9 @@ public class NotificationVolumePreferenceController extends mVibrateIconId = R.drawable.ic_volume_ringer_vibrate; mSilentIconId = R.drawable.ic_notifications_off_24dp; - updateRingerMode(); + if (updateRingerMode()) { + updateEnabledState(); + } } /** @@ -77,12 +78,10 @@ public class NotificationVolumePreferenceController extends if (mPreference == null) { setupVolPreference(screen); } - mSeparateNotification = isSeparateNotificationConfigEnabled(); - if (mPreference != null) { - mPreference.setVisible(getAvailabilityStatus() == AVAILABLE); - } + updateEffectsSuppressor(); selectPreferenceIconState(); + updateEnabledState(); } /** @@ -95,15 +94,19 @@ public class NotificationVolumePreferenceController extends boolean newVal = isSeparateNotificationConfigEnabled(); if (newVal != mSeparateNotification) { mSeparateNotification = newVal; - // manually hiding the preference because being unavailable does not do the job + // Update UI if config change happens when Sound Settings page is on the foreground if (mPreference != null) { - mPreference.setVisible(getAvailabilityStatus() == AVAILABLE); + int status = getAvailabilityStatus(); + mPreference.setVisible(status == AVAILABLE + || status == DISABLED_DEPENDENT_SETTING); + if (status == DISABLED_DEPENDENT_SETTING) { + mPreference.setEnabled(false); + } } } } } - @OnLifecycleEvent(Lifecycle.Event.ON_RESUME) @Override public void onResume() { @@ -126,10 +129,11 @@ public class NotificationVolumePreferenceController extends @Override public int getAvailabilityStatus() { boolean separateNotification = isSeparateNotificationConfigEnabled(); - return mContext.getResources().getBoolean(R.bool.config_show_notification_volume) && !mHelper.isSingleVolume() && separateNotification - ? AVAILABLE : UNSUPPORTED_ON_DEVICE; + ? (mRingerMode == AudioManager.RINGER_MODE_NORMAL + ? AVAILABLE : DISABLED_DEPENDENT_SETTING) + : UNSUPPORTED_ON_DEVICE; } @Override @@ -158,7 +162,6 @@ public class NotificationVolumePreferenceController extends if (mVibrator != null && mRingerMode == AudioManager.RINGER_MODE_VIBRATE) { mMuteIcon = mVibrateIconId; mPreference.showIcon(mVibrateIconId); - } else if (mRingerMode == AudioManager.RINGER_MODE_SILENT || mVibrator == null && mRingerMode == AudioManager.RINGER_MODE_VIBRATE) { mMuteIcon = mSilentIconId; @@ -175,6 +178,12 @@ public class NotificationVolumePreferenceController extends } } + private void updateEnabledState() { + if (mPreference != null) { + mPreference.setEnabled(mRingerMode == AudioManager.RINGER_MODE_NORMAL); + } + } + private final class H extends Handler { private static final int UPDATE_EFFECTS_SUPPRESSOR = 1; private static final int UPDATE_RINGER_MODE = 2; @@ -191,10 +200,13 @@ public class NotificationVolumePreferenceController extends updateEffectsSuppressor(); break; case UPDATE_RINGER_MODE: - updateRingerMode(); + if (updateRingerMode()) { + updateEnabledState(); + } break; case NOTIFICATION_VOLUME_CHANGED: selectPreferenceIconState(); + updateEnabledState(); break; } } @@ -239,5 +251,4 @@ public class NotificationVolumePreferenceController extends } } } - } diff --git a/src/com/android/settings/notification/RingerModeAffectedVolumePreferenceController.java b/src/com/android/settings/notification/RingerModeAffectedVolumePreferenceController.java index 255fe2f1cd3..ec619b468bc 100644 --- a/src/com/android/settings/notification/RingerModeAffectedVolumePreferenceController.java +++ b/src/com/android/settings/notification/RingerModeAffectedVolumePreferenceController.java @@ -140,11 +140,18 @@ public abstract class RingerModeAffectedVolumePreferenceController extends return valueUpdated; } - protected void updateRingerMode() { + /** + * Updates UI Icon in response to ringer mode changes. + * @return whether the ringer mode has changed. + */ + protected boolean updateRingerMode() { final int ringerMode = mHelper.getRingerModeInternal(); - if (mRingerMode == ringerMode) return; + if (mRingerMode == ringerMode) { + return false; + } mRingerMode = ringerMode; selectPreferenceIconState(); + return true; } /** diff --git a/src/com/android/settings/slices/VolumeSliceHelper.java b/src/com/android/settings/slices/VolumeSliceHelper.java index 486148270c8..1ba177823cc 100644 --- a/src/com/android/settings/slices/VolumeSliceHelper.java +++ b/src/com/android/settings/slices/VolumeSliceHelper.java @@ -93,8 +93,9 @@ public class VolumeSliceHelper { if (AudioManager.VOLUME_CHANGED_ACTION.equals(action)) { handleVolumeChanged(context, intent); - } else if (AudioManager.STREAM_MUTE_CHANGED_ACTION.equals(action) - || AudioManager.STREAM_DEVICES_CHANGED_ACTION.equals(action)) { + } else if (AudioManager.STREAM_MUTE_CHANGED_ACTION.equals(action)) { + handleMuteChanged(context, intent); + } else if (AudioManager.STREAM_DEVICES_CHANGED_ACTION.equals(action)) { handleStreamChanged(context, intent); } else { notifyAllStreamsChanged(context); @@ -109,8 +110,29 @@ public class VolumeSliceHelper { } } + /** + * When mute is changed, notifyChange on relevant Volume Slice ContentResolvers to mark them + * as needing update. + * + * In addition to the matching stream, we always notifyChange for the Notification stream + * when Ring events are issued. This is to make sure that Notification always gets updated + * for RingerMode changes, even if Notification's volume is zero and therefore it would not + * get its own AudioManager.VOLUME_CHANGED_ACTION. + */ + private static void handleMuteChanged(Context context, Intent intent) { + final int inputType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1); + handleStreamChanged(context, inputType); + if (inputType == AudioManager.STREAM_RING) { + handleStreamChanged(context, AudioManager.STREAM_NOTIFICATION); + } + } + private static void handleStreamChanged(Context context, Intent intent) { final int inputType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1); + handleStreamChanged(context, inputType); + } + + private static void handleStreamChanged(Context context, int inputType) { synchronized (sRegisteredUri) { for (Map.Entry entry : sRegisteredUri.entrySet()) { if (entry.getValue() == inputType) { diff --git a/src/com/android/settings/widget/HighlightableTopLevelPreferenceAdapter.java b/src/com/android/settings/widget/HighlightableTopLevelPreferenceAdapter.java index 3cc7ef27f7e..8084a4811d6 100644 --- a/src/com/android/settings/widget/HighlightableTopLevelPreferenceAdapter.java +++ b/src/com/android/settings/widget/HighlightableTopLevelPreferenceAdapter.java @@ -30,7 +30,7 @@ import androidx.preference.PreferenceGroup; import androidx.preference.PreferenceGroupAdapter; import androidx.preference.PreferenceViewHolder; import androidx.recyclerview.widget.RecyclerView; -import androidx.window.embedding.SplitController; +import androidx.window.embedding.ActivityEmbeddingController; import com.android.settings.R; import com.android.settings.Utils; @@ -250,6 +250,7 @@ public class HighlightableTopLevelPreferenceAdapter extends PreferenceGroupAdapt } private boolean isHighlightNeeded() { - return SplitController.getInstance().isActivityEmbedded(mHomepageActivity); + return ActivityEmbeddingController.getInstance(mHomepageActivity) + .isActivityEmbedded(mHomepageActivity); } } diff --git a/tests/robotests/src/com/android/settings/notification/NotificationVolumePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/NotificationVolumePreferenceControllerTest.java index 7e7ad10d8c1..594ef625ffb 100644 --- a/tests/robotests/src/com/android/settings/notification/NotificationVolumePreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/notification/NotificationVolumePreferenceControllerTest.java @@ -198,6 +198,7 @@ public class NotificationVolumePreferenceControllerTest { com.android.settings.R.bool.config_show_notification_volume)).thenReturn(true); // block the alternative condition to enable controller when(mTelephonyManager.isVoiceCapable()).thenReturn(true); + when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL); DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, SystemUiDeviceConfigFlags.VOLUME_SEPARATE_NOTIFICATION, "false", false); @@ -217,8 +218,8 @@ public class NotificationVolumePreferenceControllerTest { SystemUiDeviceConfigFlags.VOLUME_SEPARATE_NOTIFICATION, Boolean.toString(true), false); - assertThat(controller.getAvailabilityStatus() - == BasePreferenceController.AVAILABLE).isTrue(); + assertThat(controller.getAvailabilityStatus()).isEqualTo( + BasePreferenceController.AVAILABLE); } @Test @@ -233,9 +234,10 @@ public class NotificationVolumePreferenceControllerTest { // block the alternative condition to enable controller when(mTelephonyManager.isVoiceCapable()).thenReturn(true); + when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, SystemUiDeviceConfigFlags.VOLUME_SEPARATE_NOTIFICATION, "true", false); - NotificationVolumePreferenceController controller = new NotificationVolumePreferenceController(mContext); @@ -254,4 +256,19 @@ public class NotificationVolumePreferenceControllerTest { == BasePreferenceController.UNSUPPORTED_ON_DEVICE).isTrue(); } + @Test + public void ringerModeSilent_unaliased_getAvailability_returnsDisabled() { + when(mResources.getBoolean( + com.android.settings.R.bool.config_show_notification_volume)).thenReturn(true); + when(mHelper.isSingleVolume()).thenReturn(false); + + when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_SILENT); + + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, + SystemUiDeviceConfigFlags.VOLUME_SEPARATE_NOTIFICATION, "true", false); + + assertThat(mController.getAvailabilityStatus()) + .isEqualTo(BasePreferenceController.DISABLED_DEPENDENT_SETTING); + } + } diff --git a/tests/robotests/src/com/android/settings/slices/VolumeSliceHelperTest.java b/tests/robotests/src/com/android/settings/slices/VolumeSliceHelperTest.java index 2ceeb253c9c..b4abd8c0a58 100644 --- a/tests/robotests/src/com/android/settings/slices/VolumeSliceHelperTest.java +++ b/tests/robotests/src/com/android/settings/slices/VolumeSliceHelperTest.java @@ -34,6 +34,7 @@ import android.media.AudioManager; import android.net.Uri; import com.android.settings.notification.MediaVolumePreferenceController; +import com.android.settings.notification.NotificationVolumePreferenceController; import com.android.settings.notification.RingVolumePreferenceController; import com.android.settings.notification.SeparateRingVolumePreferenceController; import com.android.settings.notification.VolumeSeekBarPreferenceController; @@ -64,6 +65,7 @@ public class VolumeSliceHelperTest { private VolumeSeekBarPreferenceController mMediaController; private VolumeSeekBarPreferenceController mRingController; private VolumeSeekBarPreferenceController mSeparateRingController; + private VolumeSeekBarPreferenceController mNotificationController; @Before public void setUp() { @@ -72,8 +74,9 @@ public class VolumeSliceHelperTest { when(mContext.getContentResolver()).thenReturn(mResolver); mMediaController = new MediaVolumePreferenceController(mContext); - mSeparateRingController = new SeparateRingVolumePreferenceController(mContext); mRingController = new RingVolumePreferenceController(mContext); + mSeparateRingController = new SeparateRingVolumePreferenceController(mContext); + mNotificationController = new NotificationVolumePreferenceController(mContext); mIntent = createIntent(AudioManager.VOLUME_CHANGED_ACTION) .putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, 1) @@ -238,6 +241,40 @@ public class VolumeSliceHelperTest { verify(mResolver).notifyChange(mMediaController.getSliceUri(), null); } + /** + * Without this test passing, when notification is separated from ring and its value is already + * zero, setting ringermode to silent would not disable notification slider. + * Note: the above scenario happens only in volume panel where controllers do not get to + * register for events such as RINGER_MODE_CHANGE. + */ + @Test + public void onReceive_ringVolumeMuted_shouldNotifyChangeNotificationSlice() { + final Intent intent = createIntent(AudioManager.STREAM_MUTE_CHANGED_ACTION) + .putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mRingController.getAudioStream()); + registerIntentToUri(mRingController); + registerIntentToUri(mNotificationController); + + VolumeSliceHelper.onReceive(mContext, intent); + + verify(mResolver).notifyChange(mNotificationController.getSliceUri(), null); + } + + /** + * Notifying notification slice on ring mute does not mean it should not notify ring slice. + * Rather, it should notify both slices. + */ + @Test + public void onReceive_ringVolumeMuted_shouldNotifyChangeRingSlice() { + final Intent intent = createIntent(AudioManager.STREAM_MUTE_CHANGED_ACTION) + .putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mRingController.getAudioStream()); + registerIntentToUri(mRingController); + registerIntentToUri(mNotificationController); + + VolumeSliceHelper.onReceive(mContext, intent); + + verify(mResolver).notifyChange(mRingController.getSliceUri(), null); + } + @Test public void onReceive_streamDevicesChanged_shouldNotifyChange() { final Intent intent = createIntent(AudioManager.STREAM_DEVICES_CHANGED_ACTION)