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

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

Merge changes from topic "bass-client-update" into tm-qpr-dev

* changes:
  Add possibility to inject broadcast code while adding broadcast source
  BassClient: Pass current receiver state on first set code check
  BassClient: Handle setting pending broadcast code
  BassClient: Use little endianness instead of big for synced BISes
  BassClient: Send remove source command after stopping  synchronization
  BassClient: Minor adjustments of some logs and comments
parents f5610efd 82ff4047
Loading
Loading
Loading
Loading
+5 −2
Original line number Diff line number Diff line
@@ -186,8 +186,8 @@ public class BassClientService extends ProfileService {
    }

    void setActiveSyncedSource(BluetoothDevice scanDelegator, BluetoothDevice sourceDevice) {
        log("setActiveSyncedSource: scanDelegator" + scanDelegator
                + ":: sourceDevice:" + sourceDevice);
        log("setActiveSyncedSource, scanDelegator: " + scanDelegator + ", sourceDevice: " +
            sourceDevice);
        if (sourceDevice == null) {
            mActiveSourceMap.remove(scanDelegator);
        } else {
@@ -860,8 +860,11 @@ public class BassClientService extends ProfileService {
                    BassClientStateMachine.UPDATE_BCAST_SOURCE);
            message.arg1 = sourceId;
            message.arg2 = BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_IDLE;
            /* Pending remove set. Remove source once not synchronized to PA */
            message.obj = metaData;
            stateMachine.sendMessage(message);

            return;
        }
        Message message = stateMachine.obtainMessage(BassClientStateMachine.REMOVE_BCAST_SOURCE);
        message.arg1 = sourceId;
+84 −29
Original line number Diff line number Diff line
@@ -99,6 +99,7 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -171,6 +172,7 @@ public class BassClientStateMachine extends StateMachine {
    private BluetoothLeBroadcastMetadata mPendingMetadata = null;
    private BluetoothLeBroadcastReceiveState mSetBroadcastPINRcvState = null;
    private boolean mSetBroadcastCodePending = false;
    private final Map<Integer, Boolean> mPendingRemove = new HashMap();
    // Psync and PAST interfaces
    private PeriodicAdvertisingManager mPeriodicAdvManager;
    private boolean mAutoAssist = false;
@@ -243,6 +245,7 @@ public class BassClientStateMachine extends StateMachine {
        mPendingSourceId = -1;
        mPendingMetadata = null;
        mCurrentMetadata.clear();
        mPendingRemove.clear();
    }

    Boolean hasPendingSourceOperation() {
@@ -262,6 +265,18 @@ public class BassClientStateMachine extends StateMachine {
        }
    }

    boolean isPendingRemove(Integer sourceId) {
        return mPendingRemove.getOrDefault(sourceId, false);
    }

    private void setPendingRemove(Integer sourceId, boolean remove) {
        if (remove) {
            mPendingRemove.put(sourceId, remove);
        } else {
            mPendingRemove.remove(sourceId);
        }
    }

    BluetoothLeBroadcastReceiveState getBroadcastReceiveStateForSourceDevice(
            BluetoothDevice srcDevice) {
        List<BluetoothLeBroadcastReceiveState> currentSources = getAllSources();
@@ -350,9 +365,9 @@ public class BassClientStateMachine extends StateMachine {
        mPASyncRetryCounter = 1;
        // Cache Scan res for Retrys
        mScanRes = scanRes;
        /*This is an override case
        if Previous sync is still active, cancel It
        But don't stop the Scan offload as we still trying to assist remote*/
        /*This is an override case if Previous sync is still active, cancel It, but don't stop the
         * Scan offload as we still trying to assist remote
         */
        mNoStopScanOffload = true;
        cancelActiveSync(null);
        try {
@@ -389,16 +404,10 @@ public class BassClientStateMachine extends StateMachine {

    private void cancelActiveSync(BluetoothDevice sourceDev) {
        log("cancelActiveSync");
        boolean isCancelSyncNeeded = false;
        BluetoothDevice activeSyncedSrc = mService.getActiveSyncedSource(mDevice);
        if (activeSyncedSrc != null) {
            if (sourceDev == null) {
                isCancelSyncNeeded = true;
            } else if (activeSyncedSrc.equals(sourceDev)) {
                isCancelSyncNeeded = true;
            }
        }
        if (isCancelSyncNeeded) {

        /* Stop sync if there is some running */
        if (activeSyncedSrc != null && (sourceDev == null || activeSyncedSrc.equals(sourceDev))) {
            removeMessages(PSYNC_ACTIVE_TIMEOUT);
            try {
                log("calling unregisterSync");
@@ -477,11 +486,12 @@ public class BassClientStateMachine extends StateMachine {
                        int skip,
                        int timeout,
                        int status) {
                    log("onSyncEstablished syncHandle" + syncHandle
                            + "device" + device
                            + "advertisingSid" + advertisingSid
                            + "skip" + skip + "timeout" + timeout
                            + "status" + status);
                    log("onSyncEstablished syncHandle: " + syncHandle
                            + ", device: " + device
                            + ", advertisingSid: " + advertisingSid
                            + ", skip: " + skip
                            + ", timeout: " + timeout
                            + ", status: " + status);
                    if (status == BluetoothGatt.GATT_SUCCESS) {
                        // updates syncHandle, advSid
                        mService.updatePeriodicAdvertisementResultMap(
@@ -495,7 +505,7 @@ public class BassClientStateMachine extends StateMachine {
                                BassConstants.PSYNC_ACTIVE_TIMEOUT_MS);
                        mService.setActiveSyncedSource(mDevice, device);
                    } else {
                        log("failed to sync to PA" + mPASyncRetryCounter);
                        log("failed to sync to PA: " + mPASyncRetryCounter);
                        mScanRes = null;
                        if (!mAutoTriggered) {
                            Message message = obtainMessage(STOP_SCAN_OFFLOAD);
@@ -565,7 +575,7 @@ public class BassClientStateMachine extends StateMachine {
                            & (~BassConstants.ADV_ADDRESS_DONT_MATCHES_EXT_ADV_ADDRESS);
                    serviceData = serviceData
                            & (~BassConstants.ADV_ADDRESS_DONT_MATCHES_SOURCE_ADV_ADDRESS);
                    log("Initiate PAST for :" + mDevice + "syncHandle:" +  syncHandle
                    log("Initiate PAST for: " + mDevice + ", syncHandle: " +  syncHandle
                            + "serviceData" + serviceData);
                    mPeriodicAdvManager.transferSync(mDevice, serviceData, syncHandle);
                }
@@ -592,10 +602,17 @@ public class BassClientStateMachine extends StateMachine {
                && mSetBroadcastCodePending) {
            log("Update the Broadcast now");
            Message m = obtainMessage(BassClientStateMachine.SET_BCAST_CODE);

            /* Use cached receiver state if previousely didn't finished setting broadcast code or
             * use current receiver state if this is a first check and update
             */
            if (mSetBroadcastPINRcvState != null) {
                m.obj = mSetBroadcastPINRcvState;
            } else {
                m.obj = recvState;
            }

            sendMessage(m);
            mSetBroadcastCodePending = false;
            mSetBroadcastPINRcvState = null;
        }
    }

@@ -677,10 +694,7 @@ public class BassClientStateMachine extends StateMachine {
                System.arraycopy(receiverState, offset, audioSyncIndex, 0,
                        BassConstants.BCAST_RCVR_STATE_BIS_SYNC_SIZE);
                offset += BassConstants.BCAST_RCVR_STATE_BIS_SYNC_SIZE;
                log("BIS index byte array: ");
                BassUtils.printByteArray(audioSyncIndex);
                ByteBuffer wrapped = ByteBuffer.wrap(audioSyncIndex);
                audioSyncState.add((long) wrapped.getInt());
                audioSyncState.add((long) Utils.byteArrayToInt(audioSyncIndex));

                byte metaDataLength = receiverState[offset++];
                if (metaDataLength > 0) {
@@ -726,6 +740,18 @@ public class BassClientStateMachine extends StateMachine {
                    numSubGroups,
                    audioSyncState,
                    metadataList);
            log("Receiver state: " +
                "\n\tSource ID: " + sourceId +
                "\n\tSource Address Type: " + (int) sourceAddressType +
                "\n\tDevice: " + device +
                "\n\tSource Adv SID: " + sourceAdvSid +
                "\n\tBroadcast ID: " + broadcastId +
                "\n\tMetadata Sync State: " + (int) metaDataSyncState +
                "\n\tEncryption Status: " + (int) encryptionStatus +
                "\n\tBad Broadcast Code: " + badBroadcastCode +
                "\n\tNumber Of Subgroups: " + numSubGroups +
                "\n\tAudio Sync State: " + audioSyncState +
                "\n\tMetadata: " + metadataList);
        }
        return recvState;
    }
@@ -783,6 +809,12 @@ public class BassClientStateMachine extends StateMachine {
                            recvState.getSourceId(), BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST);
                    checkAndUpdateBroadcastCode(recvState);
                    processPASyncState(recvState);

                    if (isPendingRemove(recvState.getSourceId())) {
                        Message message = obtainMessage(REMOVE_BCAST_SOURCE);
                        message.arg1 = recvState.getSourceId();
                        sendMessage(message);
                    }
                }
            }
        }
@@ -998,6 +1030,7 @@ public class BassClientStateMachine extends StateMachine {
        mPendingOperation = -1;
        mPendingMetadata = null;
        mCurrentMetadata.clear();
        mPendingRemove.clear();
    }

    @VisibleForTesting
@@ -1239,6 +1272,16 @@ public class BassClientStateMachine extends StateMachine {
            stream.write(metadata.getRawMetadata(), 0, metadata.getRawMetadata().length);
        }

        if (metaData.isEncrypted() && metaData.getBroadcastCode().length == 16) {
            if (metaData.getBroadcastCode().length != 16) {
                Log.e(TAG, "Delivered invalid length of broadcast code: " +
                      metaData.getBroadcastCode().length + ", should be 16");
                return null;
            }

            mSetBroadcastCodePending = true;
        }

        byte[] res = stream.toByteArray();
        log("ADD_BCAST_SOURCE in Bytes");
        BassUtils.printByteArray(res);
@@ -1508,6 +1551,9 @@ public class BassClientStateMachine extends StateMachine {
                        mBluetoothGatt.writeCharacteristic(mBroadcastScanControlPoint);
                        mPendingOperation = message.what;
                        mPendingSourceId = (byte) sourceId;
                        if (paSync == BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_IDLE) {
                            setPendingRemove(sourceId, true);
                        }
                        mPendingMetadata = metaData;
                        transitionTo(mConnectedProcessing);
                        sendMessageDelayed(GATT_TXN_TIMEOUT, BassConstants.GATT_TXN_TIMEOUT_MS);
@@ -1540,17 +1586,22 @@ public class BassClientStateMachine extends StateMachine {
                            mPendingSourceId = (byte) recvState.getSourceId();
                            transitionTo(mConnectedProcessing);
                            sendMessageDelayed(GATT_TXN_TIMEOUT, BassConstants.GATT_TXN_TIMEOUT_MS);
                            mSetBroadcastCodePending = false;
                            mSetBroadcastPINRcvState = null;
                        }
                    }
                    break;
                case REMOVE_BCAST_SOURCE:
                    byte sid = (byte) message.arg1;
                    log("Removing Broadcast source: audioSource:" + "sourceId:"
                            + sid);
                    log("Removing Broadcast source, sourceId: " + sid);
                    byte[] removeSourceInfo = new byte[2];
                    removeSourceInfo[0] = OPCODE_REMOVE_SOURCE;
                    removeSourceInfo[1] = sid;
                    if (mBluetoothGatt != null && mBroadcastScanControlPoint != null) {
                        if (isPendingRemove((int) sid)) {
                            setPendingRemove((int) sid, false);
                        }

                        mBroadcastScanControlPoint.setValue(removeSourceInfo);
                        mBluetoothGatt.writeCharacteristic(mBroadcastScanControlPoint);
                        mPendingOperation = message.what;
@@ -1645,7 +1696,11 @@ public class BassClientStateMachine extends StateMachine {
        }
        @Override
        public void exit() {
            /* Pending Metadata will be used to bond with source ID in receiver state notify */
            if (mPendingOperation == REMOVE_BCAST_SOURCE) {
                    mPendingMetadata = null;
            }

            log("Exit ConnectedProcessing(" + mDevice + "): "
                    + messageWhatToString(getCurrentMessage().what));
        }
+53 −3
Original line number Diff line number Diff line
@@ -22,9 +22,14 @@ import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothLeBroadcastMetadata;
import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.EditText;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.widget.Toast;

import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.ViewModelProviders;
import androidx.recyclerview.widget.LinearLayoutManager;
@@ -72,9 +77,54 @@ public class BroadcastScanActivity extends AppCompatActivity {

            // Set broadcast source on peer only if scan delegator device context is available
            if (device != null) {
                // Start Dialog with the broadcast input details
                AlertDialog.Builder alert = new AlertDialog.Builder(this);
                LayoutInflater inflater = getLayoutInflater();
                alert.setTitle("Add the Broadcast:");

                View alertView =
                        inflater.inflate(R.layout.broadcast_scan_add_encrypted_source_dialog,
                                         null);
                final EditText code_input_text =
                        alertView.findViewById(R.id.broadcast_code_input);
                BluetoothLeBroadcastMetadata.Builder builder = new
                        BluetoothLeBroadcastMetadata.Builder(broadcast);

                alert.setView(alertView).setNegativeButton("Cancel", (dialog, which) -> {
                    // Do nothing
                }).setPositiveButton("Add", (dialog, which) -> {
                    BluetoothLeBroadcastMetadata metadata;
                    if (code_input_text.getText() == null) {
                        Toast.makeText(recyclerView.getContext(), "Invalid broadcast code",
                                Toast.LENGTH_SHORT).show();
                        return;
                    }
                    if (code_input_text.getText().length() == 0) {
                        Toast.makeText(recyclerView.getContext(), "Adding not encrypted broadcast "
                                       + "source broadcastId="
                                       + broadcastId, Toast.LENGTH_SHORT).show();
                        metadata = builder.setEncrypted(false).build();
                    } else {
                        if (code_input_text.getText().length() != 16) {
                            Toast.makeText(recyclerView.getContext(),
                                           "Invalid Broadcast code length",
                                           Toast.LENGTH_SHORT).show();

                            return;
                        }

                        metadata = builder.setBroadcastCode(
                                        code_input_text.getText().toString().getBytes())
                               .setEncrypted(true)
                               .build();
                    }

                    Toast.makeText(recyclerView.getContext(), "Adding broadcast source"
                                    + " broadcastId=" + broadcastId, Toast.LENGTH_SHORT).show();
                mViewModel.addBroadcastSource(device, broadcast);
                    mViewModel.addBroadcastSource(device, metadata);
                });

                alert.show();
            }
        });
        recyclerView.setAdapter(adapter);
+32 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/broadcast_scan_add_encrypted_source_dialog"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:padding="8dp">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <TextView
            android:id="@+id/textView22"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="Broadcast code:" />

        <EditText
            android:id="@+id/broadcast_code_input"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:ems="10"
            android:gravity="start|top"
            android:maxLength="16"
            android:inputType="textMultiLine|textFilter" />
    </LinearLayout>

</LinearLayout>