diff --git a/src/com/android/settings/notification/NotificationVolumePreferenceController.java b/src/com/android/settings/notification/NotificationVolumePreferenceController.java index fe7b70bf129..08b8aefde36 100644 --- a/src/com/android/settings/notification/NotificationVolumePreferenceController.java +++ b/src/com/android/settings/notification/NotificationVolumePreferenceController.java @@ -28,17 +28,18 @@ import android.os.Message; import android.service.notification.NotificationListenerService; import android.view.View; -import androidx.lifecycle.OnLifecycleEvent; +import androidx.annotation.NonNull; +import androidx.lifecycle.DefaultLifecycleObserver; +import androidx.lifecycle.LifecycleOwner; import androidx.preference.PreferenceScreen; import com.android.settings.R; -import com.android.settingslib.core.lifecycle.Lifecycle; /** * Update notification volume icon in Settings in response to user adjusting volume. */ public class NotificationVolumePreferenceController extends - RingerModeAffectedVolumePreferenceController { + RingerModeAffectedVolumePreferenceController implements DefaultLifecycleObserver { private static final String KEY_NOTIFICATION_VOLUME = "notification_volume"; private static final String TAG = "NotificationVolumePreferenceController"; @@ -80,17 +81,13 @@ public class NotificationVolumePreferenceController extends updateEnabledState(); } - @OnLifecycleEvent(Lifecycle.Event.ON_RESUME) @Override - public void onResume() { - super.onResume(); + public void onResume(@NonNull LifecycleOwner owner) { mReceiver.register(true); } - @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE) @Override - public void onPause() { - super.onPause(); + public void onPause(@NonNull LifecycleOwner owner) { mReceiver.register(false); } diff --git a/src/com/android/settings/notification/RemoteVolumeSeekBarPreference.java b/src/com/android/settings/notification/RemoteVolumeSeekBarPreference.java index 8714351d53e..8598b49ff3d 100644 --- a/src/com/android/settings/notification/RemoteVolumeSeekBarPreference.java +++ b/src/com/android/settings/notification/RemoteVolumeSeekBarPreference.java @@ -49,8 +49,7 @@ public class RemoteVolumeSeekBarPreference extends VolumeSeekBarPreference { } @Override - protected void init() { - if (mSeekBar == null) return; + protected void onBindViewHolder() { setContinuousUpdates(true); updateIconView(); updateSuppressionText(); diff --git a/src/com/android/settings/notification/RingVolumePreferenceController.java b/src/com/android/settings/notification/RingVolumePreferenceController.java index 09d8ecc102d..66d336c014c 100644 --- a/src/com/android/settings/notification/RingVolumePreferenceController.java +++ b/src/com/android/settings/notification/RingVolumePreferenceController.java @@ -27,16 +27,17 @@ import android.os.Looper; import android.os.Message; import android.service.notification.NotificationListenerService; -import androidx.lifecycle.OnLifecycleEvent; +import androidx.annotation.NonNull; +import androidx.lifecycle.DefaultLifecycleObserver; +import androidx.lifecycle.LifecycleOwner; import com.android.settings.R; -import com.android.settingslib.core.lifecycle.Lifecycle; /** * This slider represents both ring and notification */ public class RingVolumePreferenceController extends - RingerModeAffectedVolumePreferenceController { + RingerModeAffectedVolumePreferenceController implements DefaultLifecycleObserver { private static final String KEY_RING_VOLUME = "ring_volume"; private static final String TAG = "RingVolumePreferenceController"; @@ -58,10 +59,8 @@ public class RingVolumePreferenceController extends updateRingerMode(); } - @OnLifecycleEvent(Lifecycle.Event.ON_RESUME) @Override - public void onResume() { - super.onResume(); + public void onResume(@NonNull LifecycleOwner owner) { mReceiver.register(true); updateEffectsSuppressor(); selectPreferenceIconState(); @@ -71,10 +70,8 @@ public class RingVolumePreferenceController extends } } - @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE) @Override - public void onPause() { - super.onPause(); + public void onPause(@NonNull LifecycleOwner owner) { mReceiver.register(false); } diff --git a/src/com/android/settings/notification/SeparateRingVolumePreferenceController.java b/src/com/android/settings/notification/SeparateRingVolumePreferenceController.java index feb976fe8cd..e38d16f1aa8 100644 --- a/src/com/android/settings/notification/SeparateRingVolumePreferenceController.java +++ b/src/com/android/settings/notification/SeparateRingVolumePreferenceController.java @@ -27,17 +27,18 @@ import android.os.Looper; import android.os.Message; import android.service.notification.NotificationListenerService; -import androidx.lifecycle.OnLifecycleEvent; +import androidx.annotation.NonNull; +import androidx.lifecycle.DefaultLifecycleObserver; +import androidx.lifecycle.LifecycleOwner; import com.android.settings.R; -import com.android.settingslib.core.lifecycle.Lifecycle; /** * This slider is used to represent ring volume when ring is separated from notification */ // LINT.IfChange public class SeparateRingVolumePreferenceController extends - RingerModeAffectedVolumePreferenceController { + RingerModeAffectedVolumePreferenceController implements DefaultLifecycleObserver { private static final String KEY_SEPARATE_RING_VOLUME = "separate_ring_volume"; private static final String TAG = "SeparateRingVolumePreferenceController"; @@ -59,10 +60,8 @@ public class SeparateRingVolumePreferenceController extends updateRingerMode(); } - @OnLifecycleEvent(Lifecycle.Event.ON_RESUME) @Override - public void onResume() { - super.onResume(); + public void onResume(@NonNull LifecycleOwner owner) { mReceiver.register(true); updateEffectsSuppressor(); selectPreferenceIconState(); @@ -73,10 +72,8 @@ public class SeparateRingVolumePreferenceController extends } } - @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE) @Override - public void onPause() { - super.onPause(); + public void onPause(@NonNull LifecycleOwner owner) { mReceiver.register(false); } diff --git a/src/com/android/settings/notification/SoundSettings.java b/src/com/android/settings/notification/SoundSettings.java index fffb7849bbc..0b23e07f4c0 100644 --- a/src/com/android/settings/notification/SoundSettings.java +++ b/src/com/android/settings/notification/SoundSettings.java @@ -46,6 +46,7 @@ import com.android.settings.widget.UpdatableListPreferenceDialogFragment; import com.android.settingslib.core.AbstractPreferenceController; import com.android.settingslib.core.instrumentation.Instrumentable; import com.android.settingslib.core.lifecycle.Lifecycle; +import com.android.settingslib.preference.UtilsKt; import com.android.settingslib.search.SearchIndexable; import java.util.ArrayList; @@ -113,14 +114,12 @@ public class SoundSettings extends DashboardFragment implements OnActivityResult if (phoneRingTonePreference != null && openPhoneRingtonePicker) { onPreferenceTreeClick(phoneRingTonePreference); } - if (isCatalystEnabled()) { - for (String key : getPreferenceKeysInHierarchy()) { - Preference preference = findPreference(key); - if (preference instanceof VolumeSeekBarPreference) { - ((VolumeSeekBarPreference) preference).setCallback(mVolumeCallback); - } + UtilsKt.forEachRecursively(getPreferenceScreen(), preference -> { + if (preference instanceof VolumeSeekBarPreference) { + ((VolumeSeekBarPreference) preference).setCallback(mVolumeCallback); } - } + return null; + }); } @Override @@ -203,22 +202,11 @@ public class SoundSettings extends DashboardFragment implements OnActivityResult @Override public void onAttach(Context context) { super.onAttach(context); - ArrayList volumeControllers = new ArrayList<>(); - volumeControllers.add(use(AlarmVolumePreferenceController.class)); - volumeControllers.add(use(MediaVolumePreferenceController.class)); - volumeControllers.add(use(SeparateRingVolumePreferenceController.class)); - volumeControllers.add(use(NotificationVolumePreferenceController.class)); - volumeControllers.add(use(CallVolumePreferenceController.class)); use(HandsFreeProfileOutputPreferenceController.class).setCallback(listPreference -> onPreferenceDataChanged(listPreference)); mHfpOutputControllerKey = use(HandsFreeProfileOutputPreferenceController.class).getPreferenceKey(); - - for (VolumeSeekBarPreferenceController controller : volumeControllers) { - controller.setCallback(mVolumeCallback); - getSettingsLifecycle().addObserver(controller); - } } // === Volumes === diff --git a/src/com/android/settings/notification/VolumeSeekBarPreference.java b/src/com/android/settings/notification/VolumeSeekBarPreference.java index 2156c05a8ba..836962875b8 100644 --- a/src/com/android/settings/notification/VolumeSeekBarPreference.java +++ b/src/com/android/settings/notification/VolumeSeekBarPreference.java @@ -62,7 +62,6 @@ public class VolumeSeekBarPreference extends SeekBarPreference { private boolean mZenMuted; private int mIconResId; private int mMuteIconResId; - private boolean mStopped; @VisibleForTesting AudioManager mAudioManager; private Locale mLocale; @@ -114,18 +113,13 @@ public class VolumeSeekBarPreference extends SeekBarPreference { mListener = listener; } - public void onActivityResume() { - if (mStopped) { - init(); - } - } - - public void onActivityPause() { - mStopped = true; + @Override + public void onDetached() { if (mVolumizer != null) { mVolumizer.stop(); mVolumizer = null; } + super.onDetached(); } @Override @@ -135,16 +129,25 @@ public class VolumeSeekBarPreference extends SeekBarPreference { mIconView = (ImageView) view.findViewById(com.android.internal.R.id.icon); mSuppressionTextView = (TextView) view.findViewById(R.id.suppression_text); mTitle = (TextView) view.findViewById(com.android.internal.R.id.title); - init(); + onBindViewHolder(); } - protected void init() { - if (mSeekBar == null) return; - // It's unnecessary to set up relevant volumizer configuration if preference is disabled. - if (!isEnabled()) { - mSeekBar.setEnabled(false); - return; + protected void onBindViewHolder() { + boolean isEnabled = isEnabled(); + mSeekBar.setEnabled(isEnabled); + if (mVolumizer == null) { + createSeekBarVolumizer(); } + mVolumizer.setSeekBar(mSeekBar); + updateIconView(); + updateSuppressionText(); + if (isEnabled && mListener != null) { + mListener.onUpdateMuteState(); + } + } + + @SuppressWarnings("NullAway") + protected void createSeekBarVolumizer() { final SeekBarVolumizer.Callback sbvc = new SeekBarVolumizer.Callback() { @Override public void onSampleStarting(SeekBarVolumizer sbv) { @@ -184,16 +187,8 @@ public class VolumeSeekBarPreference extends SeekBarPreference { } }; final Uri sampleUri = mStream == AudioManager.STREAM_MUSIC ? getMediaVolumeUri() : null; - if (mVolumizer == null) { - mVolumizer = mSeekBarVolumizerFactory.create(mStream, sampleUri, sbvc); - } + mVolumizer = mSeekBarVolumizerFactory.create(mStream, sampleUri, sbvc); mVolumizer.start(); - mVolumizer.setSeekBar(mSeekBar); - updateIconView(); - updateSuppressionText(); - if (mListener != null) { - mListener.onUpdateMuteState(); - } } protected void updateIconView() { diff --git a/src/com/android/settings/notification/VolumeSeekBarPreferenceController.java b/src/com/android/settings/notification/VolumeSeekBarPreferenceController.java index 285e8ddbeb9..18634214e35 100644 --- a/src/com/android/settings/notification/VolumeSeekBarPreferenceController.java +++ b/src/com/android/settings/notification/VolumeSeekBarPreferenceController.java @@ -19,22 +19,17 @@ package com.android.settings.notification; import android.content.Context; import androidx.annotation.VisibleForTesting; -import androidx.lifecycle.LifecycleObserver; -import androidx.lifecycle.OnLifecycleEvent; import androidx.preference.PreferenceScreen; import com.android.settings.R; -import com.android.settings.notification.VolumeSeekBarPreference.Callback; -import com.android.settingslib.core.lifecycle.Lifecycle; /** * Base class for preference controller that handles VolumeSeekBarPreference */ public abstract class VolumeSeekBarPreferenceController extends - AdjustVolumeRestrictedPreferenceController implements LifecycleObserver { + AdjustVolumeRestrictedPreferenceController { protected VolumeSeekBarPreference mPreference; - protected VolumeSeekBarPreference.Callback mVolumePreferenceCallback; protected AudioHelper mHelper; protected VolumeSeekBarPreference.Listener mVolumePreferenceListener; @@ -48,10 +43,6 @@ public abstract class VolumeSeekBarPreferenceController extends mHelper = helper; } - public void setCallback(Callback callback) { - mVolumePreferenceCallback = callback; - } - @Override public void displayPreference(PreferenceScreen screen) { super.displayPreference(screen); @@ -62,26 +53,11 @@ public abstract class VolumeSeekBarPreferenceController extends protected void setupVolPreference(PreferenceScreen screen) { mPreference = screen.findPreference(getPreferenceKey()); - mPreference.setCallback(mVolumePreferenceCallback); mPreference.setListener(mVolumePreferenceListener); mPreference.setStream(getAudioStream()); mPreference.setMuteIcon(getMuteIcon()); } - @OnLifecycleEvent(Lifecycle.Event.ON_RESUME) - public void onResume() { - if (mPreference != null) { - mPreference.onActivityResume(); - } - } - - @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE) - public void onPause() { - if (mPreference != null) { - mPreference.onActivityPause(); - } - } - @Override public int getSliceHighlightMenuRes() { return R.string.menu_key_sound; diff --git a/tests/robotests/src/com/android/settings/notification/VolumeSeekBarPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/VolumeSeekBarPreferenceControllerTest.java index f7e32a2c9d9..d93349d294f 100644 --- a/tests/robotests/src/com/android/settings/notification/VolumeSeekBarPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/notification/VolumeSeekBarPreferenceControllerTest.java @@ -31,14 +31,18 @@ import androidx.preference.Preference; import androidx.preference.PreferenceScreen; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; -import org.mockito.MockitoAnnotations; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; import org.robolectric.RobolectricTestRunner; @RunWith(RobolectricTestRunner.class) public class VolumeSeekBarPreferenceControllerTest { + @Rule + public final MockitoRule mMockitoRule = MockitoJUnit.rule(); @Mock private Context mContext; @@ -47,8 +51,6 @@ public class VolumeSeekBarPreferenceControllerTest { @Mock private VolumeSeekBarPreference mPreference; @Mock - private VolumeSeekBarPreference.Callback mCallback; - @Mock private VolumeSeekBarPreference.Listener mListener; @Mock private AudioHelper mHelper; @@ -57,10 +59,9 @@ public class VolumeSeekBarPreferenceControllerTest { @Before public void setUp() { - MockitoAnnotations.initMocks(this); when(mScreen.findPreference(nullable(String.class))).thenReturn(mPreference); when(mPreference.getKey()).thenReturn("key"); - mController = new VolumeSeekBarPreferenceControllerTestable(mContext, mCallback, true, + mController = new VolumeSeekBarPreferenceControllerTestable(mContext, true, mPreference.getKey(), mListener); mController.setAudioHelper(mHelper); } @@ -69,7 +70,6 @@ public class VolumeSeekBarPreferenceControllerTest { public void displayPreference_available_shouldUpdatePreference() { mController.displayPreference(mScreen); - verify(mPreference).setCallback(mCallback); verify(mPreference).setStream(VolumeSeekBarPreferenceControllerTestable.AUDIO_STREAM); verify(mPreference).setMuteIcon(VolumeSeekBarPreferenceControllerTestable.MUTE_ICON); verify(mPreference).setListener(mListener); @@ -77,7 +77,7 @@ public class VolumeSeekBarPreferenceControllerTest { @Test public void displayPreference_notAvailable_shouldNotUpdatePreference() { - mController = new VolumeSeekBarPreferenceControllerTestable(mContext, mCallback, false, + mController = new VolumeSeekBarPreferenceControllerTestable(mContext, false, mPreference.getKey(), mListener); mController.displayPreference(mScreen); @@ -88,24 +88,6 @@ public class VolumeSeekBarPreferenceControllerTest { verify(mPreference, never()).setListener(mListener); } - @Test - public void onResume_shouldResumePreference() { - mController.displayPreference(mScreen); - - mController.onResume(); - - verify(mPreference).onActivityResume(); - } - - @Test - public void onPause_shouldPausePreference() { - mController.displayPreference(mScreen); - - mController.onPause(); - - verify(mPreference).onActivityPause(); - } - @Test public void sliderMethods_handleNullPreference() { when(mHelper.getStreamVolume(mController.getAudioStream())).thenReturn(4); @@ -152,19 +134,17 @@ public class VolumeSeekBarPreferenceControllerTest { assertThat(mController.getSliderPosition()).isEqualTo(7); } - private class VolumeSeekBarPreferenceControllerTestable - extends VolumeSeekBarPreferenceController { + private static class VolumeSeekBarPreferenceControllerTestable extends + VolumeSeekBarPreferenceController { - private final static int AUDIO_STREAM = 1; - private final static int MUTE_ICON = 2; + private static final int AUDIO_STREAM = 1; + private static final int MUTE_ICON = 2; - private boolean mAvailable; + private final boolean mAvailable; - VolumeSeekBarPreferenceControllerTestable(Context context, - VolumeSeekBarPreference.Callback callback, boolean available, String key, + VolumeSeekBarPreferenceControllerTestable(Context context, boolean available, String key, VolumeSeekBarPreference.Listener listener) { super(context, key); - setCallback(callback); mAvailable = available; mVolumePreferenceListener = listener; } diff --git a/tests/robotests/src/com/android/settings/notification/VolumeSeekBarPreferenceTest.java b/tests/robotests/src/com/android/settings/notification/VolumeSeekBarPreferenceTest.java index 942db3fa4d8..2e17908aeac 100644 --- a/tests/robotests/src/com/android/settings/notification/VolumeSeekBarPreferenceTest.java +++ b/tests/robotests/src/com/android/settings/notification/VolumeSeekBarPreferenceTest.java @@ -32,12 +32,14 @@ import android.preference.SeekBarVolumizer; import android.widget.SeekBar; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.Mock; -import org.mockito.MockitoAnnotations; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; import org.robolectric.RobolectricTestRunner; import java.util.Locale; @@ -47,6 +49,10 @@ public class VolumeSeekBarPreferenceTest { private static final CharSequence CONTENT_DESCRIPTION = "TEST"; private static final int STREAM = 5; + + @Rule + public final MockitoRule mMockitoRule = MockitoJUnit.rule(); + @Mock private AudioManager mAudioManager; @Mock @@ -70,10 +76,10 @@ public class VolumeSeekBarPreferenceTest { @Before public void setUp() { - MockitoAnnotations.initMocks(this); when(mContext.getSystemService(Context.AUDIO_SERVICE)).thenReturn(mAudioManager); when(mSeekBarVolumizerFactory.create(eq(STREAM), eq(null), mSbvc.capture())) .thenReturn(mVolumizer); + doCallRealMethod().when(mPreference).createSeekBarVolumizer(); doCallRealMethod().when(mPreference).setStream(anyInt()); doCallRealMethod().when(mPreference).updateContentDescription(CONTENT_DESCRIPTION); mPreference.mSeekBar = mSeekBar; @@ -99,50 +105,50 @@ public class VolumeSeekBarPreferenceTest { } @Test - public void init_listenerIsCalled() { + public void onBindViewHolder_listenerIsCalled() { when(mPreference.isEnabled()).thenReturn(true); doCallRealMethod().when(mPreference).setListener(mListener); - doCallRealMethod().when(mPreference).init(); + doCallRealMethod().when(mPreference).onBindViewHolder(); mPreference.setStream(STREAM); mPreference.setListener(mListener); - mPreference.init(); + mPreference.onBindViewHolder(); verify(mPreference).updateContentDescription(CONTENT_DESCRIPTION); } @Test - public void init_listenerNotSet_noException() { + public void onBindViewHolder_listenerNotSet_noException() { when(mPreference.isEnabled()).thenReturn(true); - doCallRealMethod().when(mPreference).init(); + doCallRealMethod().when(mPreference).onBindViewHolder(); mPreference.setStream(STREAM); - mPreference.init(); + mPreference.onBindViewHolder(); verify(mPreference, never()).updateContentDescription(CONTENT_DESCRIPTION); } @Test - public void init_preferenceIsDisabled_shouldNotInvokeListener() { + public void onBindViewHolder_preferenceIsDisabled_shouldNotInvokeListener() { when(mPreference.isEnabled()).thenReturn(false); doCallRealMethod().when(mPreference).setListener(mListener); - doCallRealMethod().when(mPreference).init(); + doCallRealMethod().when(mPreference).onBindViewHolder(); mPreference.setStream(STREAM); - mPreference.init(); + mPreference.onBindViewHolder(); verify(mPreference, never()).updateContentDescription(CONTENT_DESCRIPTION); } @Test - public void init_changeProgress_overrideStateDescriptionCalled() { + public void onBindViewHolder_changeProgress_overrideStateDescriptionCalled() { final int progress = 4; when(mPreference.isEnabled()).thenReturn(true); when(mPreference.formatStateDescription(progress)).thenReturn(CONTENT_DESCRIPTION); - doCallRealMethod().when(mPreference).init(); + doCallRealMethod().when(mPreference).onBindViewHolder(); mPreference.setStream(STREAM); - mPreference.init(); + mPreference.onBindViewHolder(); verify(mSeekBarVolumizerFactory).create(eq(STREAM), eq(null), mSbvc.capture()); @@ -166,10 +172,10 @@ public class VolumeSeekBarPreferenceTest { when(mContext.getResources()).thenReturn(mRes); when(mRes.getConfiguration()).thenReturn(mConfig); when(mConfig.getLocales()).thenReturn(new LocaleList(Locale.US)); - doCallRealMethod().when(mPreference).init(); + doCallRealMethod().when(mPreference).onBindViewHolder(); mPreference.setStream(STREAM); - mPreference.init(); + mPreference.onBindViewHolder(); verify(mSeekBarVolumizerFactory).create(eq(STREAM), eq(null), mSbvc.capture());