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

Commit f647356d authored by Chelsea Hao's avatar Chelsea Hao Committed by Android (Google) Code Review
Browse files

Merge "[Audiosharing] Increase test coverage." into main

parents af053aa3 7529e1be
Loading
Loading
Loading
Loading
+10 −3
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import android.view.View;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.lifecycle.DefaultLifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
import androidx.preference.PreferenceScreen;
@@ -48,7 +49,9 @@ public class AudioStreamButtonController extends BasePreferenceController
    private static final String TAG = "AudioStreamButtonController";
    private static final String KEY = "audio_stream_button";
    private static final int SOURCE_ORIGIN_REPOSITORY = SourceOriginForLogging.REPOSITORY.ordinal();
    private final BluetoothLeBroadcastAssistant.Callback mBroadcastAssistantCallback =

    @VisibleForTesting
    final BluetoothLeBroadcastAssistant.Callback mBroadcastAssistantCallback =
            new AudioStreamsBroadcastAssistantCallback() {
                @Override
                public void onSourceRemoved(BluetoothDevice sink, int sourceId, int reason) {
@@ -97,8 +100,7 @@ public class AudioStreamButtonController extends BasePreferenceController
                }
            };

    private final AudioStreamsRepository mAudioStreamsRepository =
            AudioStreamsRepository.getInstance();
    private AudioStreamsRepository mAudioStreamsRepository = AudioStreamsRepository.getInstance();
    private final Executor mExecutor;
    private final AudioStreamsHelper mAudioStreamsHelper;
    private final @Nullable LocalBluetoothLeBroadcastAssistant mLeBroadcastAssistant;
@@ -228,4 +230,9 @@ public class AudioStreamButtonController extends BasePreferenceController
    void init(int broadcastId) {
        mBroadcastId = broadcastId;
    }

    @VisibleForTesting
    void setAudioStreamsRepositoryForTesting(AudioStreamsRepository repository) {
        mAudioStreamsRepository = repository;
    }
}
+6 −2
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ import android.text.TextUtils;
import android.util.Log;

import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;

import com.android.settings.R;
import com.android.settings.bluetooth.Utils;
@@ -43,9 +44,12 @@ import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;

public class AudioStreamConfirmDialog extends InstrumentedDialogFragment {
    private static final String TAG = "AudioStreamConfirmDialog";
    private static final int DEFAULT_DEVICE_NAME = R.string.audio_streams_dialog_default_device;

    @VisibleForTesting
    static final int DEFAULT_DEVICE_NAME = R.string.audio_streams_dialog_default_device;

    private Context mContext;
    @Nullable private Activity mActivity;
    @VisibleForTesting @Nullable Activity mActivity;
    @Nullable private BluetoothLeBroadcastMetadata mBroadcastMetadata;
    @Nullable private BluetoothDevice mConnectedDevice;
    private int mAudioStreamConfirmDialogId = SettingsEnums.PAGE_UNKNOWN;
+3 −1
Original line number Diff line number Diff line
@@ -54,7 +54,9 @@ public class AudioStreamHeaderController extends BasePreferenceController
    private final Executor mExecutor;
    private final AudioStreamsHelper mAudioStreamsHelper;
    @Nullable private final LocalBluetoothLeBroadcastAssistant mLeBroadcastAssistant;
    private final BluetoothLeBroadcastAssistant.Callback mBroadcastAssistantCallback =

