Merge "Bluetooth 5 periodc scan API (1/2)"
This commit is contained in:
@@ -131,6 +131,7 @@ LOCAL_SRC_FILES += \
|
||||
core/java/android/bluetooth/IBluetoothGattCallback.aidl \
|
||||
core/java/android/bluetooth/IBluetoothGattServerCallback.aidl \
|
||||
core/java/android/bluetooth/le/IAdvertiserCallback.aidl \
|
||||
core/java/android/bluetooth/le/IPeriodicAdvertisingCallback.aidl \
|
||||
core/java/android/bluetooth/le/IScannerCallback.aidl \
|
||||
core/java/android/content/IClipboard.aidl \
|
||||
core/java/android/content/IContentService.aidl \
|
||||
|
||||
@@ -6695,6 +6695,7 @@ package android.bluetooth {
|
||||
method public java.util.Set<android.bluetooth.BluetoothDevice> getBondedDevices();
|
||||
method public static synchronized android.bluetooth.BluetoothAdapter getDefaultAdapter();
|
||||
method public java.lang.String getName();
|
||||
method public android.bluetooth.le.PeriodicAdvertisingManager getPeriodicAdvertisingManager();
|
||||
method public int getProfileConnectionState(int);
|
||||
method public boolean getProfileProxy(android.content.Context, android.bluetooth.BluetoothProfile.ServiceListener, int);
|
||||
method public android.bluetooth.BluetoothDevice getRemoteDevice(java.lang.String);
|
||||
@@ -7490,6 +7491,36 @@ package android.bluetooth.le {
|
||||
method public void stopScan(android.bluetooth.le.ScanCallback);
|
||||
}
|
||||
|
||||
public abstract class PeriodicAdvertisingCallback {
|
||||
ctor public PeriodicAdvertisingCallback();
|
||||
method public void onPeriodicAdvertisingReport(android.bluetooth.le.PeriodicAdvertisingReport);
|
||||
method public void onSyncEstablished(int, android.bluetooth.BluetoothDevice, int, int, int, int);
|
||||
method public void onSyncLost(int);
|
||||
field public static final int SYNC_NO_RESOURCES = 2; // 0x2
|
||||
field public static final int SYNC_NO_RESPONSE = 1; // 0x1
|
||||
}
|
||||
|
||||
public final class PeriodicAdvertisingManager {
|
||||
method public void registerSync(android.bluetooth.le.ScanResult, int, int, android.bluetooth.le.PeriodicAdvertisingCallback);
|
||||
method public void registerSync(android.bluetooth.le.ScanResult, int, int, android.bluetooth.le.PeriodicAdvertisingCallback, android.os.Handler);
|
||||
method public void unregisterSync(android.bluetooth.le.PeriodicAdvertisingCallback);
|
||||
}
|
||||
|
||||
public final class PeriodicAdvertisingReport implements android.os.Parcelable {
|
||||
ctor public PeriodicAdvertisingReport(int, int, int, int, android.bluetooth.le.ScanRecord);
|
||||
method public int describeContents();
|
||||
method public android.bluetooth.le.ScanRecord getData();
|
||||
method public int getDataStatus();
|
||||
method public int getRssi();
|
||||
method public int getSyncHandle();
|
||||
method public long getTimestampNanos();
|
||||
method public int getTxPower();
|
||||
method public void writeToParcel(android.os.Parcel, int);
|
||||
field public static final android.os.Parcelable.Creator<android.bluetooth.le.PeriodicAdvertisingReport> CREATOR;
|
||||
field public static final int DATA_COMPLETE = 0; // 0x0
|
||||
field public static final int DATA_INCOMPLETE_TRUNCATED = 2; // 0x2
|
||||
}
|
||||
|
||||
public abstract class ScanCallback {
|
||||
ctor public ScanCallback();
|
||||
method public void onBatchScanResults(java.util.List<android.bluetooth.le.ScanResult>);
|
||||
|
||||
@@ -6993,6 +6993,7 @@ package android.bluetooth {
|
||||
method public java.util.Set<android.bluetooth.BluetoothDevice> getBondedDevices();
|
||||
method public static synchronized android.bluetooth.BluetoothAdapter getDefaultAdapter();
|
||||
method public java.lang.String getName();
|
||||
method public android.bluetooth.le.PeriodicAdvertisingManager getPeriodicAdvertisingManager();
|
||||
method public int getProfileConnectionState(int);
|
||||
method public boolean getProfileProxy(android.content.Context, android.bluetooth.BluetoothProfile.ServiceListener, int);
|
||||
method public android.bluetooth.BluetoothDevice getRemoteDevice(java.lang.String);
|
||||
@@ -7797,6 +7798,36 @@ package android.bluetooth.le {
|
||||
method public void stopScan(android.bluetooth.le.ScanCallback);
|
||||
}
|
||||
|
||||
public abstract class PeriodicAdvertisingCallback {
|
||||
ctor public PeriodicAdvertisingCallback();
|
||||
method public void onPeriodicAdvertisingReport(android.bluetooth.le.PeriodicAdvertisingReport);
|
||||
method public void onSyncEstablished(int, android.bluetooth.BluetoothDevice, int, int, int, int);
|
||||
method public void onSyncLost(int);
|
||||
field public static final int SYNC_NO_RESOURCES = 2; // 0x2
|
||||
field public static final int SYNC_NO_RESPONSE = 1; // 0x1
|
||||
}
|
||||
|
||||
public final class PeriodicAdvertisingManager {
|
||||
method public void registerSync(android.bluetooth.le.ScanResult, int, int, android.bluetooth.le.PeriodicAdvertisingCallback);
|
||||
method public void registerSync(android.bluetooth.le.ScanResult, int, int, android.bluetooth.le.PeriodicAdvertisingCallback, android.os.Handler);
|
||||
method public void unregisterSync(android.bluetooth.le.PeriodicAdvertisingCallback);
|
||||
}
|
||||
|
||||
public final class PeriodicAdvertisingReport implements android.os.Parcelable {
|
||||
ctor public PeriodicAdvertisingReport(int, int, int, int, android.bluetooth.le.ScanRecord);
|
||||
method public int describeContents();
|
||||
method public android.bluetooth.le.ScanRecord getData();
|
||||
method public int getDataStatus();
|
||||
method public int getRssi();
|
||||
method public int getSyncHandle();
|
||||
method public long getTimestampNanos();
|
||||
method public int getTxPower();
|
||||
method public void writeToParcel(android.os.Parcel, int);
|
||||
field public static final android.os.Parcelable.Creator<android.bluetooth.le.PeriodicAdvertisingReport> CREATOR;
|
||||
field public static final int DATA_COMPLETE = 0; // 0x0
|
||||
field public static final int DATA_INCOMPLETE_TRUNCATED = 2; // 0x2
|
||||
}
|
||||
|
||||
public final class ResultStorageDescriptor implements android.os.Parcelable {
|
||||
ctor public ResultStorageDescriptor(int, int, int);
|
||||
method public int describeContents();
|
||||
|
||||
@@ -6704,6 +6704,7 @@ package android.bluetooth {
|
||||
method public java.util.Set<android.bluetooth.BluetoothDevice> getBondedDevices();
|
||||
method public static synchronized android.bluetooth.BluetoothAdapter getDefaultAdapter();
|
||||
method public java.lang.String getName();
|
||||
method public android.bluetooth.le.PeriodicAdvertisingManager getPeriodicAdvertisingManager();
|
||||
method public int getProfileConnectionState(int);
|
||||
method public boolean getProfileProxy(android.content.Context, android.bluetooth.BluetoothProfile.ServiceListener, int);
|
||||
method public android.bluetooth.BluetoothDevice getRemoteDevice(java.lang.String);
|
||||
@@ -7499,6 +7500,36 @@ package android.bluetooth.le {
|
||||
method public void stopScan(android.bluetooth.le.ScanCallback);
|
||||
}
|
||||
|
||||
public abstract class PeriodicAdvertisingCallback {
|
||||
ctor public PeriodicAdvertisingCallback();
|
||||
method public void onPeriodicAdvertisingReport(android.bluetooth.le.PeriodicAdvertisingReport);
|
||||
method public void onSyncEstablished(int, android.bluetooth.BluetoothDevice, int, int, int, int);
|
||||
method public void onSyncLost(int);
|
||||
field public static final int SYNC_NO_RESOURCES = 2; // 0x2
|
||||
field public static final int SYNC_NO_RESPONSE = 1; // 0x1
|
||||
}
|
||||
|
||||
public final class PeriodicAdvertisingManager {
|
||||
method public void registerSync(android.bluetooth.le.ScanResult, int, int, android.bluetooth.le.PeriodicAdvertisingCallback);
|
||||
method public void registerSync(android.bluetooth.le.ScanResult, int, int, android.bluetooth.le.PeriodicAdvertisingCallback, android.os.Handler);
|
||||
method public void unregisterSync(android.bluetooth.le.PeriodicAdvertisingCallback);
|
||||
}
|
||||
|
||||
public final class PeriodicAdvertisingReport implements android.os.Parcelable {
|
||||
ctor public PeriodicAdvertisingReport(int, int, int, int, android.bluetooth.le.ScanRecord);
|
||||
method public int describeContents();
|
||||
method public android.bluetooth.le.ScanRecord getData();
|
||||
method public int getDataStatus();
|
||||
method public int getRssi();
|
||||
method public int getSyncHandle();
|
||||
method public long getTimestampNanos();
|
||||
method public int getTxPower();
|
||||
method public void writeToParcel(android.os.Parcel, int);
|
||||
field public static final android.os.Parcelable.Creator<android.bluetooth.le.PeriodicAdvertisingReport> CREATOR;
|
||||
field public static final int DATA_COMPLETE = 0; // 0x0
|
||||
field public static final int DATA_INCOMPLETE_TRUNCATED = 2; // 0x2
|
||||
}
|
||||
|
||||
public abstract class ScanCallback {
|
||||
ctor public ScanCallback();
|
||||
method public void onBatchScanResults(java.util.List<android.bluetooth.le.ScanResult>);
|
||||
|
||||
@@ -26,6 +26,7 @@ import android.annotation.SystemApi;
|
||||
import android.app.ActivityThread;
|
||||
import android.bluetooth.le.BluetoothLeAdvertiser;
|
||||
import android.bluetooth.le.BluetoothLeScanner;
|
||||
import android.bluetooth.le.PeriodicAdvertisingManager;
|
||||
import android.bluetooth.le.ScanCallback;
|
||||
import android.bluetooth.le.ScanFilter;
|
||||
import android.bluetooth.le.ScanRecord;
|
||||
@@ -525,6 +526,7 @@ public final class BluetoothAdapter {
|
||||
|
||||
private static BluetoothLeScanner sBluetoothLeScanner;
|
||||
private static BluetoothLeAdvertiser sBluetoothLeAdvertiser;
|
||||
private static PeriodicAdvertisingManager sPeriodicAdvertisingManager;
|
||||
|
||||
private final IBluetoothManager mManagerService;
|
||||
private IBluetooth mService;
|
||||
@@ -629,6 +631,30 @@ public final class BluetoothAdapter {
|
||||
return sBluetoothLeAdvertiser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link PeriodicAdvertisingManager} object for Bluetooth LE Periodic Advertising
|
||||
* operations. Will return null if Bluetooth is turned off or if Bluetooth LE Periodic
|
||||
* Advertising is not supported on this device.
|
||||
* <p>
|
||||
* Use {@link #isLePeriodicAdvertisingSupported()} to check whether LE Periodic Advertising is
|
||||
* supported on this device before calling this method.
|
||||
*/
|
||||
public PeriodicAdvertisingManager getPeriodicAdvertisingManager() {
|
||||
if (!getLeAccess())
|
||||
return null;
|
||||
|
||||
if (!isLePeriodicAdvertisingSupported())
|
||||
return null;
|
||||
|
||||
synchronized (mLock) {
|
||||
if (sPeriodicAdvertisingManager == null) {
|
||||
sPeriodicAdvertisingManager =
|
||||
new PeriodicAdvertisingManager(mManagerService);
|
||||
}
|
||||
}
|
||||
return sPeriodicAdvertisingManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link BluetoothLeScanner} object for Bluetooth LE scan operations.
|
||||
*/
|
||||
|
||||
@@ -21,6 +21,7 @@ import android.bluetooth.BluetoothGattService;
|
||||
import android.bluetooth.le.AdvertiseSettings;
|
||||
import android.bluetooth.le.AdvertiseData;
|
||||
import android.bluetooth.le.ScanFilter;
|
||||
import android.bluetooth.le.ScanResult;
|
||||
import android.bluetooth.le.ScanSettings;
|
||||
import android.bluetooth.le.ResultStorageDescriptor;
|
||||
import android.os.ParcelUuid;
|
||||
@@ -29,6 +30,7 @@ import android.os.WorkSource;
|
||||
import android.bluetooth.IBluetoothGattCallback;
|
||||
import android.bluetooth.IBluetoothGattServerCallback;
|
||||
import android.bluetooth.le.IAdvertiserCallback;
|
||||
import android.bluetooth.le.IPeriodicAdvertisingCallback;
|
||||
import android.bluetooth.le.IScannerCallback;
|
||||
|
||||
/**
|
||||
@@ -53,6 +55,9 @@ interface IBluetoothGatt {
|
||||
in AdvertiseSettings settings);
|
||||
void stopMultiAdvertising(in int advertiserId);
|
||||
|
||||
void registerSync(in ScanResult scanResult, in int skip, in int timeout, in IPeriodicAdvertisingCallback callback);
|
||||
void unregisterSync(in IPeriodicAdvertisingCallback callback);
|
||||
|
||||
void registerClient(in ParcelUuid appId, in IBluetoothGattCallback callback);
|
||||
void unregisterClient(in int clientIf);
|
||||
void clientConnect(in int clientIf, in String address, in boolean isDirect, in int transport);
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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 android.bluetooth.le;
|
||||
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.le.PeriodicAdvertisingReport;
|
||||
|
||||
/**
|
||||
* Callback definitions for interacting with Periodic Advertising
|
||||
* @hide
|
||||
*/
|
||||
oneway interface IPeriodicAdvertisingCallback {
|
||||
|
||||
void onSyncEstablished(in int syncHandle, in BluetoothDevice device, in int advertisingSid,
|
||||
in int skip, in int timeout, in int status);
|
||||
void onPeriodicAdvertisingReport(in PeriodicAdvertisingReport report);
|
||||
void onSyncLost(in int syncHandle);
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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 android.bluetooth.le;
|
||||
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
|
||||
/**
|
||||
* Bluetooth LE periodic advertising callbacks, used to deliver periodic
|
||||
* advertising operation status.
|
||||
*
|
||||
* @see PeriodicAdvertisingManager#createSync
|
||||
*/
|
||||
public abstract class PeriodicAdvertisingCallback {
|
||||
|
||||
/**
|
||||
* The requested operation was successful.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static final int SYNC_SUCCESS = 0;
|
||||
|
||||
/**
|
||||
* Sync failed to be established because remote device did not respond.
|
||||
*/
|
||||
public static final int SYNC_NO_RESPONSE = 1;
|
||||
|
||||
/**
|
||||
* Sync failed to be established because controller can't support more syncs.
|
||||
*/
|
||||
public static final int SYNC_NO_RESOURCES = 2;
|
||||
|
||||
|
||||
/**
|
||||
* Callback when synchronization was established.
|
||||
*
|
||||
* @param syncHandle handle used to identify this synchronization.
|
||||
* @param device remote device.
|
||||
* @param advertisingSid synchronized advertising set id.
|
||||
* @param skip The number of periodic advertising packets that can be skipped
|
||||
* after a successful receive in force. @see PeriodicAdvertisingManager#createSync
|
||||
* @param timeout Synchronization timeout for the periodic advertising in force. One
|
||||
* unit is 10ms. @see PeriodicAdvertisingManager#createSync
|
||||
* @param timeout
|
||||
* @param status operation status.
|
||||
*/
|
||||
public void onSyncEstablished(int syncHandle, BluetoothDevice device,
|
||||
int advertisingSid, int skip, int timeout,
|
||||
int status) {}
|
||||
|
||||
/**
|
||||
* Callback when periodic advertising report is received.
|
||||
*
|
||||
* @param report periodic advertising report.
|
||||
*/
|
||||
public void onPeriodicAdvertisingReport(PeriodicAdvertisingReport report) {}
|
||||
|
||||
/**
|
||||
* Callback when periodic advertising synchronization was lost.
|
||||
*
|
||||
* @param syncHandle handle used to identify this synchronization.
|
||||
*/
|
||||
public void onSyncLost(int syncHandle) {}
|
||||
}
|
||||
237
core/java/android/bluetooth/le/PeriodicAdvertisingManager.java
Normal file
237
core/java/android/bluetooth/le/PeriodicAdvertisingManager.java
Normal file
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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 android.bluetooth.le;
|
||||
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.IBluetoothGatt;
|
||||
import android.bluetooth.IBluetoothManager;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* This class provides methods to perform periodic advertising related
|
||||
* operations. An application can register for periodic advertisements using
|
||||
* {@link PeriodicAdvertisingManager#registerSync}.
|
||||
* <p>
|
||||
* Use {@link BluetoothAdapter#getPeriodicAdvertisingManager()} to get an
|
||||
* instance of {@link PeriodicAdvertisingManager}.
|
||||
* <p>
|
||||
* <b>Note:</b> Most of the methods here require
|
||||
* {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
|
||||
*/
|
||||
public final class PeriodicAdvertisingManager {
|
||||
|
||||
private static final String TAG = "PeriodicAdvertisingManager";
|
||||
|
||||
private static final int SKIP_MIN = 0;
|
||||
private static final int SKIP_MAX = 499;
|
||||
private static final int TIMEOUT_MIN = 10;
|
||||
private static final int TIMEOUT_MAX = 16384;
|
||||
|
||||
private static final int SYNC_STARTING = -1;
|
||||
|
||||
private final IBluetoothManager mBluetoothManager;
|
||||
private BluetoothAdapter mBluetoothAdapter;
|
||||
|
||||
/* maps callback, to callback wrapper and sync handle */
|
||||
Map<PeriodicAdvertisingCallback,
|
||||
IPeriodicAdvertisingCallback /* callbackWrapper */> callbackWrappers;
|
||||
|
||||
/**
|
||||
* Use {@link BluetoothAdapter#getBluetoothLeScanner()} instead.
|
||||
*
|
||||
* @param bluetoothManager BluetoothManager that conducts overall Bluetooth Management.
|
||||
* @hide
|
||||
*/
|
||||
public PeriodicAdvertisingManager(IBluetoothManager bluetoothManager) {
|
||||
mBluetoothManager = bluetoothManager;
|
||||
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
|
||||
callbackWrappers = new IdentityHashMap<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronize with periodic advertising pointed to by the {@code scanResult}.
|
||||
* The {@code scanResult} used must contain a valid advertisingSid. First
|
||||
* call to registerSync will use the {@code skip} and {@code timeout} provided.
|
||||
* Subsequent calls from other apps, trying to sync with same set will reuse
|
||||
* existing sync, thus {@code skip} and {@code timeout} values will not take
|
||||
* effect. The values in effect will be returned in
|
||||
* {@link PeriodicAdvertisingCallback#onSyncEstablished}.
|
||||
*
|
||||
* @param scanResult Scan result containing advertisingSid.
|
||||
* @param skip The number of periodic advertising packets that can be skipped
|
||||
* after a successful receive. Must be between 0 and 499.
|
||||
* @param timeout Synchronization timeout for the periodic advertising. One
|
||||
* unit is 10ms. Must be between 10 (100ms) and 16384 (163.84s).
|
||||
* @param callback Callback used to deliver all operations status.
|
||||
* @throws IllegalArgumentException if {@code scanResult} is null or {@code
|
||||
* skip} is invalid or {@code timeout} is invalid or {@code callback} is null.
|
||||
*/
|
||||
public void registerSync(ScanResult scanResult, int skip, int timeout,
|
||||
PeriodicAdvertisingCallback callback) {
|
||||
registerSync(scanResult, skip, timeout, callback, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronize with periodic advertising pointed to by the {@code scanResult}.
|
||||
* The {@code scanResult} used must contain a valid advertisingSid. First
|
||||
* call to registerSync will use the {@code skip} and {@code timeout} provided.
|
||||
* Subsequent calls from other apps, trying to sync with same set will reuse
|
||||
* existing sync, thus {@code skip} and {@code timeout} values will not take
|
||||
* effect. The values in effect will be returned in
|
||||
* {@link PeriodicAdvertisingCallback#onSyncEstablished}.
|
||||
*
|
||||
* @param scanResult Scan result containing advertisingSid.
|
||||
* @param skip The number of periodic advertising packets that can be skipped
|
||||
* after a successful receive. Must be between 0 and 499.
|
||||
* @param timeout Synchronization timeout for the periodic advertising. One
|
||||
* unit is 10ms. Must be between 10 (100ms) and 16384 (163.84s).
|
||||
* @param callback Callback used to deliver all operations status.
|
||||
* @param handler thread upon which the callbacks will be invoked.
|
||||
* @throws IllegalArgumentException if {@code scanResult} is null or {@code
|
||||
* skip} is invalid or {@code timeout} is invalid or {@code callback} is null.
|
||||
*/
|
||||
public void registerSync(ScanResult scanResult, int skip, int timeout,
|
||||
PeriodicAdvertisingCallback callback, Handler handler) {
|
||||
if (callback == null) {
|
||||
throw new IllegalArgumentException("callback can't be null");
|
||||
}
|
||||
|
||||
if (scanResult == null) {
|
||||
throw new IllegalArgumentException("scanResult can't be null");
|
||||
}
|
||||
|
||||
if (scanResult.getAdvertisingSid() == ScanResult.SID_NOT_PRESENT) {
|
||||
throw new IllegalArgumentException("scanResult must contain a valid sid");
|
||||
}
|
||||
|
||||
if (skip < SKIP_MIN || skip > SKIP_MAX) {
|
||||
throw new IllegalArgumentException(
|
||||
"timeout must be between " + TIMEOUT_MIN + " and " + TIMEOUT_MAX);
|
||||
}
|
||||
|
||||
if (timeout < TIMEOUT_MIN || timeout > TIMEOUT_MAX) {
|
||||
throw new IllegalArgumentException(
|
||||
"timeout must be between " + TIMEOUT_MIN + " and " + TIMEOUT_MAX);
|
||||
}
|
||||
|
||||
IBluetoothGatt gatt;
|
||||
try {
|
||||
gatt = mBluetoothManager.getBluetoothGatt();
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Failed to get Bluetooth gatt - ", e);
|
||||
callback.onSyncEstablished(0, scanResult.getDevice(), scanResult.getAdvertisingSid(),
|
||||
skip, timeout,
|
||||
PeriodicAdvertisingCallback.SYNC_NO_RESOURCES);
|
||||
return;
|
||||
}
|
||||
|
||||
if (handler == null)
|
||||
handler = new Handler(Looper.getMainLooper());
|
||||
|
||||
IPeriodicAdvertisingCallback wrapped = wrap(callback, handler);
|
||||
callbackWrappers.put(callback, wrapped);
|
||||
|
||||
try {
|
||||
gatt.registerSync(scanResult, skip, timeout, wrapped);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Failed to register sync - ", e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel pending attempt to create sync, or terminate existing sync.
|
||||
*
|
||||
* @param callback Callback used to deliver all operations status.
|
||||
* @throws IllegalArgumentException if {@code callback} is null, or not a properly
|
||||
* registered callback.
|
||||
*/
|
||||
public void unregisterSync(PeriodicAdvertisingCallback callback) {
|
||||
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;
|
||||
}
|
||||
|
||||
IPeriodicAdvertisingCallback wrapper = callbackWrappers.remove(callback);
|
||||
if (wrapper == null) {
|
||||
throw new IllegalArgumentException("callback was not properly registered");
|
||||
}
|
||||
|
||||
try {
|
||||
gatt.unregisterSync(wrapper);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Failed to cancel sync creation - ", e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private IPeriodicAdvertisingCallback wrap(PeriodicAdvertisingCallback callback, Handler handler) {
|
||||
return new IPeriodicAdvertisingCallback.Stub() {
|
||||
public void onSyncEstablished(int syncHandle, BluetoothDevice device,
|
||||
int advertisingSid, int skip, int timeout, int status) {
|
||||
|
||||
handler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
callback.onSyncEstablished(syncHandle, device, advertisingSid, skip, timeout,
|
||||
status);
|
||||
|
||||
if (status != PeriodicAdvertisingCallback.SYNC_SUCCESS) {
|
||||
// App can still unregister the sync until notified it failed. Remove callback
|
||||
// after app was notifed.
|
||||
callbackWrappers.remove(callback);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void onPeriodicAdvertisingReport(PeriodicAdvertisingReport report) {
|
||||
handler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
callback.onPeriodicAdvertisingReport(report);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void onSyncLost(int syncHandle) {
|
||||
handler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
callback.onSyncLost(syncHandle);
|
||||
// App can still unregister the sync until notified it's lost. Remove callback after
|
||||
// app was notifed.
|
||||
callbackWrappers.remove(callback);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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 android.bluetooth.le;
|
||||
|
||||
parcelable PeriodicAdvertisingReport;
|
||||
184
core/java/android/bluetooth/le/PeriodicAdvertisingReport.java
Normal file
184
core/java/android/bluetooth/le/PeriodicAdvertisingReport.java
Normal file
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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 android.bluetooth.le;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* PeriodicAdvertisingReport for Bluetooth LE synchronized advertising.
|
||||
*/
|
||||
public final class PeriodicAdvertisingReport implements Parcelable {
|
||||
|
||||
/**
|
||||
* The data returned is complete
|
||||
*/
|
||||
public static final int DATA_COMPLETE = 0;
|
||||
|
||||
/**
|
||||
* The data returned is incomplete. The controller was unsuccessfull to
|
||||
* receive all chained packets, returning only partial data.
|
||||
*/
|
||||
public static final int DATA_INCOMPLETE_TRUNCATED = 2;
|
||||
|
||||
private int syncHandle;
|
||||
private int txPower;
|
||||
private int rssi;
|
||||
private int dataStatus;
|
||||
|
||||
// periodic advertising data.
|
||||
@Nullable
|
||||
private ScanRecord data;
|
||||
|
||||
// Device timestamp when the result was last seen.
|
||||
private long timestampNanos;
|
||||
|
||||
/**
|
||||
* Constructor of periodic advertising result.
|
||||
*
|
||||
*/
|
||||
public PeriodicAdvertisingReport(int syncHandle, int txPower, int rssi,
|
||||
int dataStatus, ScanRecord data) {
|
||||
this.syncHandle = syncHandle;
|
||||
this.txPower = txPower;
|
||||
this.rssi = rssi;
|
||||
this.dataStatus = dataStatus;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
private PeriodicAdvertisingReport(Parcel in) {
|
||||
readFromParcel(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeInt(syncHandle);
|
||||
dest.writeLong(txPower);
|
||||
dest.writeInt(rssi);
|
||||
dest.writeInt(dataStatus);
|
||||
if (data != null) {
|
||||
dest.writeInt(1);
|
||||
dest.writeByteArray(data.getBytes());
|
||||
} else {
|
||||
dest.writeInt(0);
|
||||
}
|
||||
}
|
||||
|
||||
private void readFromParcel(Parcel in) {
|
||||
syncHandle = in.readInt();
|
||||
txPower = in.readInt();
|
||||
rssi = in.readInt();
|
||||
dataStatus = in.readInt();
|
||||
if (in.readInt() == 1) {
|
||||
data = ScanRecord.parseFromBytes(in.createByteArray());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the synchronization handle.
|
||||
*/
|
||||
public int getSyncHandle() {
|
||||
return syncHandle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the transmit power in dBm. The valid range is [-127, 126]. Value
|
||||
* of 127 means information was not available.
|
||||
*/
|
||||
public int getTxPower() {
|
||||
return txPower;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the received signal strength in dBm. The valid range is [-127, 20].
|
||||
*/
|
||||
public int getRssi() {
|
||||
return rssi;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the data status. Can be one of {@link PeriodicAdvertisingReport#DATA_COMPLETE}
|
||||
* or {@link PeriodicAdvertisingReport#DATA_INCOMPLETE_TRUNCATED}.
|
||||
*/
|
||||
public int getDataStatus() {
|
||||
return dataStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the data contained in this periodic advertising report.
|
||||
*/
|
||||
@Nullable
|
||||
public ScanRecord getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns timestamp since boot when the scan record was observed.
|
||||
*/
|
||||
public long getTimestampNanos() {
|
||||
return timestampNanos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(syncHandle, txPower, rssi, dataStatus, data, timestampNanos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null || getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
PeriodicAdvertisingReport other = (PeriodicAdvertisingReport) obj;
|
||||
return (syncHandle == other.syncHandle) &&
|
||||
(txPower == other.txPower) &&
|
||||
(rssi == other.rssi) &&
|
||||
(dataStatus == other.dataStatus) &&
|
||||
Objects.equals(data, other.data) &&
|
||||
(timestampNanos == other.timestampNanos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PeriodicAdvertisingReport{syncHandle=" + syncHandle +
|
||||
", txPower=" + txPower + ", rssi=" + rssi + ", dataStatus=" + dataStatus +
|
||||
", data=" + Objects.toString(data) + ", timestampNanos=" + timestampNanos + '}';
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<PeriodicAdvertisingReport> CREATOR = new Creator<PeriodicAdvertisingReport>() {
|
||||
@Override
|
||||
public PeriodicAdvertisingReport createFromParcel(Parcel source) {
|
||||
return new PeriodicAdvertisingReport(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PeriodicAdvertisingReport[] newArray(int size) {
|
||||
return new PeriodicAdvertisingReport[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user