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

Commit 44a0b59a authored by chelseahao's avatar chelseahao
Browse files

[Audiosharing] Listen to `onProfileConnectionStateChanged` of...

[Audiosharing] Listen to `onProfileConnectionStateChanged` of LE_AUDIO_BROADCAST_ASSISTANT to be more precise on device connection status upon bluetooth on/off. Also increase test coverage.

Test: atest -c com.android.settings.connecteddevice.audiosharing.audiostreams
Flag: com.android.settingslib.flags.enable_le_audio_qr_code_private_broadcast_sharing
Bug: 345686602
Change-Id: Ia78b1fe19bff3cb179794db1dc09374db13818d8
parent 4b853891
Loading
Loading
Loading
Loading
+15 −14
Original line number Diff line number Diff line
@@ -16,24 +16,22 @@

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

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.text.TextUtils;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.android.settings.R;
import com.android.settings.bluetooth.Utils;
import com.android.settingslib.bluetooth.BluetoothCallback;
import com.android.settingslib.bluetooth.BluetoothUtils;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.utils.ThreadUtils;

public class AudioStreamsActiveDeviceSummaryUpdater implements BluetoothCallback {
    private static final String TAG = "AudioStreamsActiveDeviceSummaryUpdater";
    private static final boolean DEBUG = BluetoothUtils.D;
    private final LocalBluetoothManager mBluetoothManager;
    private Context mContext;
    @Nullable private String mSummary;
@@ -47,17 +45,20 @@ public class AudioStreamsActiveDeviceSummaryUpdater implements BluetoothCallback
    }

    @Override
    public void onActiveDeviceChanged(
            @Nullable CachedBluetoothDevice activeDevice, int bluetoothProfile) {
        if (DEBUG) {
            Log.d(
                    TAG,
                    "onActiveDeviceChanged() with activeDevice : "
                            + (activeDevice == null ? "null" : activeDevice.getAddress())
                            + " on profile : "
                            + bluetoothProfile);
    public void onBluetoothStateChanged(@AdapterState int bluetoothState) {
        if (bluetoothState == BluetoothAdapter.STATE_OFF) {
            notifyChangeIfNeeded();
        }
    }
        if (bluetoothProfile == BluetoothProfile.LE_AUDIO) {

    @Override
    public void onProfileConnectionStateChanged(
            @NonNull CachedBluetoothDevice cachedDevice,
            @ConnectionState int state,
            int bluetoothProfile) {
        if (bluetoothProfile == BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT
                && (state == BluetoothAdapter.STATE_CONNECTED
                        || state == BluetoothAdapter.STATE_DISCONNECTED)) {
            notifyChangeIfNeeded();
        }
    }
+8 −4
Original line number Diff line number Diff line
@@ -16,12 +16,12 @@

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

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.LifecycleOwner;

import com.android.settings.bluetooth.Utils;
@@ -44,9 +44,13 @@ public class AudioStreamsCategoryController extends AudioSharingBasePreferenceCo
    private final BluetoothCallback mBluetoothCallback =
            new BluetoothCallback() {
                @Override
                public void onActiveDeviceChanged(
                        @Nullable CachedBluetoothDevice activeDevice, int bluetoothProfile) {
                    if (bluetoothProfile == BluetoothProfile.LE_AUDIO) {
                public void onProfileConnectionStateChanged(
                        @NonNull CachedBluetoothDevice cachedDevice,
                        @ConnectionState int state,
                        int bluetoothProfile) {
                    if (bluetoothProfile == BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT
                            && (state == BluetoothAdapter.STATE_CONNECTED
                                    || state == BluetoothAdapter.STATE_DISCONNECTED)) {
                        updateVisibility();
                    }
                }
+0 −13
Original line number Diff line number Diff line
@@ -19,7 +19,6 @@ package com.android.settings.connecteddevice.audiosharing.audiostreams;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothLeBroadcastMetadata;
import android.bluetooth.BluetoothLeBroadcastReceiveState;
import android.util.Log;

public class AudioStreamsProgressCategoryCallback extends AudioStreamsBroadcastAssistantCallback {
    private static final String TAG = "AudioStreamsProgressCategoryCallback";
@@ -53,10 +52,6 @@ public class AudioStreamsProgressCategoryCallback extends AudioStreamsBroadcastA
    @Override
    public void onSearchStarted(int reason) {
        super.onSearchStarted(reason);
        if (mCategoryController == null) {
            Log.w(TAG, "onSearchStarted() : mCategoryController is null!");
            return;
        }
        mCategoryController.setScanning(true);
    }

@@ -69,10 +64,6 @@ public class AudioStreamsProgressCategoryCallback extends AudioStreamsBroadcastA
    @Override
    public void onSearchStopped(int reason) {
        super.onSearchStopped(reason);
        if (mCategoryController == null) {
            Log.w(TAG, "onSearchStopped() : mCategoryController is null!");
            return;
        }
        mCategoryController.setScanning(false);
    }

@@ -86,10 +77,6 @@ public class AudioStreamsProgressCategoryCallback extends AudioStreamsBroadcastA
    @Override
    public void onSourceFound(BluetoothLeBroadcastMetadata source) {
        super.onSourceFound(source);
        if (mCategoryController == null) {
            Log.w(TAG, "onSourceFound() : mCategoryController is null!");
            return;
        }
        mCategoryController.handleSourceFound(source);
    }

+8 −3
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

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

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.util.Log;
@@ -47,9 +48,13 @@ public class AudioStreamsScanQrCodeController extends BasePreferenceController
    final BluetoothCallback mBluetoothCallback =
            new BluetoothCallback() {
                @Override
                public void onActiveDeviceChanged(
                        @Nullable CachedBluetoothDevice activeDevice, int bluetoothProfile) {
                    if (bluetoothProfile == BluetoothProfile.LE_AUDIO) {
                public void onProfileConnectionStateChanged(
                        @NonNull CachedBluetoothDevice cachedDevice,
                        @ConnectionState int state,
                        int bluetoothProfile) {
                    if (bluetoothProfile == BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT
                            && (state == BluetoothAdapter.STATE_CONNECTED
                                    || state == BluetoothAdapter.STATE_DISCONNECTED)) {
                        updateVisibility();
                    }
                }
+143 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

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.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.content.Context;

import androidx.preference.Preference;
import androidx.test.core.app.ApplicationProvider;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;

@RunWith(RobolectricTestRunner.class)
public class AudioStreamStateHandlerTest {
    @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();
    private static final int SUMMARY_RES = 1;
    private static final String SUMMARY = "summary";
    private final Context mContext = spy(ApplicationProvider.getApplicationContext());
    @Mock private AudioStreamsProgressCategoryController mController;
    @Mock private AudioStreamsHelper mHelper;
    @Mock private AudioStreamPreference mPreference;
    private AudioStreamStateHandler mHandler;

    @Before
    public void setUp() {
        mHandler = spy(new AudioStreamStateHandler());
    }

    @Test
    public void testHandleStateChange_noChange_doNothing() {
        when(mHandler.getStateEnum())
                .thenReturn(
                        AudioStreamsProgressCategoryController.AudioStreamState
                                .ADD_SOURCE_BAD_CODE);
        when(mPreference.getAudioStreamState())
                .thenReturn(
                        AudioStreamsProgressCategoryController.AudioStreamState
                                .ADD_SOURCE_BAD_CODE);

        mHandler.handleStateChange(mPreference, mController, mHelper);

        verify(mPreference, never()).setAudioStreamState(any());
        verify(mHandler, never()).performAction(any(), any(), any());
        verify(mPreference, never()).setIsConnected(anyBoolean(), anyString(), any());
    }

    @Test
    public void testHandleStateChange_setNewState() {
        when(mHandler.getStateEnum())
                .thenReturn(AudioStreamsProgressCategoryController.AudioStreamState.SOURCE_ADDED);
        when(mPreference.getAudioStreamState())
                .thenReturn(
                        AudioStreamsProgressCategoryController.AudioStreamState
                                .ADD_SOURCE_BAD_CODE);

        mHandler.handleStateChange(mPreference, mController, mHelper);

        verify(mPreference)
                .setAudioStreamState(
                        AudioStreamsProgressCategoryController.AudioStreamState.SOURCE_ADDED);
        verify(mHandler).performAction(any(), any(), any());
        verify(mPreference).setIsConnected(eq(true), eq(""), eq(null));
    }

    @Test
    public void testHandleStateChange_setNewState_newSummary_newListener() {
        Preference.OnPreferenceClickListener listener =
                mock(Preference.OnPreferenceClickListener.class);
        when(mHandler.getStateEnum())
                .thenReturn(
                        AudioStreamsProgressCategoryController.AudioStreamState
                                .ADD_SOURCE_BAD_CODE);
        when(mHandler.getSummary()).thenReturn(SUMMARY_RES);
        when(mHandler.getOnClickListener(any())).thenReturn(listener);
        when(mPreference.getAudioStreamState())
                .thenReturn(
                        AudioStreamsProgressCategoryController.AudioStreamState.ADD_SOURCE_FAILED);
        when(mPreference.getContext()).thenReturn(mContext);
        doReturn(SUMMARY).when(mContext).getString(anyInt());

        mHandler.handleStateChange(mPreference, mController, mHelper);

        verify(mPreference)
                .setAudioStreamState(
                        AudioStreamsProgressCategoryController.AudioStreamState
                                .ADD_SOURCE_BAD_CODE);
        verify(mHandler).performAction(any(), any(), any());
        verify(mPreference).setIsConnected(eq(false), eq(SUMMARY), eq(listener));
    }

    @Test
    public void testGetSummary() {
        int res = mHandler.getSummary();
        assertThat(res).isEqualTo(AudioStreamStateHandler.EMPTY_STRING_RES);
    }

    @Test
    public void testGetOnClickListener() {
        Preference.OnPreferenceClickListener listener = mHandler.getOnClickListener(mController);
        assertThat(listener).isNull();
    }

    @Test
    public void testGetStateEnum() {
        var state = mHandler.getStateEnum();
        assertThat(state)
                .isEqualTo(AudioStreamsProgressCategoryController.AudioStreamState.UNKNOWN);
    }
}
Loading