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

Commit 0a916220 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Periodic sync and PAST implementation"

parents 01868691 7efe6b5e
Loading
Loading
Loading
Loading
+56 −6
Original line number Original line Diff line number Diff line
@@ -184,7 +184,7 @@ static jmethodID method_onPeriodicAdvertisingEnabled;
static jmethodID method_onSyncLost;
static jmethodID method_onSyncLost;
static jmethodID method_onSyncReport;
static jmethodID method_onSyncReport;
static jmethodID method_onSyncStarted;
static jmethodID method_onSyncStarted;

static jmethodID method_onSyncTransferredCallback;
/**
/**
 * Static variables
 * Static variables
 */
 */
@@ -2230,6 +2230,8 @@ static void periodicScanClassInitNative(JNIEnv* env, jclass clazz) {
      env->GetMethodID(clazz, "onSyncStarted", "(IIIILjava/lang/String;III)V");
      env->GetMethodID(clazz, "onSyncStarted", "(IIIILjava/lang/String;III)V");
  method_onSyncReport = env->GetMethodID(clazz, "onSyncReport", "(IIII[B)V");
  method_onSyncReport = env->GetMethodID(clazz, "onSyncReport", "(IIII[B)V");
  method_onSyncLost = env->GetMethodID(clazz, "onSyncLost", "(I)V");
  method_onSyncLost = env->GetMethodID(clazz, "onSyncLost", "(I)V");
  method_onSyncTransferredCallback = env->GetMethodID(
      clazz, "onSyncTransferredCallback", "(IILjava/lang/String;)V");
}
}


static void periodicScanInitializeNative(JNIEnv* env, jobject object) {
static void periodicScanInitializeNative(JNIEnv* env, jobject object) {
@@ -2254,10 +2256,16 @@ static void onSyncStarted(int reg_id, uint8_t status, uint16_t sync_handle,
                          uint8_t phy, uint16_t interval) {
                          uint8_t phy, uint16_t interval) {
  CallbackEnv sCallbackEnv(__func__);
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid()) return;
  if (!sCallbackEnv.valid()) return;
  if (!mPeriodicScanCallbacksObj) {
    ALOGE("mPeriodicScanCallbacksObj is NULL. Return.");
    return;
  }
  ScopedLocalRef<jstring> addr(sCallbackEnv.get(),
                               bdaddr2newjstr(sCallbackEnv.get(), &address));


  sCallbackEnv->CallVoidMethod(mPeriodicScanCallbacksObj, method_onSyncStarted,
  sCallbackEnv->CallVoidMethod(mPeriodicScanCallbacksObj, method_onSyncStarted,
                               reg_id, sync_handle, sid, address_type, address,
                               reg_id, sync_handle, sid, address_type,
                               phy, interval, status);
                               addr.get(), phy, interval, status);
}
}


static void onSyncReport(uint16_t sync_handle, int8_t tx_power, int8_t rssi,
static void onSyncReport(uint16_t sync_handle, int8_t tx_power, int8_t rssi,
@@ -2287,19 +2295,56 @@ static void startSyncNative(JNIEnv* env, jobject object, jint sid,
                            jstring address, jint skip, jint timeout,
                            jstring address, jint skip, jint timeout,
                            jint reg_id) {
                            jint reg_id) {
  if (!sGattIf) return;
  if (!sGattIf) return;

  sGattIf->scanner->StartSync(sid, str2addr(env, address), skip, timeout,
  sGattIf->scanner->StartSync(sid, str2addr(env, address), skip, timeout,
                              base::Bind(&onSyncStarted, reg_id),
                              base::Bind(&onSyncStarted, reg_id),
                              base::Bind(&onSyncReport),
                              base::Bind(&onSyncReport),
                              base::Bind(&onSyncLost));
                              base::Bind(&onSyncLost));
}
}


static void stopSyncNative(int sync_handle) {
static void stopSyncNative(JNIEnv* env, jobject object, jint sync_handle) {
  if (!sGattIf) return;
  if (!sGattIf) return;

  sGattIf->scanner->StopSync(sync_handle);
  sGattIf->scanner->StopSync(sync_handle);
}
}


static void cancelSyncNative(JNIEnv* env, jobject object, jint sid,
                             jstring address) {
  if (!sGattIf) return;
  sGattIf->scanner->CancelCreateSync(sid, str2addr(env, address));
}

static void onSyncTransferredCb(int pa_source, uint8_t status,
                                RawAddress address) {
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid()) return;
  if (!mPeriodicScanCallbacksObj) {
    ALOGE("mPeriodicScanCallbacksObj is NULL. Return.");
    return;
  }
  ScopedLocalRef<jstring> addr(sCallbackEnv.get(),
                               bdaddr2newjstr(sCallbackEnv.get(), &address));

  sCallbackEnv->CallVoidMethod(mPeriodicScanCallbacksObj,
                               method_onSyncTransferredCallback, pa_source,
                               status, addr.get());
}

