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

Commit eba6276a authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "To preserve active sync, restart scan after add source completion." into main

parents 3ceee5be 04d37598
Loading
Loading
Loading
Loading
+53 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 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.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamsProgressCategoryController.AudioStreamState.ADD_SOURCE_WAIT_FOR_RESPONSE_FROM_QR;

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

import com.android.settingslib.flags.Flags;

class AddSourceWaitForResponseFromQrState extends AddSourceWaitForResponseState {
    @Nullable
    private static AddSourceWaitForResponseFromQrState sInstance = null;

    @VisibleForTesting
    AddSourceWaitForResponseFromQrState() {
    }

    static AddSourceWaitForResponseFromQrState getInstance() {
        if (sInstance == null) {
            sInstance = new AddSourceWaitForResponseFromQrState();
        }
        return sInstance;
    }

    @Override
    void onExit(AudioStreamScanHelper scanHelper,
            AudioStreamsProgressCategoryController.AudioStreamState newState) {
        if (Flags.audioStreamScanWithFilter()) {
            scanHelper.restartScanningWithoutFilter();
        }
    }

    @Override
    AudioStreamsProgressCategoryController.AudioStreamState getStateEnum() {
        return ADD_SOURCE_WAIT_FOR_RESPONSE_FROM_QR;
    }
}
+4 −2
Original line number Diff line number Diff line
@@ -70,7 +70,7 @@ class AudioStreamStateHandler {
                            + newState);
        }
        if (prevStateHandler != null) {
            prevStateHandler.onExit(scanHelper);
            prevStateHandler.onExit(scanHelper, newState);
        }

        preference.setAudioStreamState(newState);
