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

Commit 03fc3c9b authored by Treehugger Robot's avatar Treehugger Robot Committed by Automerger Merge Worker
Browse files

Merge "TbsService: merge "start" into constructor" into main am: 69dcde5b am: 7a43185b

parents e80d9a6c 7a43185b
Loading
Loading
Loading
Loading
+47 −76
Original line number Diff line number Diff line
@@ -19,6 +19,8 @@ package com.android.bluetooth.tbs;

import static android.bluetooth.BluetoothDevice.METADATA_GTBS_CCCD;

import static java.util.Objects.requireNonNull;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
@@ -27,7 +29,6 @@ import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattServerCallback;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
@@ -48,12 +49,10 @@ import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;

public class TbsGatt {

    private static final String TAG = "TbsGatt";
    private static final String TAG = TbsGatt.class.getSimpleName();

    private static final String UUID_PREFIX = "0000";
    private static final String UUID_SUFFIX = "-0000-1000-8000-00805f9b34fb";
@@ -66,51 +65,50 @@ public class TbsGatt {
    @VisibleForTesting static final UUID UUID_BEARER_TECHNOLOGY = makeUuid("2BB5");
    @VisibleForTesting static final UUID UUID_BEARER_URI_SCHEMES_SUPPORTED_LIST = makeUuid("2BB6");
    @VisibleForTesting static final UUID UUID_BEARER_LIST_CURRENT_CALLS = makeUuid("2BB9");
    @VisibleForTesting static final UUID UUID_CONTENT_CONTROL_ID = makeUuid("2BBA");
    private static final UUID UUID_CONTENT_CONTROL_ID = makeUuid("2BBA");
    @VisibleForTesting static final UUID UUID_STATUS_FLAGS = makeUuid("2BBB");
    @VisibleForTesting static final UUID UUID_CALL_STATE = makeUuid("2BBD");
    @VisibleForTesting static final UUID UUID_CALL_CONTROL_POINT = makeUuid("2BBE");

    @VisibleForTesting
    static final UUID UUID_CALL_CONTROL_POINT_OPTIONAL_OPCODES = makeUuid("2BBF");

    private static final UUID UUID_CALL_CONTROL_POINT_OPTIONAL_OPCODES = makeUuid("2BBF");
    @VisibleForTesting static final UUID UUID_TERMINATION_REASON = makeUuid("2BC0");
    @VisibleForTesting static final UUID UUID_INCOMING_CALL = makeUuid("2BC1");
    @VisibleForTesting static final UUID UUID_CALL_FRIENDLY_NAME = makeUuid("2BC2");

    @VisibleForTesting
    static final UUID UUID_CLIENT_CHARACTERISTIC_CONFIGURATION = makeUuid("2902");

    @VisibleForTesting static final int STATUS_FLAG_INBAND_RINGTONE_ENABLED = 0x0001;
    @VisibleForTesting static final int STATUS_FLAG_SILENT_MODE_ENABLED = 0x0002;

    @VisibleForTesting static final int CALL_CONTROL_POINT_OPTIONAL_OPCODE_LOCAL_HOLD = 0x0001;
    @VisibleForTesting static final int CALL_CONTROL_POINT_OPTIONAL_OPCODE_JOIN = 0x0002;

    @VisibleForTesting public static final int CALL_CONTROL_POINT_OPCODE_ACCEPT = 0x00;
    @VisibleForTesting public static final int CALL_CONTROL_POINT_OPCODE_TERMINATE = 0x01;
    @VisibleForTesting public static final int CALL_CONTROL_POINT_OPCODE_LOCAL_HOLD = 0x02;
    @VisibleForTesting public static final int CALL_CONTROL_POINT_OPCODE_LOCAL_RETRIEVE = 0x03;
    @VisibleForTesting public static final int CALL_CONTROL_POINT_OPCODE_ORIGINATE = 0x04;
    @VisibleForTesting public static final int CALL_CONTROL_POINT_OPCODE_JOIN = 0x05;
    private static final int CALL_CONTROL_POINT_OPTIONAL_OPCODE_LOCAL_HOLD = 0x0001;
    private static final int CALL_CONTROL_POINT_OPTIONAL_OPCODE_JOIN = 0x0002;

    @VisibleForTesting public static final int CALL_CONTROL_POINT_RESULT_SUCCESS = 0x00;
    static final int CALL_CONTROL_POINT_OPCODE_ACCEPT = 0x00;
    static final int CALL_CONTROL_POINT_OPCODE_TERMINATE = 0x01;
    static final int CALL_CONTROL_POINT_OPCODE_LOCAL_HOLD = 0x02;
    static final int CALL_CONTROL_POINT_OPCODE_LOCAL_RETRIEVE = 0x03;
    static final int CALL_CONTROL_POINT_OPCODE_ORIGINATE = 0x04;
    static final int CALL_CONTROL_POINT_OPCODE_JOIN = 0x05;

    @VisibleForTesting
    public static final int CALL_CONTROL_POINT_RESULT_OPCODE_NOT_SUPPORTED = 0x01;
    static final int CALL_CONTROL_POINT_RESULT_SUCCESS = 0x00;
    static final int CALL_CONTROL_POINT_RESULT_OPCODE_NOT_SUPPORTED = 0x01;
    static final int CALL_CONTROL_POINT_RESULT_OPERATION_NOT_POSSIBLE = 0x02;
    static final int CALL_CONTROL_POINT_RESULT_INVALID_CALL_INDEX = 0x03;
    static final int CALL_CONTROL_POINT_RESULT_STATE_MISMATCH = 0x04;
    static final int CALL_CONTROL_POINT_RESULT_INVALID_OUTGOING_URI = 0x06;

    @VisibleForTesting
    public static final int CALL_CONTROL_POINT_RESULT_OPERATION_NOT_POSSIBLE = 0x02;
    private final Object mPendingGattOperationsLock = new Object();
    private final Map<BluetoothDevice, Integer> mStatusFlagValue = new HashMap<>();

    @VisibleForTesting public static final int CALL_CONTROL_POINT_RESULT_INVALID_CALL_INDEX = 0x03;
    @VisibleForTesting public static final int CALL_CONTROL_POINT_RESULT_STATE_MISMATCH = 0x04;
    @VisibleForTesting public static final int CALL_CONTROL_POINT_RESULT_LACK_OF_RESOURCES = 0x05;
    @GuardedBy("mPendingGattOperationsLock")
    private final Map<BluetoothDevice, List<GattOpContext>> mPendingGattOperations =
            new HashMap<>();

    @VisibleForTesting
    public static final int CALL_CONTROL_POINT_RESULT_INVALID_OUTGOING_URI = 0x06;
    private final Map<BluetoothDevice, HashMap<UUID, Short>> mCccDescriptorValues = new HashMap<>();

    private final Object mPendingGattOperationsLock = new Object();
    private final Context mContext;
    private final AdapterService mAdapterService;
    private final TbsService mTbsService;
    private final Handler mHandler;
    private final BluetoothGattServerProxy mBluetoothGattServer;
    private final GattCharacteristic mBearerProviderNameCharacteristic;
    private final GattCharacteristic mBearerUciCharacteristic;
    private final GattCharacteristic mBearerTechnologyCharacteristic;
@@ -124,18 +122,10 @@ public class TbsGatt {
    private final GattCharacteristic mTerminationReasonCharacteristic;
    private final GattCharacteristic mIncomingCallCharacteristic;
    private final GattCharacteristic mCallFriendlyNameCharacteristic;
    private boolean mSilentMode = false;
    private Map<BluetoothDevice, Integer> mStatusFlagValue = new HashMap<>();

    @GuardedBy("mPendingGattOperationsLock")
    private Map<BluetoothDevice, List<GattOpContext>> mPendingGattOperations = new HashMap<>();

    private BluetoothGattServerProxy mBluetoothGattServer;
    private Handler mHandler;
    private Callback mCallback;
    private AdapterService mAdapterService;
    private HashMap<BluetoothDevice, HashMap<UUID, Short>> mCccDescriptorValues;
    private TbsService mTbsService;

    private boolean mSilentMode = false;

    private static final int LOG_NB_EVENTS = 200;
    private BluetoothEventLogger mEventLogger = null;
@@ -242,12 +232,19 @@ public class TbsGatt {
        public byte[] mValue;
    }

    TbsGatt(TbsService tbsService) {
        mContext = tbsService;
        mAdapterService =
                Objects.requireNonNull(
                        AdapterService.getAdapterService(),
                        "AdapterService shouldn't be null when creating TbsGatt");
    TbsGatt(AdapterService adapterService, TbsService tbsService) {
        this(adapterService, tbsService, new BluetoothGattServerProxy(adapterService));
    }

    @VisibleForTesting
    TbsGatt(
            AdapterService adapterService,
            TbsService tbsService,
            BluetoothGattServerProxy gattServerProxy) {
        mTbsService = requireNonNull(tbsService);
        mAdapterService = requireNonNull(adapterService);
        mBluetoothGattServer = requireNonNull(gattServerProxy);
        mHandler = new Handler(Looper.getMainLooper());

        mBearerProviderNameCharacteristic =
                new GattCharacteristic(
@@ -317,13 +314,6 @@ public class TbsGatt {
                                | BluetoothGattCharacteristic.PROPERTY_NOTIFY,
                        BluetoothGattCharacteristic.PERMISSION_READ_ENCRYPTED);

        mTbsService = tbsService;
        mBluetoothGattServer = null;
    }

    @VisibleForTesting
    void setBluetoothGattServerForTesting(BluetoothGattServerProxy proxy) {
        mBluetoothGattServer = proxy;
    }

    public boolean init(
@@ -335,7 +325,6 @@ public class TbsGatt {
            String providerName,
            int technology,
            Callback callback) {
        mCccDescriptorValues = new HashMap<>();
        mBearerProviderNameCharacteristic.setValue(providerName);
        mBearerTechnologyCharacteristic.setValue(new byte[] {(byte) (technology & 0xFF)});
        mBearerUciCharacteristic.setValue(uci);
@@ -344,11 +333,6 @@ public class TbsGatt {
        setCallControlPointOptionalOpcodes(isLocalHoldOpcodeSupported, isJoinOpcodeSupported);
        mStatusFlagsCharacteristic.setValue(0, BluetoothGattCharacteristic.FORMAT_UINT16, 0);
        mCallback = callback;
        mHandler = new Handler(Looper.getMainLooper());

        if (mBluetoothGattServer == null) {
            mBluetoothGattServer = new BluetoothGattServerProxy(mContext);
        }

        if (!mBluetoothGattServer.open(mGattServerCallback)) {
            Log.e(TAG, " Could not open Gatt server");
@@ -381,22 +365,14 @@ public class TbsGatt {

        mEventLogger.add("Initialized");
        mAdapterService.registerBluetoothStateCallback(
                mContext.getMainExecutor(), mBluetoothStateChangeCallback);
                mAdapterService.getMainExecutor(), mBluetoothStateChangeCallback);
        return true;
    }

    public void cleanup() {
        mAdapterService.unregisterBluetoothStateCallback(mBluetoothStateChangeCallback);

        if (mBluetoothGattServer == null) {
            return;
        }
        mBluetoothGattServer.close();
        mBluetoothGattServer = null;
    }

    public Context getContext() {
        return mContext;
    }

    private void removeUuidFromMetadata(ParcelUuid charUuid, BluetoothDevice device) {
@@ -506,20 +482,15 @@ public class TbsGatt {
                BluetoothDevice device, BluetoothGattCharacteristic characteristic, byte[] value) {
            if (getDeviceAuthorization(device) != BluetoothDevice.ACCESS_ALLOWED) return;
            if (value == null) return;
            if (mBluetoothGattServer != null) {
                mBluetoothGattServer.notifyCharacteristicChanged(
                        device, characteristic, false, value);
            }
            mBluetoothGattServer.notifyCharacteristicChanged(device, characteristic, false, value);
        }

        private void notifyCharacteristicChanged(
                BluetoothDevice device, BluetoothGattCharacteristic characteristic) {
            if (getDeviceAuthorization(device) != BluetoothDevice.ACCESS_ALLOWED) return;

            if (mBluetoothGattServer != null) {
            mBluetoothGattServer.notifyCharacteristicChanged(device, characteristic, false);
        }
        }

        public void notifyWithValue(
                BluetoothDevice device, BluetoothGattCharacteristic characteristic, byte[] value) {
+24 −40
Original line number Diff line number Diff line
@@ -17,6 +17,8 @@

package com.android.bluetooth.tbs;

import static java.util.Objects.requireNonNull;

import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothLeAudio;
import android.bluetooth.BluetoothLeCall;
@@ -50,8 +52,7 @@ import java.util.UUID;

/** Container class to store TBS instances */
public class TbsGeneric {

    private static final String TAG = "TbsGeneric";
    private static final String TAG = TbsGeneric.class.getSimpleName();

    private static final String UCI = "GTBS";
    private static final String DEFAULT_PROVIDER_NAME = "none";
@@ -121,17 +122,20 @@ public class TbsGeneric {
        }
    }

    private boolean mIsInitialized = false;
    private TbsGatt mTbsGatt = null;
    private List<Bearer> mBearerList = new ArrayList<>();
    private final List<Bearer> mBearerList = new ArrayList<>();
    private final Map<Integer, TbsCall> mCurrentCallsList = new TreeMap<>();
    private final Receiver mReceiver = new Receiver();
    private final ServiceFactory mFactory = new ServiceFactory();

    private final TbsGatt mTbsGatt;
    private final Context mContext;

    private boolean mIsInitialized;
    private int mLastIndexAssigned = TbsCall.INDEX_UNASSIGNED;
    private Map<Integer, TbsCall> mCurrentCallsList = new TreeMap<>();
    private Bearer mForegroundBearer = null;
    private int mLastRequestIdAssigned = 0;
    private List<String> mUriSchemes = new ArrayList<>(Arrays.asList("tel"));
    private Receiver mReceiver = null;
    private int mStoredRingerMode = -1;
    private final ServiceFactory mFactory = new ServiceFactory();
    private LeAudioService mLeAudioService;

    private final class Receiver extends BroadcastReceiver {
@@ -162,9 +166,9 @@ public class TbsGeneric {
    }
    ;

    public synchronized boolean init(TbsGatt tbsGatt) {
        Log.d(TAG, "init");
        mTbsGatt = tbsGatt;
    TbsGeneric(Context ctx, TbsGatt tbsGatt) {
        mTbsGatt = requireNonNull(tbsGatt);
        mContext = requireNonNull(ctx);

        int ccid =
                ContentControlIdKeeper.acquireCcid(
@@ -173,7 +177,7 @@ public class TbsGeneric {
        if (!isCcidValid(ccid)) {
            Log.e(TAG, " CCID is not valid");
            cleanup();
            return false;
            return;
        }

        if (!mTbsGatt.init(
@@ -187,15 +191,10 @@ public class TbsGeneric {
                mTbsGattCallback)) {
            Log.e(TAG, " TbsGatt init failed");
            cleanup();
            return false;
            return;
        }

        AudioManager audioManager = mTbsGatt.getContext().getSystemService(AudioManager.class);
        if (audioManager == null) {
            Log.w(TAG, " AudioManager is not available");
            cleanup();
            return false;
        }
        AudioManager audioManager = requireNonNull(mContext.getSystemService(AudioManager.class));

        // read initial value of ringer mode
        mStoredRingerMode = audioManager.getRingerMode();
@@ -206,25 +205,20 @@ public class TbsGeneric {
            mTbsGatt.clearSilentModeFlag();
        }

        mReceiver = new Receiver();
        IntentFilter filter = new IntentFilter(AudioManager.RINGER_MODE_CHANGED_ACTION);
        filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
        mTbsGatt.getContext().registerReceiver(mReceiver, filter);
        mContext.registerReceiver(mReceiver, filter);

        mIsInitialized = true;
        return true;
    }

    public synchronized void cleanup() {
        Log.d(TAG, "cleanup");

        if (mTbsGatt != null) {
            if (mReceiver != null) {
                mTbsGatt.getContext().unregisterReceiver(mReceiver);
        if (mIsInitialized) {
            mContext.unregisterReceiver(mReceiver);
        }
        mTbsGatt.cleanup();
            mTbsGatt = null;
        }

        mIsInitialized = false;
    }
@@ -236,10 +230,8 @@ public class TbsGeneric {
     */
    public synchronized void onDeviceAuthorizationSet(BluetoothDevice device) {
        // Notify TBS GATT service instance in case of pending operations
        if (mTbsGatt != null) {
        mTbsGatt.onDeviceAuthorizationSet(device);
    }
    }

    /**
     * Set inband ringtone for the device. When set, notification will be sent to given device.
@@ -247,10 +239,6 @@ public class TbsGeneric {
     * @param device device for which inband ringtone has been set
     */
    public synchronized void setInbandRingtoneSupport(BluetoothDevice device) {
        if (mTbsGatt == null) {
            Log.w(TAG, "setInbandRingtoneSupport, mTbsGatt is null");
            return;
        }
        mTbsGatt.setInbandRingtoneFlag(device);
    }

@@ -260,10 +248,6 @@ public class TbsGeneric {
     * @param device device for which inband ringtone has been cleared
     */
    public synchronized void clearInbandRingtoneSupport(BluetoothDevice device) {
        if (mTbsGatt == null) {
            Log.w(TAG, "setInbandRingtoneSupport, mTbsGatt is null");
            return;
        }
        mTbsGatt.clearInbandRingtoneFlag(device);
    }

@@ -767,7 +751,7 @@ public class TbsGeneric {
            Log.i(TAG, "originate uri=" + uri);
            Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED, Uri.parse(uri));
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            mTbsGatt.getContext().startActivity(intent);
            mContext.startActivity(intent);
            mTbsGatt.setCallControlPointResult(
                    device,
                    TbsGatt.CALL_CONTROL_POINT_OPCODE_ORIGINATE,
+12 −19
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@ package com.android.bluetooth.tbs;
import static android.Manifest.permission.BLUETOOTH_CONNECT;
import static android.Manifest.permission.BLUETOOTH_PRIVILEGED;

import static java.util.Objects.requireNonNull;

import android.annotation.RequiresPermission;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothLeCall;
@@ -27,13 +29,13 @@ import android.bluetooth.BluetoothProfile;
import android.bluetooth.IBluetoothLeCallControl;
import android.bluetooth.IBluetoothLeCallControlCallback;
import android.content.AttributionSource;
import android.content.Context;
import android.os.ParcelUuid;
import android.os.RemoteException;
import android.sysprop.BluetoothProperties;
import android.util.Log;

import com.android.bluetooth.Utils;
import com.android.bluetooth.btservice.AdapterService;
import com.android.bluetooth.btservice.ProfileService;
import com.android.bluetooth.le_audio.LeAudioService;
import com.android.internal.annotations.VisibleForTesting;
@@ -44,16 +46,20 @@ import java.util.Map;
import java.util.UUID;

public class TbsService extends ProfileService {

    private static final String TAG = "TbsService";
    private static final String TAG = TbsService.class.getSimpleName();

    private static TbsService sTbsService;

    private final Map<BluetoothDevice, Integer> mDeviceAuthorizations = new HashMap<>();
    private final TbsGeneric mTbsGeneric;

    private final TbsGeneric mTbsGeneric = new TbsGeneric();
    public TbsService(AdapterService adapterService) {
        super(requireNonNull(adapterService));

    public TbsService(Context ctx) {
        super(ctx);
        // Mark service as started
        setTbsService(this);

        mTbsGeneric = new TbsGeneric(adapterService, new TbsGatt(adapterService, this));
    }

    public static boolean isEnabled() {
@@ -65,19 +71,6 @@ public class TbsService extends ProfileService {
        return new TbsServerBinder(this);
    }

    @Override
    public void start() {
        Log.d(TAG, "start()");
        if (sTbsService != null) {
            throw new IllegalStateException("start() called twice");
        }

        // Mark service as started
        setTbsService(this);

        mTbsGeneric.init(new TbsGatt(this));
    }

    @Override
    public void stop() {
        Log.d(TAG, "stop()");