static void syncTransferNative(JNIEnv* env, jobject object, jint pa_source,
                               jstring addr, jint service_data,
                               jint sync_handle) {
  if (!sGattIf) return;
  sGattIf->scanner->TransferSync(str2addr(env, addr), service_data, sync_handle,
                                 base::Bind(&onSyncTransferredCb, pa_source));
}

static void transferSetInfoNative(JNIEnv* env, jobject object, jint pa_source,
                                  jstring addr, jint service_data,
                                  jint adv_handle) {
  if (!sGattIf) return;
  sGattIf->scanner->TransferSetInfo(
      str2addr(env, addr), service_data, adv_handle,
      base::Bind(&onSyncTransferredCb, pa_source));
}

static void gattTestNative(JNIEnv* env, jobject object, jint command,
static void gattTestNative(JNIEnv* env, jobject object, jint command,
                           jlong uuid1_lsb, jlong uuid1_msb, jstring bda1,
                           jlong uuid1_lsb, jlong uuid1_msb, jstring bda1,
                           jint p1, jint p2, jint p3, jint p4, jint p5) {
                           jint p1, jint p2, jint p3, jint p4, jint p5) {
@@ -2358,6 +2403,11 @@ static JNINativeMethod sPeriodicScanMethods[] = {
    {"cleanupNative", "()V", (void*)periodicScanCleanupNative},
    {"cleanupNative", "()V", (void*)periodicScanCleanupNative},
    {"startSyncNative", "(ILjava/lang/String;III)V", (void*)startSyncNative},
    {"startSyncNative", "(ILjava/lang/String;III)V", (void*)startSyncNative},
    {"stopSyncNative", "(I)V", (void*)stopSyncNative},
    {"stopSyncNative", "(I)V", (void*)stopSyncNative},
    {"cancelSyncNative", "(ILjava/lang/String;)V", (void*)cancelSyncNative},
    {"syncTransferNative", "(ILjava/lang/String;II)V",
     (void*)syncTransferNative},
    {"transferSetInfoNative", "(ILjava/lang/String;II)V",
     (void*)transferSetInfoNative},
};
};


// JNI functions defined in ScanManager class.
// JNI functions defined in ScanManager class.
+40 −1
Original line number Original line Diff line number Diff line
@@ -1088,12 +1088,32 @@ public class GattService extends ProfileService {
        }
        }


        @Override
        @Override
        public void unregisterSync(
        public void transferSync(BluetoothDevice bda, int serviceData , int syncHandle,
                AttributionSource attributionSource) {
            GattService service = getService();
            if (service == null) {
                return;
            }
            service.transferSync(bda, serviceData , syncHandle, attributionSource);
        }

        @Override
        public void transferSetInfo(BluetoothDevice bda, int serviceData , int advHandle,
                IPeriodicAdvertisingCallback callback, AttributionSource attributionSource) {
                IPeriodicAdvertisingCallback callback, AttributionSource attributionSource) {
            GattService service = getService();
            GattService service = getService();
            if (service == null) {
            if (service == null) {
                return;
                return;
            }
            }
            service.transferSetInfo(bda, serviceData , advHandle, callback, attributionSource);
        }

        @Override
        public void unregisterSync(IPeriodicAdvertisingCallback callback,
                AttributionSource attributionSource) {
            GattService service = getService();
            if (service == null) {
                return;
            }
            service.unregisterSync(callback, attributionSource);
            service.unregisterSync(callback, attributionSource);
        }
        }


