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

Commit 96f3b1a3 authored by Fei Zheng's avatar Fei Zheng Committed by Alain Vongsouvanh
Browse files

DIP: Implement API to get device identification information

Bug: 141666056
Test: atest BluetoothInstrumentationTests
Sponsor: alainv@
Tag: #feature

Change-Id: I24f788dfcf3beae9b2af4515cb1f32b817807cad
parent 9c2cb262
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ static const Uuid UUID_PBAP_PSE = Uuid::From16Bit(0x112F);
static const Uuid UUID_MAP_MAS = Uuid::From16Bit(0x1132);
static const Uuid UUID_MAP_MNS = Uuid::From16Bit(0x1133);
static const Uuid UUID_SAP = Uuid::From16Bit(0x112D);
static const Uuid UUID_DIP = Uuid::From16Bit(0x1200);

namespace android {
static jmethodID method_sdpRecordFoundCallback;
@@ -39,6 +40,7 @@ static jmethodID method_sdpMnsRecordFoundCallback;
static jmethodID method_sdpPseRecordFoundCallback;
static jmethodID method_sdpOppOpsRecordFoundCallback;
static jmethodID method_sdpSapsRecordFoundCallback;
static jmethodID method_sdpDipRecordFoundCallback;

static const btsdp_interface_t* sBluetoothSdpInterface = NULL;

@@ -96,6 +98,9 @@ static void classInitNative(JNIEnv* env, jclass clazz) {
  /* SAP Server record */
  method_sdpSapsRecordFoundCallback = env->GetMethodID(
      clazz, "sdpSapsRecordFoundCallback", "(I[B[BIILjava/lang/String;Z)V");
  /* DIP record */
  method_sdpDipRecordFoundCallback = env->GetMethodID(
      clazz, "sdpDipRecordFoundCallback", "(I[B[BIIIIIZZ)V");
}

static jboolean sdpSearchNative(JNIEnv* env, jobject obj, jbyteArray address,
@@ -214,6 +219,17 @@ static void sdp_search_callback(bt_status_t status, const RawAddress& bd_addr,
          addr.get(), uuid.get(), (jint)record->mas.hdr.rfcomm_channel_number,
          (jint)record->mas.hdr.profile_version, service_name.get(),
          more_results);
    } else if (uuid_in == UUID_DIP) {
      ALOGD("%s, Get UUID_DIP", __func__);
      sCallbackEnv->CallVoidMethod(
          sCallbacksObj, method_sdpDipRecordFoundCallback, (jint)status,
          addr.get(), uuid.get(), (jint)record->dip.spec_id,
          (jint)record->dip.vendor,
          (jint)record->dip.vendor_id_source,
          (jint)record->dip.product,
          (jint)record->dip.version,
          record->dip.primary_record,
          more_results);
    } else {
      // we don't have a wrapper for this uuid, send as raw data
      jint record_data_size = record->hdr.user1_ptr_len;
+34 −0
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
package com.android.bluetooth.sdp;

import android.bluetooth.BluetoothDevice;
import android.bluetooth.SdpDipRecord;
import android.bluetooth.SdpMasRecord;
import android.bluetooth.SdpMnsRecord;
import android.bluetooth.SdpOppOpsRecord;
@@ -365,6 +366,39 @@ public class SdpManager {
        }
    }

    void sdpDipRecordFoundCallback(int status, byte[] address,
            byte[] uuid,  int specificationId,
            int vendorId, int vendorIdSource,
            int productId, int version,
            boolean primaryRecord,
            boolean moreResults) {
        synchronized(TRACKER_LOCK) {
            SdpSearchInstance inst = sSdpSearchTracker.getSearchInstance(address, uuid);
            SdpDipRecord sdpRecord = null;
            if (inst == null) {
              Log.e(TAG, "sdpDipRecordFoundCallback: Search instance is NULL");
              return;
            }
            inst.setStatus(status);
            if (D) {
                Log.d(TAG, "sdpDipRecordFoundCallback: status " + status);
            }
            if (status == AbstractionLayer.BT_STATUS_SUCCESS) {
                sdpRecord = new SdpDipRecord(specificationId,
                        vendorId, vendorIdSource,
                        productId, version,
                        primaryRecord);
            }
            if (D) {
                Log.d(TAG, "UUID: " + Arrays.toString(uuid));
            }
            if (D) {
                Log.d(TAG, "UUID in parcel: " + ((Utils.byteArrayToUuid(uuid))[0]).toString());
            }
            sendSdpIntent(inst, sdpRecord, moreResults);
        }
    }

