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

Commit 1caa6d11 authored by Jaikumar Ganesh's avatar Jaikumar Ganesh
Browse files

Add new API for fetching UUIDs using SDP.

Add new API which clients can use to force an SDP query.
The result is broadcast using an intent having the UUIDs.
The intent is broadcast after a timeout, in case of an error.
This timeout is greater than the page timeout.

Change-Id: I61e6db4c05b34c42f679a66987e37e2063a793b6
parent 074c11c1
Loading
Loading
Loading
Loading
+45 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import android.util.Log;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.UUID;

/**
 * Represents a remote Bluetooth device.
@@ -225,6 +226,20 @@ public final class BluetoothDevice implements Parcelable {
    /** @hide */
    public static final String EXTRA_PASSKEY = "android.bluetooth.device.extra.PASSKEY";

    /**
     * Broadcast Action: This intent is used to broadcast the {@link UUID}
     * wrapped as a {@link ParcelUuid} of the remote device after it has been
     * fetched. This intent is sent only when the UUIDs of the remote device
     * are requested to be fetched using Service Discovery Protocol
     * <p> Always contains the extra field {@link #EXTRA_DEVICE}
     * <p> Always contains the extra filed {@link #EXTRA_UUID}
     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
     * @hide
     */
    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    public static final String ACTION_UUID =
            "android.bleutooth.device.action.UUID";

    /**
     * Broadcast Action: Indicates a failure to retrieve the name of a remote
     * device.
@@ -292,6 +307,15 @@ public final class BluetoothDevice implements Parcelable {
     * @hide */
    public static final int PAIRING_VARIANT_DISPLAY_PASSKEY = 4;

    /**
     * Used as an extra field in {@link #ACTION_UUID} intents,
     * Contains the {@link ParcelUuid}s of the remote device which is a parcelable
     * version of {@link UUID}.
     * @hide
     */
    public static final String EXTRA_UUID = "android.bluetooth.device.extra.UUID";


    private static IBluetooth sService;  /* Guarenteed constant after first object constructed */

    private final String mAddress;