@@ -2621,6 +2641,25 @@ public class GattService extends ProfileService {
        mPeriodicScanManager.stopSync(callback);
        mPeriodicScanManager.stopSync(callback);
    }
    }


    void transferSync(BluetoothDevice bda, int serviceData, int syncHandle,
            AttributionSource attributionSource) {
        if (!Utils.checkScanPermissionForDataDelivery(
                this, attributionSource, "GattService transferSync")) {
            return;
        }
        mPeriodicScanManager.transferSync(bda, serviceData, syncHandle);
    }

    void transferSetInfo(BluetoothDevice bda, int serviceData,
                  int advHandle, IPeriodicAdvertisingCallback callback,
                  AttributionSource attributionSource) {
        if (!Utils.checkScanPermissionForDataDelivery(
                this, attributionSource, "GattService transferSetInfo")) {
            return;
        }
        mPeriodicScanManager.transferSetInfo(bda, serviceData, advHandle, callback);
    }

    /**************************************************************************
    /**************************************************************************
     * ADVERTISING SET
     * ADVERTISING SET
     *************************************************************************/
     *************************************************************************/
+209 −40
Original line number Original line Diff line number Diff line
@@ -16,6 +16,8 @@


package com.android.bluetooth.gatt;
package com.android.bluetooth.gatt;


import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.le.IPeriodicAdvertisingCallback;
import android.bluetooth.le.IPeriodicAdvertisingCallback;
import android.bluetooth.le.PeriodicAdvertisingReport;
import android.bluetooth.le.PeriodicAdvertisingReport;
import android.bluetooth.le.ScanRecord;
import android.bluetooth.le.ScanRecord;
@@ -30,6 +32,7 @@ import com.android.bluetooth.btservice.AdapterService;
import java.util.Collections;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashMap;
import java.util.Map;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;


/**
/**
 * Manages Bluetooth LE Periodic scans
 * Manages Bluetooth LE Periodic scans
@@ -40,10 +43,12 @@ class PeriodicScanManager {
    private static final boolean DBG = GattServiceConfig.DBG;
    private static final boolean DBG = GattServiceConfig.DBG;
    private static final String TAG = GattServiceConfig.TAG_PREFIX + "SyncManager";
    private static final String TAG = GattServiceConfig.TAG_PREFIX + "SyncManager";


    private final AdapterService mAdapterService;
    private final BluetoothAdapter mAdapter;
    Map<IBinder, SyncInfo> mSyncs = Collections.synchronizedMap(new HashMap<>());
    Map<IBinder, SyncInfo> mSyncs = new ConcurrentHashMap<>();
    Map<IBinder, SyncTransferInfo> mSyncTransfers = Collections.synchronizedMap(new HashMap<>());
    static int sTempRegistrationId = -1;
    static int sTempRegistrationId = -1;

    private static final int PA_SOURCE_LOCAL = 1;
    private static final int PA_SOURCE_REMOTE = 2;
    /**
    /**
     * Constructor of {@link SyncManager}.
     * Constructor of {@link SyncManager}.
     */
     */
