package org.altbeacon.beacon.service.scanner;
import android.annotation.TargetApi;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.os.SystemClock;
import org.altbeacon.beacon.logging.LogManager;
import org.altbeacon.bluetooth.BluetoothCrashResolver;
@TargetApi(18)
public class CycledLeScannerForJellyBeanMr2 extends CycledLeScanner {
private static final String TAG = "CycledLeScannerForJellyBeanMr2";
private BluetoothAdapter.LeScanCallback leScanCallback;
public CycledLeScannerForJellyBeanMr2(Context context, long scanPeriod, long betweenScanPeriod, boolean backgroundFlag, CycledLeScanCallback cycledLeScanCallback, BluetoothCrashResolver crashResolver) {
super(context, scanPeriod, betweenScanPeriod, backgroundFlag, cycledLeScanCallback, crashResolver);
}
@Override
protected void stopScan() {
postStopLeScan();
}
@Override
protected boolean deferScanIfNeeded() {
long millisecondsUntilStart = mNextScanCycleStartTime - SystemClock.elapsedRealtime();
if (millisecondsUntilStart > 0) {
LogManager.d(TAG, "Waiting to start next Bluetooth scan for another %s milliseconds",
millisecondsUntilStart);
// Don't actually wait until the next scan time -- only wait up to 1 second. This
// allows us to start scanning sooner if a consumer enters the foreground and expects
// results more quickly.
if (mBackgroundFlag) {
setWakeUpAlarm();
}
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
scanLeDevice(true);
}
}, millisecondsUntilStart > 1000 ? 1000 : millisecondsUntilStart);
return true;
}
return false;
}
@Override
protected void startScan() {
postStartLeScan();
}
@Override
protected void finishScan() {
postStopLeScan();
mScanningPaused = true;
}
private void postStartLeScan() {
final BluetoothAdapter bluetoothAdapter = getBluetoothAdapter();
if (bluetoothAdapter == null) {
return;
}
final BluetoothAdapter.LeScanCallback leScanCallback = getLeScanCallback();
mScanHandler.removeCallbacksAndMessages(null);
mScanHandler.post(new Runnable() {
@Override
public void run() {
try {
//noinspection deprecation
bluetoothAdapter.startLeScan(leScanCallback);
} catch (Exception e) {
LogManager.e(e, TAG, "Internal Android exception in startLeScan()");
}
}
});
}
private void postStopLeScan() {
final BluetoothAdapter bluetoothAdapter = getBluetoothAdapter();
if (bluetoothAdapter == null) {
return;
}
final BluetoothAdapter.LeScanCallback leScanCallback = getLeScanCallback();
mScanHandler.removeCallbacksAndMessages(null);
mScanHandler.post(new Runnable() {
@Override
public void run() {
try {
//noinspection deprecation
bluetoothAdapter.stopLeScan(leScanCallback);
} catch (Exception e) {
LogManager.e(e, TAG, "Internal Android exception in stopLeScan()");
}
}
});
}
private BluetoothAdapter.LeScanCallback getLeScanCallback() {
if (leScanCallback == null) {
leScanCallback =
new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(final BluetoothDevice device, final int rssi,
final byte[] scanRecord) {
LogManager.d(TAG, "got record");
mCycledLeScanCallback.onLeScan(device, rssi, scanRecord);
mBluetoothCrashResolver.notifyScannedDevice(device, getLeScanCallback());
}
};
}
return leScanCallback;
}
}