@@ -507,6 +531,27 @@ public final class BluetoothDevice implements Parcelable {
        return null;
    }

     /**
      *  Perform a SDP query on the remote device to get the UUIDs
      *  supported. This API is asynchronous and an Intent is sent,
      *  with the UUIDs supported by the remote end. If there is an error
      *  in getting the SDP records or if the process takes a long time,
      *  an Intent is sent with the UUIDs that is currently present in the
      *  cache. Clients should use the {@link getUuids} to get UUIDs
      *  is SDP is not to be performed.
      *
      *  @return False if the sanity check fails, True if the process
      *               of initiating an ACL connection to the remote device
      *               was started.
      *  @hide
      */
     public boolean fetchUuidsWithSdp() {
        try {
            return sService.fetchRemoteUuidsWithSdp(mAddress);
        } catch (RemoteException e) {Log.e(TAG, "", e);}
        return false;
    }

    /** @hide */
    public int getServiceChannel(ParcelUuid uuid) {
         try {
+1 −0
Original line number Diff line number Diff line
@@ -53,6 +53,7 @@ interface IBluetooth
    String getRemoteName(in String address);
    int getRemoteClass(in String address);
    ParcelUuid[] getRemoteUuids(in String address);
    boolean fetchRemoteUuidsWithSdp(in String address);
    int getRemoteServiceChannel(in String address,in ParcelUuid uuid);

    boolean setPin(in String address, in byte[] pin);
+23 −0
Original line number Diff line number Diff line
@@ -330,6 +330,9 @@ class BluetoothEventLoop {
            Log.e(TAG, "onDevicePropertyChanged: Address of the remote device in null");
            return;
        }
        if (DBG) {
            log("Device property changed:" + address + "property:" + name);
        }
        BluetoothDevice device = mAdapter.getRemoteDevice(address);
        if (name.equals("Name")) {
            Intent intent = new Intent(BluetoothDevice.ACTION_NAME_CHANGED);
@@ -366,6 +369,7 @@ class BluetoothEventLoop {
                uuid = str.toString();
            }
            mBluetoothService.setRemoteDeviceProperty(address, name, uuid);
            mBluetoothService.sendUuidIntent(address);
        } else if (name.equals("Paired")) {
            if (propValues[1].equals("true")) {
                mBluetoothService.getBondState().setBondState(address, BluetoothDevice.BOND_BONDED);
@@ -528,6 +532,25 @@ class BluetoothEventLoop {
        return;
    }

    private void onDiscoverServicesResult(String deviceObjectPath, boolean result) {
        String address = mBluetoothService.getAddressFromObjectPath(deviceObjectPath);
        // We don't parse the xml here, instead just query Bluez for the properties.
        if (result) {
            String[] properties = mBluetoothService.getRemoteDeviceProperties(address);
            mBluetoothService.addRemoteDeviceProperties(address, properties);
        }
        mBluetoothService.sendUuidIntent(address);
    }

    private void onCreateDeviceResult(String address, boolean result) {
        if (DBG) {
            log("Result of onCreateDeviceResult:" + result);
        }
        if (!result) {
            mBluetoothService.sendUuidIntent(address);
        }
    }

    private void onRestartRequired() {
        if (mBluetoothService.isEnabled()) {
            Log.e(TAG, "*** A serious error occured (did bluetoothd crash?) - " +
+61 −0
Original line number Diff line number Diff line
@@ -76,10 +76,17 @@ public class BluetoothService extends IBluetooth.Stub {

    private static final int MESSAGE_REGISTER_SDP_RECORDS = 1;
    private static final int MESSAGE_FINISH_DISABLE = 2;
    private static final int MESSAGE_UUID_INTENT = 3;

    // The timeout used to sent the UUIDs Intent
    // This timeout should be greater than the page timeout
    private static final int UUID_INTENT_DELAY = 6000;

    private final Map<String, String> mAdapterProperties;
    private final HashMap <String, Map<String, String>> mDeviceProperties;

    private final ArrayList <String> mUuidIntentTracker;

    static {
        classInitNative();
    }
@@ -104,6 +111,7 @@ public class BluetoothService extends IBluetooth.Stub {
        mIsDiscovering = false;
        mAdapterProperties = new HashMap<String, String>();
        mDeviceProperties = new HashMap<String, Map<String,String>>();
        mUuidIntentTracker = new ArrayList<String>();
        registerForAirplaneMode();
    }

@@ -291,6 +299,11 @@ public class BluetoothService extends IBluetooth.Stub {
            case MESSAGE_FINISH_DISABLE:
                finishDisable(msg.arg1 != 0);
                break;
            case MESSAGE_UUID_INTENT:
                String address = (String)msg.obj;
                if (address != null)
                    sendUuidIntent(address);
                break;
            }
        }
    };
@@ -976,6 +989,10 @@ public class BluetoothService extends IBluetooth.Stub {
        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
            return null;
        }
        return getUuidFromCache(address);
    }

    private ParcelUuid[] getUuidFromCache(String address) {
        String value = getRemoteDeviceProperty(address, "UUIDs");
        if (value == null) return null;

@@ -990,6 +1007,36 @@ public class BluetoothService extends IBluetooth.Stub {
        return uuids;
    }

    public synchronized boolean fetchRemoteUuidsWithSdp(String address) {
        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
            return false;
        }

        if (mUuidIntentTracker.contains(address)) {
            // An SDP query for this address is already in progress
            return true;
        }

        boolean ret;
        if (getBondState(address) == BluetoothDevice.BOND_BONDED) {
            String path = getObjectPathFromAddress(address);
            if (path == null) return false;

            // Use an empty string for the UUID pattern
            ret = discoverServicesNative(path, "");
        } else {
            ret = createDeviceNative(address);
        }

        mUuidIntentTracker.add(address);

        Message message = mHandler.obtainMessage(MESSAGE_UUID_INTENT);
        message.obj = address;
        mHandler.sendMessageDelayed(message, UUID_INTENT_DELAY);
        return ret;
    }

    /**
     * Gets the rfcomm channel associated with the UUID.
     *
@@ -1121,6 +1168,18 @@ public class BluetoothService extends IBluetooth.Stub {
                Settings.System.AIRPLANE_MODE_ON, 0) == 1;
    }

    /* Broadcast the Uuid intent */
    /*package*/ synchronized void sendUuidIntent(String address) {
        if (mUuidIntentTracker.contains(address)) {
            ParcelUuid[] uuid = getUuidFromCache(address);
            Intent intent = new Intent(BluetoothDevice.ACTION_UUID);
            intent.putExtra(BluetoothDevice.EXTRA_UUID, uuid);
            mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);

            mUuidIntentTracker.remove(address);
        }
    }

    @Override
    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
        pw.println("\nmIsAirplaneSensitive = " + mIsAirplaneSensitive + "\n");
@@ -1284,4 +1343,6 @@ public class BluetoothService extends IBluetooth.Stub {
    private native boolean setPairingConfirmationNative(String address, boolean confirm,
            int nativeData);
    private native boolean setDevicePropertyBooleanNative(String objectPath, String key, int value);
    private native boolean createDeviceNative(String address);
    private native boolean discoverServicesNative(String objectPath, String pattern);
}
+54 −0
Original line number Diff line number Diff line
@@ -48,6 +48,8 @@ static jmethodID method_onDeviceRemoved;
static jmethodID method_onDeviceDisconnectRequested;

static jmethodID method_onCreatePairedDeviceResult;
static jmethodID method_onCreateDeviceResult;
static jmethodID method_onDiscoverServicesResult;
static jmethodID method_onGetDeviceServiceChannelResult;

static jmethodID method_onRequestPinCode;
@@ -92,6 +94,10 @@ static void classInitNative(JNIEnv* env, jclass clazz) {

    method_onCreatePairedDeviceResult = env->GetMethodID(clazz, "onCreatePairedDeviceResult",
                                                         "(Ljava/lang/String;I)V");
    method_onCreateDeviceResult = env->GetMethodID(clazz, "onCreateDeviceResult",
                                                         "(Ljava/lang/String;Z)V");
    method_onDiscoverServicesResult = env->GetMethodID(clazz, "onDiscoverServicesResult",
                                                         "(Ljava/lang/String;Z)V");

    method_onAgentAuthorize = env->GetMethodID(clazz, "onAgentAuthorize",
                                               "(Ljava/lang/String;Ljava/lang/String;)Z");
@@ -1097,6 +1103,54 @@ done:
    free(user);
}

void onCreateDeviceResult(DBusMessage *msg, void *user, void *n) {
    LOGV(__FUNCTION__);

    native_data_t *nat = (native_data_t *)n;
    const char *address= (const char *)user;
    DBusError err;
    dbus_error_init(&err);
    JNIEnv *env;
    nat->vm->GetEnv((void**)&env, nat->envVer);

    LOGV("... Address = %s", address);

    bool result = JNI_TRUE;
    if (dbus_set_error_from_message(&err, msg)) {
        LOG_AND_FREE_DBUS_ERROR(&err);
        result = JNI_FALSE;
    }
    env->CallVoidMethod(nat->me,
                        method_onCreateDeviceResult,
                        env->NewStringUTF(address),
                        result);
    free(user);
}

void onDiscoverServicesResult(DBusMessage *msg, void *user, void *n) {
    LOGV(__FUNCTION__);

    native_data_t *nat = (native_data_t *)n;
    const char *path = (const char *)user;
    DBusError err;
    dbus_error_init(&err);
    JNIEnv *env;
    nat->vm->GetEnv((void**)&env, nat->envVer);

    LOGV("... Device Path = %s", path);

    bool result = JNI_TRUE;
    if (dbus_set_error_from_message(&err, msg)) {
        LOG_AND_FREE_DBUS_ERROR(&err);
        result = JNI_FALSE;
    }
    env->CallVoidMethod(nat->me,
                        method_onDiscoverServicesResult,
                        env->NewStringUTF(path),
                        result);
    free(user);
}

void onGetDeviceServiceChannelResult(DBusMessage *msg, void *user, void *n) {
    LOGV(__FUNCTION__);

Loading