@@ -51,7 +56,7 @@ class PeriodicScanManager {
        if (DBG) {
        if (DBG) {
            Log.d(TAG, "advertise manager created");
            Log.d(TAG, "advertise manager created");
        }
        }
        mAdapterService = adapterService;
        mAdapter = BluetoothAdapter.getDefaultAdapter();
    }
    }


    void start() {
    void start() {
@@ -67,21 +72,52 @@ class PeriodicScanManager {
        sTempRegistrationId = -1;
        sTempRegistrationId = -1;
    }
    }


    class SyncTransferInfo {
        public String address;
        public SyncDeathRecipient deathRecipient;
        public IPeriodicAdvertisingCallback callback;

        SyncTransferInfo(String address, IPeriodicAdvertisingCallback callback) {
            this.address = address;
            this.callback = callback;
        }
    }

    class SyncInfo {
    class SyncInfo {
        /* When id is negative, the registration is ongoing. When the registration finishes, id
        /* When id is negative, the registration is ongoing. When the registration finishes, id
         * becomes equal to sync_handle */
         * becomes equal to sync_handle */
        public Integer id;
        public Integer id;
        public Integer advSid;
        public String address;
        public Integer skip;
        public Integer timeout;
        public SyncDeathRecipient deathRecipient;
        public SyncDeathRecipient deathRecipient;
        public IPeriodicAdvertisingCallback callback;
        public IPeriodicAdvertisingCallback callback;


        SyncInfo(Integer id, SyncDeathRecipient deathRecipient,
        SyncInfo(Integer id, Integer advSid, String address, Integer skip, Integer timeout,
                SyncDeathRecipient deathRecipient,
                IPeriodicAdvertisingCallback callback) {
                IPeriodicAdvertisingCallback callback) {
            this.id = id;
            this.id = id;
            this.advSid = advSid;
            this.address = address;
            this.skip = skip;
            this.timeout = timeout;
            this.deathRecipient = deathRecipient;
            this.deathRecipient = deathRecipient;
            this.callback = callback;
            this.callback = callback;
        }
        }
    }
    }


    Map.Entry<IBinder, SyncTransferInfo> findSyncTransfer(String address) {
        Map.Entry<IBinder, SyncTransferInfo> entry = null;
        for (Map.Entry<IBinder, SyncTransferInfo> e : mSyncTransfers.entrySet()) {
            if (e.getValue().address.equals(address)) {
                entry = e;
                break;
            }
        }
        return entry;
    }

    IBinder toBinder(IPeriodicAdvertisingCallback e) {
    IBinder toBinder(IPeriodicAdvertisingCallback e) {
        return ((IInterface) e).asBinder();
        return ((IInterface) e).asBinder();
    }
    }
@@ -113,6 +149,33 @@ class PeriodicScanManager {
        return entry;
        return entry;
    }
    }


    Map.Entry<IBinder, SyncInfo> findMatchingSync(int advSid, String address) {
        Map.Entry<IBinder, SyncInfo> entry = null;
        for (Map.Entry<IBinder, SyncInfo> e : mSyncs.entrySet()) {
            if (e.getValue().advSid == advSid && e.getValue().address.equals(address)) {
                return entry = e;
            }
        }
        return entry;
    }

    Map<IBinder, SyncInfo> findAllSync(int syncHandle) {
        Map<IBinder, SyncInfo> syncMap = new HashMap<IBinder, SyncInfo>();
        for (Map.Entry<IBinder, SyncInfo> e : mSyncs.entrySet()) {
            if (e.getValue().id != syncHandle) {
                continue;
            }
            syncMap.put(e.getKey(), new SyncInfo(e.getValue().id,
                                                 e.getValue().advSid,
                                                 e.getValue().address,
                                                 e.getValue().skip,
                                                 e.getValue().timeout,
                                                 e.getValue().deathRecipient,
                                                 e.getValue().callback));
        }
        return syncMap;
    }

    void onSyncStarted(int regId, int syncHandle, int sid, int addressType, String address, int phy,
    void onSyncStarted(int regId, int syncHandle, int sid, int addressType, String address, int phy,
            int interval, int status) throws Exception {
            int interval, int status) throws Exception {
        if (DBG) {
        if (DBG) {
@@ -120,26 +183,37 @@ class PeriodicScanManager {
                    "onSyncStarted() - regId=" + regId + ", syncHandle=" + syncHandle + ", status="
                    "onSyncStarted() - regId=" + regId + ", syncHandle=" + syncHandle + ", status="
                            + status);
                            + status);
        }
        }

        Map<IBinder, SyncInfo> syncMap = findAllSync(regId);
        Map.Entry<IBinder, SyncInfo> entry = findSync(regId);
        if (syncMap.size() == 0) {
        if (entry == null) {
            Log.d(TAG, "onSyncStarted() - no callback found for regId " + regId);
            Log.i(TAG, "onSyncStarted() - no callback found for regId " + regId);
            // Sync was stopped before it was properly registered.
            stopSyncNative(syncHandle);
            stopSyncNative(syncHandle);
            return;
            return;
        }
        }


        IPeriodicAdvertisingCallback callback = entry.getValue().callback;
        synchronized (mSyncs) {
            for (Map.Entry<IBinder, SyncInfo> e : mSyncs.entrySet()) {
                if (e.getValue().id != regId) {
                    continue;
                }
                IPeriodicAdvertisingCallback callback = e.getValue().callback;
                if (status == 0) {
                if (status == 0) {
            entry.setValue(new SyncInfo(syncHandle, entry.getValue().deathRecipient, callback));
                    Log.d(TAG, "onSyncStarted: updating id with syncHandle " + syncHandle);
                    e.setValue(new SyncInfo(syncHandle, sid, address, e.getValue().skip,
                                            e.getValue().timeout, e.getValue().deathRecipient,
                                            callback));
                    callback.onSyncEstablished(syncHandle, mAdapter.getRemoteDevice(address),
                                               sid, e.getValue().skip, e.getValue().timeout,
                                               status);
                } else {
                } else {
            IBinder binder = entry.getKey();
                    callback.onSyncEstablished(syncHandle, mAdapter.getRemoteDevice(address),
            binder.unlinkToDeath(entry.getValue().deathRecipient, 0);
                                               sid, e.getValue().skip, e.getValue().timeout,
                                               status);
                    IBinder binder = e.getKey();
                    binder.unlinkToDeath(e.getValue().deathRecipient, 0);
                    mSyncs.remove(binder);
                    mSyncs.remove(binder);
                }
                }

            }
        // TODO: fix callback arguments
        }
        // callback.onSyncStarted(syncHandle, tx_power, status);
    }
    }


    void onSyncReport(int syncHandle, int txPower, int rssi, int dataStatus, byte[] data)
    void onSyncReport(int syncHandle, int txPower, int rssi, int dataStatus, byte[] data)
