Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a618a8a2 authored by Yiyi Shen's avatar Yiyi Shen Committed by Android (Google) Code Review
Browse files

Merge "[Audiosharing] Move entry preference out of group category" into main

parents 001ec9d3 5a8e10bb
Loading
Loading
Loading
Loading
+8 −7
Original line number Diff line number Diff line
@@ -30,13 +30,6 @@
        android:key="audio_sharing_device_list"
        android:title="@string/audio_sharing_device_group_title"
        settings:controller="com.android.settings.connecteddevice.audiosharing.AudioSharingDevicePreferenceController">
        <Preference
            android:fragment="com.android.settings.connecteddevice.audiosharing.AudioSharingDashboardFragment"
            android:icon="@drawable/ic_bt_le_audio_sharing"
            android:key="connected_device_audio_sharing_settings"
            android:order="100"
            android:title="@string/audio_sharing_title"
            settings:searchable="false" />
    </PreferenceCategory>

    <PreferenceCategory
@@ -44,6 +37,14 @@
        android:title="@string/connected_device_temp_bond_device_title"
        settings:controller="com.android.settings.connecteddevice.audiosharing.TemporaryBondDeviceGroupController" />

    <Preference
        android:fragment="com.android.settings.connecteddevice.audiosharing.AudioSharingDashboardFragment"
        android:icon="@drawable/ic_bt_le_audio_sharing"
        android:key="connected_device_audio_sharing_settings"
        android:title="@string/audio_sharing_title"
        settings:controller="com.android.settings.connecteddevice.audiosharing.AudioSharingPreferenceController"
        settings:searchable="false" />

    <PreferenceCategory
        android:key="available_device_list"
        android:title="@string/connected_device_media_device_title"
+2 −16
Original line number Diff line number Diff line
@@ -78,8 +78,6 @@ public class AudioSharingDevicePreferenceController extends BasePreferenceContro

    private static final String TAG = "AudioSharingDevicePrefController";
    private static final String KEY = "audio_sharing_device_list";
    private static final String KEY_AUDIO_SHARING_SETTINGS =
            "connected_device_audio_sharing_settings";

    @Nullable private final LocalBluetoothManager mBtManager;
    @Nullable private final CachedBluetoothDeviceManager mDeviceManager;
@@ -89,7 +87,6 @@ public class AudioSharingDevicePreferenceController extends BasePreferenceContro
    private final Executor mExecutor;
    private final MetricsFeatureProvider mMetricsFeatureProvider;
    @Nullable private PreferenceGroup mPreferenceGroup;
    @Nullable private Preference mAudioSharingSettingsPreference;
    @Nullable private BluetoothDeviceUpdater mBluetoothDeviceUpdater;
    @Nullable private DashboardFragment mFragment;
    @Nullable private AudioSharingDialogHandler mDialogHandler;