    /* TODO: Test or remove! */
    void sdpRecordFoundCallback(int status, byte[] address, byte[] uuid, int sizeRecord,
            byte[] record) {
+1 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ android_test {
        "androidx.room_room-migration",
        "androidx.room_room-runtime",
        "androidx.room_room-testing",
        "truth-prebuilt",
    ],

    asset_dirs: ["src/com/android/bluetooth/btservice/storage/schemas"],
+138 −0
Original line number Diff line number Diff line
/*
 * Copyright 2018 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.bluetooth.sdp;

import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.verify;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothUuid;
import android.bluetooth.SdpDipRecord;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Looper;
import android.os.ParcelUuid;

import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;

import com.android.bluetooth.R;
import com.android.bluetooth.sdp.SdpManager;
import com.android.bluetooth.TestUtils;
import com.android.bluetooth.btservice.AbstractionLayer;
import com.android.bluetooth.btservice.AdapterService;
import com.android.bluetooth.Utils;

import org.junit.After;
import org.junit.Assume;
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.MockitoAnnotations;

@SmallTest
@RunWith(AndroidJUnit4.class)
public class DipTest {
    private BluetoothAdapter mAdapter;
    private Context mTargetContext;
    private SdpManager mSdpManager;
    private BluetoothDevice mTestDevice;

    private ArgumentCaptor<Intent> mIntentArgument = ArgumentCaptor.forClass(Intent.class);
    private ArgumentCaptor<String> mStringArgument = ArgumentCaptor.forClass(String.class);

    @Mock private AdapterService mAdapterService = null;

    @Before
    public void setUp() throws Exception {
        mTargetContext = InstrumentationRegistry.getTargetContext();
        // Set up mocks and test assets
        MockitoAnnotations.initMocks(this);

        TestUtils.setAdapterService(mAdapterService);

        if (Looper.myLooper() == null) {
            Looper.prepare();
        }

        mAdapter = BluetoothAdapter.getDefaultAdapter();
        mSdpManager = SdpManager.init(mAdapterService);

        // Get a device for testing
        mTestDevice = mAdapter.getRemoteDevice("00:01:02:03:04:05");
    }

    @After
    public void tearDown() throws Exception {
    }

    private void verifyDipSdpRecordIntent(ArgumentCaptor<Intent> intentArgument,
            int status, BluetoothDevice device,
            byte[] uuid,  int specificationId,
            int vendorId, int vendorIdSource,
            int productId, int version,
            boolean primaryRecord) {
        Intent intent = intentArgument.getValue();

        assertThat(intent).isNotEqualTo(null);
        assertThat(BluetoothDevice.ACTION_SDP_RECORD).isEqualTo(intent.getAction());
        assertThat(device).isEqualTo(intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE));
        assertThat(Utils.byteArrayToUuid(uuid)[0]).isEqualTo(intent.getParcelableExtra(BluetoothDevice.EXTRA_UUID));
        assertThat(status).isEqualTo(intent.getIntExtra(BluetoothDevice.EXTRA_SDP_SEARCH_STATUS, -1));

        SdpDipRecord record = intent.getParcelableExtra(BluetoothDevice.EXTRA_SDP_RECORD);
        assertThat(record).isNotEqualTo(null);
        assertThat(specificationId).isEqualTo(record.getSpecificationId());
        assertThat(vendorId).isEqualTo(record.getVendorId());
        assertThat(vendorIdSource).isEqualTo(record.getVendorIdSource());
        assertThat(productId).isEqualTo(record.getProductId());
        assertThat(version).isEqualTo(record.getVersion());
        assertThat(primaryRecord).isEqualTo(record.getPrimaryRecord());
    }

    /**
     * Test that an outgoing connection/disconnection succeeds
     */
    @Test
    @SmallTest
    public void testDipCallbackSuccess() {
        // DIP uuid in bytes
        byte[] uuid = {0, 0, 18, 0, 0, 0, 16, 0, -128, 0, 0, -128, 95, -101, 52, -5};
        int specificationId = 0x0103;
        int vendorId = 0x18d1;
        int vendorIdSource = 1;
        int productId = 0x1234;
        int version = 0x0100;
        boolean primaryRecord = true;
        boolean moreResults = false;

        mSdpManager.sdpSearch(mTestDevice, BluetoothUuid.DIP);
        mSdpManager.sdpDipRecordFoundCallback(AbstractionLayer.BT_STATUS_SUCCESS,
                Utils.getByteAddress(mTestDevice), uuid, specificationId,
                vendorId, vendorIdSource, productId, version, primaryRecord, moreResults);
        verify(mAdapterService).sendBroadcast(mIntentArgument.capture(), mStringArgument.capture());
        verifyDipSdpRecordIntent(mIntentArgument, AbstractionLayer.BT_STATUS_SUCCESS, mTestDevice,
                uuid, specificationId, vendorId, vendorIdSource, productId, version, primaryRecord);
    }
}