@@ -148,33 +222,38 @@ class PeriodicScanManager {
            Log.d(TAG, "onSyncReport() - syncHandle=" + syncHandle);
            Log.d(TAG, "onSyncReport() - syncHandle=" + syncHandle);
        }
        }


        Map.Entry<IBinder, SyncInfo> entry = findSync(syncHandle);
        Map<IBinder, SyncInfo> syncMap = findAllSync(syncHandle);
        if (entry == null) {
        if (syncMap.isEmpty()) {
            Log.i(TAG, "onSyncReport() - no callback found for syncHandle " + syncHandle);
            Log.i(TAG, "onSyncReport() - no callback found for syncHandle " + syncHandle);
            return;
            return;
        }
        }

        for (Map.Entry<IBinder, SyncInfo> e :syncMap.entrySet()) {
        IPeriodicAdvertisingCallback callback = entry.getValue().callback;
            IPeriodicAdvertisingCallback callback = e.getValue().callback;
            PeriodicAdvertisingReport report =
            PeriodicAdvertisingReport report =
                    new PeriodicAdvertisingReport(syncHandle, txPower, rssi, dataStatus,
                    new PeriodicAdvertisingReport(syncHandle, txPower, rssi, dataStatus,
                            ScanRecord.parseFromBytes(data));
                            ScanRecord.parseFromBytes(data));
            callback.onPeriodicAdvertisingReport(report);
            callback.onPeriodicAdvertisingReport(report);
        }
        }
    }


    void onSyncLost(int syncHandle) throws Exception {
    void onSyncLost(int syncHandle) throws Exception {
        if (DBG) {
        if (DBG) {
            Log.d(TAG, "onSyncLost() - syncHandle=" + syncHandle);
            Log.d(TAG, "onSyncLost() - syncHandle=" + syncHandle);
        }
        }

        Map<IBinder, SyncInfo> syncMap = findAllSync(syncHandle);
        Map.Entry<IBinder, SyncInfo> entry = findSync(syncHandle);
        if (syncMap.isEmpty()) {
        if (entry == null) {
            Log.i(TAG, "onSyncLost() - no callback found for syncHandle " + syncHandle);
            Log.i(TAG, "onSyncLost() - no callback found for syncHandle " + syncHandle);
            return;
            return;
        }
        }

        for (Map.Entry<IBinder, SyncInfo> e :syncMap.entrySet()) {
        IPeriodicAdvertisingCallback callback = entry.getValue().callback;
            IPeriodicAdvertisingCallback callback = e.getValue().callback;
        mSyncs.remove(entry);
            IBinder binder = toBinder(callback);
            synchronized (mSyncs) {
                mSyncs.remove(binder);
            }
            callback.onSyncLost(syncHandle);
            callback.onSyncLost(syncHandle);

        }
    }
    }


    void startSync(ScanResult scanResult, int skip, int timeout,
    void startSync(ScanResult scanResult, int skip, int timeout,
@@ -189,9 +268,38 @@ class PeriodicScanManager {


        String address = scanResult.getDevice().getAddress();
        String address = scanResult.getDevice().getAddress();
        int sid = scanResult.getAdvertisingSid();
        int sid = scanResult.getAdvertisingSid();
        if (DBG) {
            Log.d(TAG, "startSync for Device: " + address + " sid: " + sid);
        }
        synchronized (mSyncs) {
            Map.Entry<IBinder, SyncInfo> entry = findMatchingSync(sid, address);
            if (entry != null) {
                //Found matching sync. Copy sync handle
                if (DBG) {
                    Log.d(TAG, "startSync: Matching entry found");
                }
                mSyncs.put(binder, new SyncInfo(entry.getValue().id, sid, address,
                        entry.getValue().skip, entry.getValue().timeout, deathRecipient,
                        callback));
                if (entry.getValue().id >= 0) {
                    try {
                        callback.onSyncEstablished(entry.getValue().id,
                                                   mAdapter.getRemoteDevice(address),
                                                   sid, entry.getValue().skip,
                                                   entry.getValue().timeout, 0 /*success*/);
                    } catch (RemoteException e) {
                        throw new IllegalArgumentException("Can't invoke callback");
                    }
                } else {
                    Log.d(TAG, "startSync(): sync pending for same remote");
                }
                return;
            }
        }


        int cbId = --sTempRegistrationId;
        int cbId = --sTempRegistrationId;
        mSyncs.put(binder, new SyncInfo(cbId, deathRecipient, callback));
        mSyncs.put(binder, new SyncInfo(cbId, sid, address, skip, timeout,
                deathRecipient, callback));


        if (DBG) {
        if (DBG) {
            Log.d(TAG, "startSync() - reg_id=" + cbId + ", callback: " + binder);
            Log.d(TAG, "startSync() - reg_id=" + cbId + ", callback: " + binder);
@@ -204,8 +312,10 @@ class PeriodicScanManager {
        if (DBG) {
        if (DBG) {
            Log.d(TAG, "stopSync() " + binder);
            Log.d(TAG, "stopSync() " + binder);
        }
        }

        SyncInfo sync = null;
        SyncInfo sync = mSyncs.remove(binder);
        synchronized (mSyncs) {
            sync = mSyncs.remove(binder);
        }
        if (sync == null) {
        if (sync == null) {
            Log.e(TAG, "stopSync() - no client found for callback");
            Log.e(TAG, "stopSync() - no client found for callback");
            return;
            return;
@@ -213,14 +323,65 @@ class PeriodicScanManager {


        Integer syncHandle = sync.id;
        Integer syncHandle = sync.id;
        binder.unlinkToDeath(sync.deathRecipient, 0);
        binder.unlinkToDeath(sync.deathRecipient, 0);
        Log.d(TAG, "stopSync: " + syncHandle);


        synchronized (mSyncs) {
            Map.Entry<IBinder, SyncInfo> entry = findSync(syncHandle);
            if (entry != null) {
                Log.d(TAG, "stopSync() - another app synced to same PA, not stopping sync");
                return;
            }
        }
        Log.d(TAG, "calling stopSyncNative: " + syncHandle.intValue());
        if (syncHandle < 0) {
        if (syncHandle < 0) {
            Log.i(TAG, "stopSync() - not finished registration yet");
            Log.i(TAG, "cancelSync() - sync not established yet");
            // Sync will be freed once initiated in onSyncStarted()
            cancelSyncNative(sync.advSid, sync.address);
        } else {
            stopSyncNative(syncHandle.intValue());
        }
    }

    void onSyncTransferredCallback(int paSource, int status, String bda) {
        Log.d(TAG, "onSyncTransferredCallback()");
        Map.Entry<IBinder, SyncTransferInfo> entry = findSyncTransfer(bda);
        if (entry != null) {
            mSyncTransfers.remove(entry);
            IPeriodicAdvertisingCallback callback = entry.getValue().callback;
            try {
                callback.onSyncTransferred(mAdapter.getRemoteDevice(bda), status);
            } catch (RemoteException e) {
                throw new IllegalArgumentException("Can't find callback for sync transfer");
            }
        }
    }

    void transferSync(BluetoothDevice bda, int serviceData, int syncHandle) {
        Log.d(TAG, "transferSync()");
        Map.Entry<IBinder, SyncInfo> entry = findSync(syncHandle);
        if (entry == null) {
            Log.d(TAG, "transferSync: callback not registered");
            return;
            return;
        }
        }
        //check for duplicate transfers
        mSyncTransfers.put(entry.getKey(), new SyncTransferInfo(bda.getAddress(),
                           entry.getValue().callback));
        syncTransferNative(PA_SOURCE_REMOTE, bda.getAddress(), serviceData, syncHandle);
    }


        stopSyncNative(syncHandle);
    void transferSetInfo(BluetoothDevice bda, int serviceData,
                  int advHandle, IPeriodicAdvertisingCallback callback) {
        SyncDeathRecipient deathRecipient = new SyncDeathRecipient(callback);
        IBinder binder = toBinder(callback);
        if (DBG) {
            Log.d(TAG, "transferSetInfo() " + binder);
        }
        try {
            binder.linkToDeath(deathRecipient, 0);
        } catch (RemoteException e) {
            throw new IllegalArgumentException("Can't link to periodic scanner death");
        }
        mSyncTransfers.put(binder, new SyncTransferInfo(bda.getAddress(), callback));
        transferSetInfoNative(PA_SOURCE_LOCAL, bda.getAddress(), serviceData, advHandle);
    }
    }


    static {
    static {
@@ -236,4 +397,12 @@ class PeriodicScanManager {
    private native void startSyncNative(int sid, String address, int skip, int timeout, int regId);
    private native void startSyncNative(int sid, String address, int skip, int timeout, int regId);


    private native void stopSyncNative(int syncHandle);
    private native void stopSyncNative(int syncHandle);

    private native void cancelSyncNative(int sid, String address);

    private native void syncTransferNative(int paSource, String address, int serviceData,
                                           int syncHandle);

    private native void transferSetInfoNative(int paSource, String address, int serviceData,
                                              int advHandle);
}
}
+9 −0
Original line number Original line Diff line number Diff line
@@ -78,4 +78,13 @@ public abstract class PeriodicAdvertisingCallback {
     */
     */
    public void onSyncLost(int syncHandle) {
    public void onSyncLost(int syncHandle) {
    }
    }

    /**
     * Callback when periodic sync transferred.
     *
     * @param device
     * @param status
     */
    public void onSyncTransferred(BluetoothDevice device, int status) {
    }
}
}
+83 −0
Original line number Original line Diff line number Diff line
@@ -16,6 +16,7 @@


package android.bluetooth.le;
package android.bluetooth.le;


import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
import android.annotation.SuppressLint;
import android.bluetooth.Attributable;
import android.bluetooth.Attributable;
@@ -215,6 +216,79 @@ public final class PeriodicAdvertisingManager {
        }
        }
    }
    }


    /**
     * Transfer periodic sync
     *
     * @hide
     */
    public void transferSync(BluetoothDevice bda, int serviceData, int syncHandle) {
        IBluetoothGatt gatt;
        try {
            gatt = mBluetoothManager.getBluetoothGatt();
        } catch (RemoteException e) {
            Log.e(TAG, "Failed to get Bluetooth gatt - ", e);
            PeriodicAdvertisingCallback callback = null;
            for (PeriodicAdvertisingCallback cb : mCallbackWrappers.keySet()) {
                callback = cb;
            }
            if (callback != null) {
                callback.onSyncTransferred(bda,
                        PeriodicAdvertisingCallback.SYNC_NO_RESOURCES);
            }
            return;
        }
        try {
            gatt.transferSync(bda, serviceData , syncHandle, mAttributionSource);
        } catch (RemoteException e) {
            Log.e(TAG, "Failed to register sync - ", e);
            return;
        }
    }

    /**
     * Transfer set info
     *
     * @hide
     */
    public void transferSetInfo(BluetoothDevice bda, int serviceData,
                                int advHandle, PeriodicAdvertisingCallback callback) {
        transferSetInfo(bda, serviceData, advHandle, callback, null);
    }

    /**
     * Transfer set info
     *
     * @hide
     */
    public void transferSetInfo(BluetoothDevice bda, int serviceData,
                                int advHandle, PeriodicAdvertisingCallback callback,
                                @Nullable Handler handler) {
        if (callback == null) {
            throw new IllegalArgumentException("callback can't be null");
        }
        IBluetoothGatt gatt;
        try {
            gatt = mBluetoothManager.getBluetoothGatt();
        } catch (RemoteException e) {
            Log.e(TAG, "Failed to get Bluetooth gatt - ", e);
            return;
        }
        if (handler == null) {
            handler = new Handler(Looper.getMainLooper());
        }
        IPeriodicAdvertisingCallback wrapper = wrap(callback, handler);
        if (wrapper == null) {
            throw new IllegalArgumentException("callback was not properly registered");
        }
        try {
            gatt.transferSetInfo(bda, serviceData , advHandle, wrapper, mAttributionSource);
        } catch (RemoteException e) {
            Log.e(TAG, "Failed to register sync - ", e);
            return;
        }

    }

    @SuppressLint("AndroidFrameworkBluetoothPermission")
    @SuppressLint("AndroidFrameworkBluetoothPermission")
    private IPeriodicAdvertisingCallback wrap(PeriodicAdvertisingCallback callback,
    private IPeriodicAdvertisingCallback wrap(PeriodicAdvertisingCallback callback,
            Handler handler) {
            Handler handler) {
@@ -259,6 +333,15 @@ public final class PeriodicAdvertisingManager {
                    }
                    }
                });
                });
            }
            }

            public void onSyncTransferred(BluetoothDevice device, int status) {
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        callback.onSyncTransferred(device, status);
                    }
                });
            }
        };
        };
    }
    }
}
}
Loading