    @VisibleForTesting
    final BluetoothLeBroadcastAssistant.Callback mBroadcastAssistantCallback =
            new AudioStreamsBroadcastAssistantCallback() {
                @Override
                public void onSourceRemoved(BluetoothDevice sink, int sourceId, int reason) {
+0 −11
Original line number Diff line number Diff line
@@ -23,7 +23,6 @@ import android.app.settings.SettingsEnums;
import android.bluetooth.BluetoothLeBroadcastMetadata;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;

import androidx.annotation.Nullable;
@@ -63,11 +62,6 @@ public class AudioStreamsDashboardFragment extends DashboardFragment {
        return R.xml.bluetooth_le_audio_streams;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
@@ -91,11 +85,6 @@ public class AudioStreamsDashboardFragment extends DashboardFragment {
        }
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
+177 −2
Original line number Diff line number Diff line
@@ -16,22 +16,36 @@

package com.android.settings.connecteddevice.audiosharing.audiostreams;

import static com.google.common.truth.Truth.assertThat;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.app.settings.SettingsEnums;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothLeBroadcastAssistant;
import android.bluetooth.BluetoothLeBroadcastMetadata;
import android.bluetooth.BluetoothLeBroadcastReceiveState;
import android.content.Context;
import android.view.View;

import androidx.lifecycle.LifecycleOwner;
import androidx.preference.PreferenceScreen;
import androidx.test.core.app.ApplicationProvider;

import com.android.settings.R;
import com.android.settings.connecteddevice.audiosharing.audiostreams.testshadows.ShadowAudioStreamsHelper;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.shadow.ShadowThreadUtils;
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.widget.ActionButtonsPreference;

import org.junit.After;
@@ -39,14 +53,17 @@ import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Executor;

@RunWith(RobolectricTestRunner.class)
@Config(
@@ -63,14 +80,23 @@ public class AudioStreamButtonControllerTest {
    @Mock private AudioStreamsHelper mAudioStreamsHelper;
    @Mock private PreferenceScreen mScreen;
    @Mock private BluetoothLeBroadcastReceiveState mBroadcastReceiveState;
    @Mock private LocalBluetoothLeBroadcastAssistant mAssistant;
    @Mock private AudioStreamsRepository mRepository;
    @Mock private ActionButtonsPreference mPreference;
    private Lifecycle mLifecycle;
    private LifecycleOwner mLifecycleOwner;
    private FakeFeatureFactory mFeatureFactory;
    private AudioStreamButtonController mController;

    @Before
    public void setUp() {
        ShadowAudioStreamsHelper.setUseMock(mAudioStreamsHelper);
        when(mAudioStreamsHelper.getLeBroadcastAssistant()).thenReturn(mAssistant);
        mFeatureFactory = FakeFeatureFactory.setupForTest();
        mController = new AudioStreamButtonController(mContext, KEY);
        mController.init(BROADCAST_ID);
        mLifecycleOwner = () -> mLifecycle;
        mLifecycle = new Lifecycle(mLifecycleOwner);
        when(mScreen.findPreference(KEY)).thenReturn(mPreference);
        when(mPreference.getContext()).thenReturn(mContext);
        when(mPreference.setButton1Text(anyInt())).thenReturn(mPreference);
@@ -85,6 +111,40 @@ public class AudioStreamButtonControllerTest {
        ShadowAudioStreamsHelper.reset();
    }

    @Test
    public void onStart_registerCallbacks() {
        mController.onStart(mLifecycleOwner);
        verify(mAssistant)
                .registerServiceCallBack(
                        any(Executor.class), any(BluetoothLeBroadcastAssistant.Callback.class));
    }

    @Test
    public void onStart_profileNull_doNothing() {
        when(mAudioStreamsHelper.getLeBroadcastAssistant()).thenReturn(null);
        mController = new AudioStreamButtonController(mContext, KEY);
        mController.onStart(mLifecycleOwner);
        verify(mAssistant, never())
                .registerServiceCallBack(
                        any(Executor.class), any(BluetoothLeBroadcastAssistant.Callback.class));
    }

    @Test
    public void onStop_unregisterCallbacks() {
        mController.onStop(mLifecycleOwner);
        verify(mAssistant)
                .unregisterServiceCallBack(any(BluetoothLeBroadcastAssistant.Callback.class));
    }

    @Test
    public void onStop_profileNull_doNothing() {
        when(mAudioStreamsHelper.getLeBroadcastAssistant()).thenReturn(null);
        mController = new AudioStreamButtonController(mContext, KEY);
        mController.onStop(mLifecycleOwner);
        verify(mAssistant, never())
                .unregisterServiceCallBack(any(BluetoothLeBroadcastAssistant.Callback.class));
    }

    @Test
    public void testDisplayPreference_sourceConnected_setDisconnectButton() {
        when(mAudioStreamsHelper.getAllConnectedSources())
@@ -96,18 +156,133 @@ public class AudioStreamButtonControllerTest {
        verify(mPreference).setButton1Enabled(true);
        verify(mPreference).setButton1Text(R.string.audio_streams_disconnect);
        verify(mPreference).setButton1Icon(com.android.settings.R.drawable.ic_settings_close);
        verify(mPreference).setButton1OnClickListener(any(View.OnClickListener.class));

        ArgumentCaptor<View.OnClickListener> listenerCaptor =
                ArgumentCaptor.forClass(View.OnClickListener.class);
        verify(mPreference).setButton1OnClickListener(listenerCaptor.capture());
        var listener = listenerCaptor.getValue();

        assertThat(listener).isNotNull();
        listener.onClick(mock(View.class));
        verify(mAudioStreamsHelper).removeSource(BROADCAST_ID);
        verify(mPreference).setButton1Enabled(false);
        verify(mFeatureFactory.metricsFeatureProvider)
                .action(any(), eq(SettingsEnums.ACTION_AUDIO_STREAM_LEAVE_BUTTON_CLICK));
    }

    @Test
    public void testDisplayPreference_sourceNotConnected_setConnectButton() {
        when(mAudioStreamsHelper.getAllConnectedSources()).thenReturn(Collections.emptyList());
        mController.setAudioStreamsRepositoryForTesting(mRepository);
        var metadataToRejoin = mock(BluetoothLeBroadcastMetadata.class);
        when(mRepository.getSavedMetadata(any(), anyInt())).thenReturn(metadataToRejoin);

        mController.displayPreference(mScreen);

        verify(mPreference).setButton1Enabled(true);
        verify(mPreference).setButton1Text(R.string.audio_streams_connect);
        verify(mPreference).setButton1Icon(com.android.settings.R.drawable.ic_add_24dp);
        verify(mPreference).setButton1OnClickListener(any(View.OnClickListener.class));

        ArgumentCaptor<View.OnClickListener> listenerCaptor =
                ArgumentCaptor.forClass(View.OnClickListener.class);
        verify(mPreference).setButton1OnClickListener(listenerCaptor.capture());
        var listener = listenerCaptor.getValue();

        assertThat(listener).isNotNull();
        listener.onClick(mock(View.class));
        verify(mAudioStreamsHelper).addSource(metadataToRejoin);
        verify(mPreference).setButton1Enabled(false);
        verify(mFeatureFactory.metricsFeatureProvider)
                .action(any(), eq(SettingsEnums.ACTION_AUDIO_STREAM_JOIN), anyInt());
    }

    @Test
    public void testCallback_onSourceRemoved_updateButton() {
        when(mAudioStreamsHelper.getAllConnectedSources()).thenReturn(Collections.emptyList());

        mController.displayPreference(mScreen);
        mController.mBroadcastAssistantCallback.onSourceRemoved(
                mock(BluetoothDevice.class), /* sourceId= */ 0, /* reason= */ 0);

        // Called twice, once in displayPreference, the other one in callback
        verify(mPreference, times(2)).setButton1Enabled(true);
        verify(mPreference, times(2)).setButton1Text(R.string.audio_streams_connect);
        verify(mPreference, times(2)).setButton1Icon(com.android.settings.R.drawable.ic_add_24dp);
    }

    @Test
    public void testCallback_onSourceRemovedFailed_updateButton() {
        when(mAudioStreamsHelper.getAllConnectedSources())
                .thenReturn(List.of(mBroadcastReceiveState));
        when(mBroadcastReceiveState.getBroadcastId()).thenReturn(BROADCAST_ID);

        mController.displayPreference(mScreen);
        mController.mBroadcastAssistantCallback.onSourceRemoveFailed(
                mock(BluetoothDevice.class), /* sourceId= */ 0, /* reason= */ 0);

        verify(mFeatureFactory.metricsFeatureProvider)
                .action(any(), eq(SettingsEnums.ACTION_AUDIO_STREAM_LEAVE_FAILED));

        // Called twice, once in displayPreference, the other one in callback
        verify(mPreference, times(2)).setButton1Enabled(true);
        verify(mPreference, times(2)).setButton1Text(R.string.audio_streams_disconnect);
        verify(mPreference, times(2))
                .setButton1Icon(com.android.settings.R.drawable.ic_settings_close);
    }

    @Test
    public void testCallback_onReceiveStateChanged_updateButton() {
        when(mAudioStreamsHelper.getAllConnectedSources())
                .thenReturn(List.of(mBroadcastReceiveState));
        when(mBroadcastReceiveState.getBroadcastId()).thenReturn(BROADCAST_ID);
        BluetoothLeBroadcastReceiveState state = mock(BluetoothLeBroadcastReceiveState.class);
        List<Long> bisSyncState = new ArrayList<>();
        bisSyncState.add(1L);
        when(state.getBisSyncState()).thenReturn(bisSyncState);

        mController.displayPreference(mScreen);
        mController.mBroadcastAssistantCallback.onReceiveStateChanged(
                mock(BluetoothDevice.class), /* sourceId= */ 0, state);

        verify(mFeatureFactory.metricsFeatureProvider)
                .action(any(), eq(SettingsEnums.ACTION_AUDIO_STREAM_JOIN_SUCCEED), anyInt());

        // Called twice, once in displayPreference, the other one in callback
        verify(mPreference, times(2)).setButton1Enabled(true);
        verify(mPreference, times(2)).setButton1Text(R.string.audio_streams_disconnect);
        verify(mPreference, times(2))
                .setButton1Icon(com.android.settings.R.drawable.ic_settings_close);
    }

    @Test
    public void testCallback_onSourceAddFailed_updateButton() {
        when(mAudioStreamsHelper.getAllConnectedSources()).thenReturn(Collections.emptyList());

        mController.displayPreference(mScreen);
        mController.mBroadcastAssistantCallback.onSourceAddFailed(
                mock(BluetoothDevice.class),
                mock(BluetoothLeBroadcastMetadata.class),
                /* reason= */ 0);

        verify(mFeatureFactory.metricsFeatureProvider)
                .action(any(), eq(SettingsEnums.ACTION_AUDIO_STREAM_JOIN_FAILED_OTHER), anyInt());

        // Called twice, once in displayPreference, the other one in callback
        verify(mPreference, times(2)).setButton1Enabled(true);
        verify(mPreference, times(2)).setButton1Text(R.string.audio_streams_connect);
        verify(mPreference, times(2)).setButton1Icon(com.android.settings.R.drawable.ic_add_24dp);
    }

    @Test
    public void testCallback_onSourceLost_updateButton() {
        when(mAudioStreamsHelper.getAllConnectedSources()).thenReturn(Collections.emptyList());

        mController.displayPreference(mScreen);
        mController.mBroadcastAssistantCallback.onSourceLost(/* broadcastId= */ 0);

        // Called twice, once in displayPreference, the other one in callback
        verify(mPreference, times(2)).setButton1Enabled(true);
        verify(mPreference, times(2)).setButton1Text(R.string.audio_streams_connect);
        verify(mPreference, times(2)).setButton1Icon(com.android.settings.R.drawable.ic_add_24dp);
    }
}
Loading