@@ -280,13 +277,8 @@ public class AudioSharingDevicePreferenceController extends BasePreferenceContro
        super.displayPreference(screen);
        mPreferenceGroup = screen.findPreference(KEY);
        if (mPreferenceGroup != null) {
            mAudioSharingSettingsPreference =
                    mPreferenceGroup.findPreference(KEY_AUDIO_SHARING_SETTINGS);
            mPreferenceGroup.setVisible(false);
        }
        if (mAudioSharingSettingsPreference != null) {
            mAudioSharingSettingsPreference.setVisible(false);
        }

        if (isAvailable()) {
            if (mBluetoothDeviceUpdater != null) {
@@ -320,11 +312,8 @@ public class AudioSharingDevicePreferenceController extends BasePreferenceContro
    @Override
    public void onDeviceAdded(Preference preference) {
        if (mPreferenceGroup != null) {
            if (mPreferenceGroup.getPreferenceCount() == 1) {
            if (mPreferenceGroup.getPreferenceCount() == 0) {
                mPreferenceGroup.setVisible(true);
                if (mAudioSharingSettingsPreference != null) {
                    mAudioSharingSettingsPreference.setVisible(true);
                }
            }
            mPreferenceGroup.addPreference(preference);
        }
@@ -334,11 +323,8 @@ public class AudioSharingDevicePreferenceController extends BasePreferenceContro
    public void onDeviceRemoved(Preference preference) {
        if (mPreferenceGroup != null) {
            mPreferenceGroup.removePreference(preference);
            if (mPreferenceGroup.getPreferenceCount() == 1) {
            if (mPreferenceGroup.getPreferenceCount() == 0) {
                mPreferenceGroup.setVisible(false);
                if (mAudioSharingSettingsPreference != null) {
                    mAudioSharingSettingsPreference.setVisible(false);
                }
            }
        }
    }
+54 −6
Original line number Diff line number Diff line
@@ -45,6 +45,9 @@ import java.util.concurrent.Executors;
public class AudioSharingPreferenceController extends BasePreferenceController
        implements DefaultLifecycleObserver, BluetoothCallback {
    private static final String TAG = "AudioSharingPreferenceController";
    private static final String CONNECTED_DEVICES_PREF_KEY =
            "connected_device_audio_sharing_settings";
    private static final String CONNECTION_PREFERENCES_PREF_KEY = "audio_sharing_settings";

    @Nullable private final LocalBluetoothManager mBtManager;
    @Nullable private final BluetoothEventManager mEventManager;
@@ -57,7 +60,7 @@ public class AudioSharingPreferenceController extends BasePreferenceController
            new BluetoothLeBroadcast.Callback() {
                @Override
                public void onBroadcastStarted(int reason, int broadcastId) {
                    refreshSummary();
                    refreshPreference();
                }

                @Override
@@ -69,7 +72,7 @@ public class AudioSharingPreferenceController extends BasePreferenceController

                @Override
                public void onBroadcastStopped(int reason, int broadcastId) {
                    refreshSummary();
                    refreshPreference();
                }

                @Override
@@ -111,6 +114,7 @@ public class AudioSharingPreferenceController extends BasePreferenceController
        }
        mEventManager.registerCallback(this);
        mBroadcast.registerServiceCallBack(mExecutor, mBroadcastCallback);
        updateVisibility();
    }

    @Override
@@ -131,6 +135,13 @@ public class AudioSharingPreferenceController extends BasePreferenceController
    public void displayPreference(@NonNull PreferenceScreen screen) {
        super.displayPreference(screen);
        mPreference = screen.findPreference(getPreferenceKey());
        // super.displayPreference set the visibility based on isAvailable()
        // immediately set the preference invisible on Connected devices page to avoid the audio
        // sharing entrance being shown before updateVisibility(need binder call) take effects.
        if (mPreference != null && CONNECTED_DEVICES_PREF_KEY.equals(getPreferenceKey())) {
            mPreference.setVisible(false);
        }
        updateVisibility();
    }

    @Override
@@ -141,14 +152,51 @@ public class AudioSharingPreferenceController extends BasePreferenceController

    @Override
    public CharSequence getSummary() {
        return BluetoothUtils.isBroadcasting(mBtManager)
        return switch (getPreferenceKey()) {
            case CONNECTION_PREFERENCES_PREF_KEY -> BluetoothUtils.isBroadcasting(mBtManager)
                    ? mContext.getString(R.string.audio_sharing_summary_on)
                    : mContext.getString(R.string.audio_sharing_summary_off);
            default -> "";
        };
    }

    @Override
    public void onBluetoothStateChanged(@AdapterState int bluetoothState) {
        refreshSummary();
        refreshPreference();
    }

    private void refreshPreference() {
        switch (getPreferenceKey()) {
            // Audio sharing entrance on Connected devices page has no summary, but its visibility
            // will change based on audio sharing state
            case CONNECTED_DEVICES_PREF_KEY -> updateVisibility();
            // Audio sharing entrance on Connection preferences page always show up, but its summary
            // will change based on audio sharing state
            case CONNECTION_PREFERENCES_PREF_KEY -> refreshSummary();
        }
    }

    private void updateVisibility() {
        if (mPreference == null) {
            return;
        }
        switch (getPreferenceKey()) {
            case CONNECTED_DEVICES_PREF_KEY -> {
                var unused =
                        ThreadUtils.postOnBackgroundThread(
                                () -> {
                                    boolean visible = BluetoothUtils.isBroadcasting(mBtManager);
                                    AudioSharingUtils.postOnMainThread(
                                            mContext,
                                            () -> {
                                                // Check nullability to pass NullAway check
                                                if (mPreference != null) {
                                                    mPreference.setVisible(visible);
                                                }
                                            });
                                });
            }
        }
    }

    private void refreshSummary() {
+2 −13
Original line number Diff line number Diff line
@@ -117,8 +117,6 @@ import java.util.concurrent.Executor;
        })
public class AudioSharingDevicePreferenceControllerTest {
    private static final String KEY = "audio_sharing_device_list";
    private static final String KEY_AUDIO_SHARING_SETTINGS =
            "connected_device_audio_sharing_settings";
    private static final String TEST_DEVICE_NAME = "test";

    @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();
@@ -151,7 +149,6 @@ public class AudioSharingDevicePreferenceControllerTest {
    private Lifecycle mLifecycle;
    private LifecycleOwner mLifecycleOwner;
    private PreferenceCategory mPreferenceGroup;
    private Preference mAudioSharingPreference;
    private FakeFeatureFactory mFeatureFactory;
    private AudioManager mAudioManager;

@@ -189,10 +186,6 @@ public class AudioSharingDevicePreferenceControllerTest {
        when(mScreen.getContext()).thenReturn(mContext);
        mPreferenceGroup = spy(new PreferenceCategory(mContext));
        doReturn(mPreferenceManager).when(mPreferenceGroup).getPreferenceManager();
        mAudioSharingPreference = new Preference(mContext);
        mPreferenceGroup.addPreference(mAudioSharingPreference);
        when(mPreferenceGroup.findPreference(KEY_AUDIO_SHARING_SETTINGS))
                .thenReturn(mAudioSharingPreference);
        when(mScreen.findPreference(KEY)).thenReturn(mPreferenceGroup);
        mController = new AudioSharingDevicePreferenceController(mContext);
        mController.init(mFragment);
@@ -260,7 +253,6 @@ public class AudioSharingDevicePreferenceControllerTest {
        mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
        mController.displayPreference(mScreen);
        assertThat(mPreferenceGroup.isVisible()).isFalse();
        assertThat(mAudioSharingPreference.isVisible()).isFalse();
        verify(mBluetoothDeviceUpdater, never()).forceUpdate();
    }

@@ -269,7 +261,6 @@ public class AudioSharingDevicePreferenceControllerTest {
        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
        mController.displayPreference(mScreen);
        assertThat(mPreferenceGroup.isVisible()).isFalse();
        assertThat(mAudioSharingPreference.isVisible()).isFalse();
        verify(mBluetoothDeviceUpdater).setPrefContext(mContext);
        verify(mBluetoothDeviceUpdater).forceUpdate();
    }
@@ -299,8 +290,7 @@ public class AudioSharingDevicePreferenceControllerTest {
        shadowOf(Looper.getMainLooper()).idle();

        assertThat(mPreferenceGroup.isVisible()).isTrue();
        assertThat(mAudioSharingPreference.isVisible()).isTrue();
        assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(2);
        assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
    }

    @Test
@@ -312,8 +302,7 @@ public class AudioSharingDevicePreferenceControllerTest {
        shadowOf(Looper.getMainLooper()).idle();

        assertThat(mPreferenceGroup.isVisible()).isFalse();
        assertThat(mAudioSharingPreference.isVisible()).isFalse();
        assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
        assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(0);
    }

    @Test
+121 −6
Original line number Diff line number Diff line
@@ -25,8 +25,10 @@ import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_
import static com.google.common.truth.Truth.assertThat;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.robolectric.Shadows.shadowOf;
@@ -77,7 +79,8 @@ import org.robolectric.shadow.api.Shadow;
            ShadowThreadUtils.class
        })
public class AudioSharingPreferenceControllerTest {
    private static final String PREF_KEY = "audio_sharing_settings";
    private static final String PREF_KEY1 = "audio_sharing_settings";
    private static final String PREF_KEY2 = "connected_device_audio_sharing_settings";

    @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();
    @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
@@ -110,9 +113,6 @@ public class AudioSharingPreferenceControllerTest {
        when(localBluetoothManager.getEventManager()).thenReturn(mBtEventManager);
        when(localBluetoothManager.getProfileManager()).thenReturn(mLocalBtProfileManager);
        when(mLocalBtProfileManager.getLeAudioBroadcastProfile()).thenReturn(mBroadcast);
        mController = new AudioSharingPreferenceController(mContext, PREF_KEY);
        mPreference = spy(new Preference(mContext));
        when(mScreen.findPreference(PREF_KEY)).thenReturn(mPreference);
    }

    @After
@@ -124,6 +124,7 @@ public class AudioSharingPreferenceControllerTest {
    @Test
    public void onStart_flagOn_registerCallback() {
        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
        setupControllerWithKey(PREF_KEY1);
        mController.onStart(mLifecycleOwner);
        verify(mBtEventManager).registerCallback(mController);
        verify(mBroadcast).registerServiceCallBack(any(), any(BluetoothLeBroadcast.Callback.class));
@@ -132,6 +133,7 @@ public class AudioSharingPreferenceControllerTest {
    @Test
    public void onStart_flagOff_skipRegisterCallback() {
        mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
        setupControllerWithKey(PREF_KEY1);
        mController.onStart(mLifecycleOwner);
        verify(mBtEventManager, never()).registerCallback(mController);
        verify(mBroadcast, never())
@@ -141,6 +143,7 @@ public class AudioSharingPreferenceControllerTest {
    @Test
    public void onStop_flagOn_unregisterCallback() {
        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
        setupControllerWithKey(PREF_KEY1);
        mController.onStop(mLifecycleOwner);
        verify(mBtEventManager).unregisterCallback(mController);
        verify(mBroadcast).unregisterServiceCallBack(any(BluetoothLeBroadcast.Callback.class));
@@ -149,6 +152,7 @@ public class AudioSharingPreferenceControllerTest {
    @Test
    public void onStop_flagOff_skipUnregisterCallback() {
        mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
        setupControllerWithKey(PREF_KEY1);
        mController.onStop(mLifecycleOwner);
        verify(mBtEventManager, never()).unregisterCallback(mController);
        verify(mBroadcast, never())
@@ -158,65 +162,169 @@ public class AudioSharingPreferenceControllerTest {
    @Test
    public void getAvailabilityStatus_flagOn() {
        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
        setupControllerWithKey(PREF_KEY1);
        assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
    }

    @Test
    public void getAvailabilityStatus_flagOff() {
        mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
        setupControllerWithKey(PREF_KEY1);
        assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
    }

    @Test
    public void getSummary_broadcastOn() {
    public void getSummary_connectionPreference_broadcastOn() {
        when(mBroadcast.isEnabled(any())).thenReturn(true);
        setupControllerWithKey(PREF_KEY1);
        assertThat(mController.getSummary().toString())
                .isEqualTo(mContext.getString(R.string.audio_sharing_summary_on));
    }

    @Test
    public void getSummary_broadcastOff() {
    public void getSummary_connectionPreference_broadcastOff() {
        when(mBroadcast.isEnabled(any())).thenReturn(false);
        setupControllerWithKey(PREF_KEY1);
        assertThat(mController.getSummary().toString())
                .isEqualTo(mContext.getString(R.string.audio_sharing_summary_off));
    }

    @Test
    public void getSummary_connectedDevices_broadcastOn() {
        when(mBroadcast.isEnabled(any())).thenReturn(true);
        setupControllerWithKey(PREF_KEY2);
        assertThat(mController.getSummary().toString()).isEmpty();
    }

    @Test
    public void getSummary_connectedDevices_broadcastOff() {
        when(mBroadcast.isEnabled(any())).thenReturn(false);
        setupControllerWithKey(PREF_KEY2);
        assertThat(mController.getSummary().toString()).isEmpty();
    }

    @Test
    public void onBluetoothStateChanged_refreshSummary() {
        setupControllerWithKey(PREF_KEY1);
        mController.updateState(mPreference);
        mController.displayPreference(mScreen);
        shadowOf(Looper.getMainLooper()).idle();
        assertThat(mPreference.getSummary().toString())
                .isEqualTo(mContext.getString(R.string.audio_sharing_summary_off));
        assertThat(mPreference.isVisible()).isTrue();

        when(mBroadcast.isEnabled(any())).thenReturn(true);
        mController.onBluetoothStateChanged(STATE_ON);
        shadowOf(Looper.getMainLooper()).idle();
        assertThat(mPreference.getSummary().toString())
                .isEqualTo(mContext.getString(R.string.audio_sharing_summary_on));
        assertThat(mPreference.isVisible()).isTrue();

        when(mBroadcast.isEnabled(any())).thenReturn(false);
        mController.onBluetoothStateChanged(STATE_OFF);
        shadowOf(Looper.getMainLooper()).idle();
        assertThat(mPreference.getSummary().toString())
                .isEqualTo(mContext.getString(R.string.audio_sharing_summary_off));
        assertThat(mPreference.isVisible()).isTrue();
    }

    @Test
    public void onBluetoothStateChanged_refreshVisibility() {
        setupControllerWithKey(PREF_KEY2);
        mController.updateState(mPreference);
        mController.displayPreference(mScreen);
        shadowOf(Looper.getMainLooper()).idle();
        assertThat(mPreference.getSummary().toString()).isEmpty();
        assertThat(mPreference.isVisible()).isFalse();

        when(mBroadcast.isEnabled(any())).thenReturn(true);
        mController.onBluetoothStateChanged(STATE_ON);
        shadowOf(Looper.getMainLooper()).idle();
        assertThat(mPreference.getSummary().toString()).isEmpty();
        assertThat(mPreference.isVisible()).isTrue();

        when(mBroadcast.isEnabled(any())).thenReturn(false);
        mController.onBluetoothStateChanged(STATE_OFF);
        shadowOf(Looper.getMainLooper()).idle();
        assertThat(mPreference.getSummary().toString()).isEmpty();
        assertThat(mPreference.isVisible()).isFalse();
    }

    @Test
    public void testBluetoothLeBroadcastCallbacks_refreshSummary() {
        setupControllerWithKey(PREF_KEY1);
        mController.updateState(mPreference);
        mController.displayPreference(mScreen);
        shadowOf(Looper.getMainLooper()).idle();
        assertThat(mPreference.getSummary().toString())
                .isEqualTo(mContext.getString(R.string.audio_sharing_summary_off));
        assertThat(mPreference.isVisible()).isTrue();

        when(mBroadcast.isEnabled(any())).thenReturn(true);
        mController.mBroadcastCallback.onBroadcastStarted(/* reason= */ 1, /* broadcastId= */ 1);
        shadowOf(Looper.getMainLooper()).idle();
        assertThat(mPreference.getSummary().toString())
                .isEqualTo(mContext.getString(R.string.audio_sharing_summary_on));
        assertThat(mPreference.isVisible()).isTrue();

        when(mBroadcast.isEnabled(any())).thenReturn(false);
        mController.mBroadcastCallback.onBroadcastStopped(/* reason= */ 1, /* broadcastId= */ 1);
        shadowOf(Looper.getMainLooper()).idle();
        assertThat(mPreference.getSummary().toString())
                .isEqualTo(mContext.getString(R.string.audio_sharing_summary_off));
        assertThat(mPreference.isVisible()).isTrue();
    }

    @Test
    public void testBluetoothLeBroadcastCallbacks_refreshVisibility() {
        setupControllerWithKey(PREF_KEY2);
        mController.updateState(mPreference);
        mController.displayPreference(mScreen);
        shadowOf(Looper.getMainLooper()).idle();
        assertThat(mPreference.getSummary().toString()).isEmpty();
        assertThat(mPreference.isVisible()).isFalse();

        when(mBroadcast.isEnabled(any())).thenReturn(true);
        mController.mBroadcastCallback.onBroadcastStarted(/* reason= */ 1, /* broadcastId= */ 1);
        shadowOf(Looper.getMainLooper()).idle();
        assertThat(mPreference.getSummary().toString()).isEmpty();
        assertThat(mPreference.isVisible()).isTrue();

        when(mBroadcast.isEnabled(any())).thenReturn(false);
        mController.mBroadcastCallback.onBroadcastStopped(/* reason= */ 1, /* broadcastId= */ 1);
        shadowOf(Looper.getMainLooper()).idle();
        assertThat(mPreference.getSummary().toString()).isEmpty();
        assertThat(mPreference.isVisible()).isFalse();
    }

    @Test
    public void testBluetoothLeBroadcastCallbacks_doNothing() {
        setupControllerWithKey(PREF_KEY1);
        mController.displayPreference(mScreen);
        shadowOf(Looper.getMainLooper()).idle();
        verify(mPreference).setVisible(anyBoolean());

        mController.mBroadcastCallback.onBroadcastMetadataChanged(/* reason= */ 1, mMetadata);
        verify(mPreference, never()).setSummary(any());
        mController.mBroadcastCallback.onBroadcastUpdated(/* reason= */ 1, /* broadcastId= */ 1);
        verify(mPreference, never()).setSummary(any());
        mController.mBroadcastCallback.onPlaybackStarted(/* reason= */ 1, /* broadcastId= */ 1);
        verify(mPreference, never()).setSummary(any());
        mController.mBroadcastCallback.onPlaybackStopped(/* reason= */ 1, /* broadcastId= */ 1);
        verify(mPreference, never()).setSummary(any());
        mController.mBroadcastCallback.onBroadcastStartFailed(/* reason= */ 1);
        verify(mPreference, never()).setSummary(any());
        mController.mBroadcastCallback.onBroadcastStopFailed(/* reason= */ 1);
        verify(mPreference, never()).setSummary(any());
        mController.mBroadcastCallback.onBroadcastUpdateFailed(
                /* reason= */ 1, /* broadcastId= */ 1);
        verify(mPreference, never()).setSummary(any());
        verify(mPreference).setVisible(anyBoolean());

        setupControllerWithKey(PREF_KEY2);
        mController.displayPreference(mScreen);
        shadowOf(Looper.getMainLooper()).idle();
        verify(mPreference, times(3)).setVisible(anyBoolean());

        mController.mBroadcastCallback.onBroadcastMetadataChanged(/* reason= */ 1, mMetadata);
        verify(mPreference, never()).setSummary(any());
@@ -233,5 +341,12 @@ public class AudioSharingPreferenceControllerTest {
        mController.mBroadcastCallback.onBroadcastUpdateFailed(
                /* reason= */ 1, /* broadcastId= */ 1);
        verify(mPreference, never()).setSummary(any());
        verify(mPreference, times(3)).setVisible(anyBoolean());
    }

    private void setupControllerWithKey(String preferenceKey) {
        mController = new AudioSharingPreferenceController(mContext, preferenceKey);
        mPreference = spy(new Preference(mContext));
        when(mScreen.findPreference(preferenceKey)).thenReturn(mPreference);
    }
}