@@ -129,7 +129,9 @@ class AudioStreamStateHandler {
    /**
     * Perform action when exiting one state.
     */
    void onExit(AudioStreamScanHelper scanHelper) {}
    void onExit(AudioStreamScanHelper scanHelper,
            AudioStreamsProgressCategoryController.AudioStreamState newState) {
    }

    /**
     * The preference summary for the audio stream state (e.g, Scanning...) This method is intended
+7 −2
Original line number Diff line number Diff line
@@ -132,6 +132,8 @@ public class AudioStreamsProgressCategoryController extends BasePreferenceContro
        SYNCED,
        // When addSource is called for this source and waiting for response.
        ADD_SOURCE_WAIT_FOR_RESPONSE,
        // When addSource is called for this source and waiting for response from a QR code scan.
        ADD_SOURCE_WAIT_FOR_RESPONSE_FROM_QR,
        // When addSource result in a bad code response.
        ADD_SOURCE_BAD_CODE,
        // When addSource result in other bad state.
@@ -238,7 +240,7 @@ public class AudioStreamsProgressCategoryController extends BasePreferenceContro
    // Find preference by scanned source and decide next state.
    // Expect one of the following:
    // 1) No preference existed, create new preference with state SYNCED
    // 2) WAIT_FOR_SYNC, move to ADD_SOURCE_WAIT_FOR_RESPONSE
    // 2) WAIT_FOR_SYNC, move to ADD_SOURCE_WAIT_FOR_RESPONSE_FROM_QR
    // 3) SOURCE_ADDED, leave as-is
    @Override
    public void handleSourceFound(@NonNull BluetoothLeBroadcastMetadata source) {
@@ -284,7 +286,8 @@ public class AudioStreamsProgressCategoryController extends BasePreferenceContro
                                        .setBroadcastCode(mSourceFromQrCode.getBroadcastCode())
                                        .build());
                        moveToState(
                                existingPreference, AudioStreamState.ADD_SOURCE_WAIT_FOR_RESPONSE);
                                existingPreference,
                                AudioStreamState.ADD_SOURCE_WAIT_FOR_RESPONSE_FROM_QR);
                    } else {
                        // A preference with source founded existed either because it's already
                        // connected (SOURCE_ADDED) or present (SOURCE_PRESENT). Any other reason
@@ -760,6 +763,8 @@ public class AudioStreamsProgressCategoryController extends BasePreferenceContro
            case SYNCED -> SyncedState.getInstance();
            case WAIT_FOR_SYNC -> WaitForSyncState.getInstance();
            case ADD_SOURCE_WAIT_FOR_RESPONSE -> AddSourceWaitForResponseState.getInstance();
            case ADD_SOURCE_WAIT_FOR_RESPONSE_FROM_QR ->
                    AddSourceWaitForResponseFromQrState.getInstance();
            case ADD_SOURCE_BAD_CODE -> AddSourceBadCodeState.getInstance();
            case ADD_SOURCE_FAILED -> AddSourceFailedState.getInstance();
            case SOURCE_PRESENT -> SourcePresentState.getInstance();
+11 −2
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

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

import static com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamsProgressCategoryController.AudioStreamState.ADD_SOURCE_WAIT_FOR_RESPONSE_FROM_QR;
import static com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamsScanQrCodeController.REQUEST_SCAN_BT_BROADCAST_QR_CODE;

import android.app.settings.SettingsEnums;
@@ -87,8 +88,16 @@ class WaitForSyncState extends AudioStreamStateHandler {
    }

    @Override
    void onExit(AudioStreamScanHelper scanHelper) {
        if (Flags.audioStreamScanWithFilter()) {
    void onExit(AudioStreamScanHelper scanHelper,
            AudioStreamsProgressCategoryController.AudioStreamState newState) {
        // If the new state indicates that we're in the process of adding source
        // (ADD_SOURCE_WAIT_FOR_RESPONSE_FROM_QR), we will not stop and restart scanning here,
        // instead, we will wait until the add source operation's completion. This is to preserve
        // the sync link which is needed for the add source operation, as bluetooth stack clears
        // active syncs when stopping scanning. If we're moving to other states, we can safely stop
        // and restart scanning.
        if (Flags.audioStreamScanWithFilter() && !newState.equals(
                ADD_SOURCE_WAIT_FOR_RESPONSE_FROM_QR)) {
            scanHelper.restartScanningWithoutFilter();
        }
    }
+81 −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.Mockito.spy;
import static org.mockito.Mockito.verify;

import android.content.Context;
import android.platform.test.flag.junit.SetFlagsRule;

import androidx.test.core.app.ApplicationProvider;

import com.android.settingslib.flags.Flags;

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 AddSourceWaitForResponseFromQrStateTest {
    @Rule
    public final MockitoRule mMockitoRule = MockitoJUnit.rule();
    @Rule
    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
    private final Context mContext = spy(ApplicationProvider.getApplicationContext());
    @Mock
    private AudioStreamScanHelper mScanHelper;
    private AddSourceWaitForResponseFromQrState mInstance;

    @Before
    public void setUp() {
        mInstance = new AddSourceWaitForResponseFromQrState();
    }

    @Test
    public void testGetInstance() {
        mInstance = AddSourceWaitForResponseFromQrState.getInstance();
        assertThat(mInstance).isNotNull();
        assertThat(mInstance).isInstanceOf(AudioStreamStateHandler.class);
    }

    @Test
    public void testGetStateEnum() {
        AudioStreamsProgressCategoryController.AudioStreamState stateEnum =
                mInstance.getStateEnum();
        assertThat(stateEnum)
                .isEqualTo(
                        AudioStreamsProgressCategoryController.AudioStreamState
                                .ADD_SOURCE_WAIT_FOR_RESPONSE_FROM_QR);
    }

    @Test
    public void testOnExit_restartScanWithoutFilter() {
        mSetFlagsRule.enableFlags(Flags.FLAG_AUDIO_STREAM_SCAN_WITH_FILTER);
        mInstance.onExit(mScanHelper,
                AudioStreamsProgressCategoryController.AudioStreamState.SYNCED);

        verify(mScanHelper).restartScanningWithoutFilter();
    }
}
Loading