26
26
import android .bluetooth .BluetoothAdapter ;
27
27
import android .bluetooth .le .BluetoothLeScanner ;
28
28
import android .bluetooth .le .ScanCallback ;
29
+ import android .bluetooth .le .ScanFilter ;
29
30
import android .bluetooth .le .ScanResult ;
30
31
import android .bluetooth .le .ScanSettings ;
31
32
import android .os .Build ;
32
33
34
+ import java .util .ArrayList ;
35
+ import java .util .List ;
33
36
import java .util .Locale ;
34
37
35
38
/**
36
39
* @see BootloaderScanner
37
40
*/
38
41
@ TargetApi (Build .VERSION_CODES .LOLLIPOP )
39
42
public class BootloaderScannerLollipop extends ScanCallback implements BootloaderScanner {
40
- private final Object mLock = new Object ();
41
- private String mDeviceAddress ;
42
- private String mDeviceAddressIncremented ;
43
- private String mBootloaderAddress ;
44
- private boolean mFound ;
45
-
46
- @ Override
47
- public String searchFor (final String deviceAddress ) {
48
- final String firstBytes = deviceAddress .substring (0 , 15 );
49
- final String lastByte = deviceAddress .substring (15 ); // assuming that the device address is correct
50
- final String lastByteIncremented = String .format (Locale .US , "%02X" , (Integer .valueOf (lastByte , 16 ) + ADDRESS_DIFF ) & 0xFF );
51
-
52
- mDeviceAddress = deviceAddress ;
53
- mDeviceAddressIncremented = firstBytes + lastByteIncremented ;
54
- mBootloaderAddress = null ;
55
- mFound = false ;
56
-
57
- // Add timeout
58
- new Thread (new Runnable () {
59
- @ Override
60
- public void run () {
61
- try {
62
- Thread .sleep (BootloaderScanner .TIMEOUT );
63
- } catch (final InterruptedException e ) {
64
- // do nothing
65
- }
66
-
67
- if (mFound )
68
- return ;
69
-
70
- mBootloaderAddress = null ;
71
- mFound = true ;
72
-
73
- // Notify the waiting thread
74
- synchronized (mLock ) {
75
- mLock .notifyAll ();
76
- }
77
- }
78
- }, "Scanner timer" ).start ();
79
-
80
- final BluetoothAdapter adapter = BluetoothAdapter .getDefaultAdapter ();
81
- if (adapter == null || adapter .getState () != BluetoothAdapter .STATE_ON )
82
- return null ;
83
- final BluetoothLeScanner scanner = adapter .getBluetoothLeScanner ();
84
- if (scanner == null )
85
- return null ;
86
- /*
87
- * Scanning with filters does not work on Nexus 9 (Android 5.1). No devices are found and scanner terminates on timeout.
88
- * We will match the device address in the callback method instead. It's not like it should be, but at least it works.
89
- */
90
- //final List<ScanFilter> filters = new ArrayList<>();
91
- //filters.add(new ScanFilter.Builder().setDeviceAddress(mDeviceAddress).build());
92
- //filters.add(new ScanFilter.Builder().setDeviceAddress(mDeviceAddressIncremented).build());
93
- final ScanSettings settings = new ScanSettings .Builder ().setScanMode (ScanSettings .SCAN_MODE_LOW_LATENCY ).build ();
94
- scanner .startScan (/*filters*/ null , settings , this );
95
-
96
- try {
97
- synchronized (mLock ) {
98
- while (!mFound )
99
- mLock .wait ();
100
- }
101
- } catch (final InterruptedException e ) {
102
- // do nothing
103
- }
104
-
105
- scanner .stopScan (this );
106
- return mBootloaderAddress ;
107
- }
108
-
109
- @ Override
110
- public void onScanResult (final int callbackType , final ScanResult result ) {
111
- final String address = result .getDevice ().getAddress ();
112
-
113
- if (mDeviceAddress .equals (address ) || mDeviceAddressIncremented .equals (address )) {
114
- mBootloaderAddress = address ;
115
- mFound = true ;
116
-
117
- // Notify the waiting thread
118
- synchronized (mLock ) {
119
- mLock .notifyAll ();
120
- }
121
- }
122
- }
43
+ private final Object mLock = new Object ();
44
+ private String mDeviceAddress ;
45
+ private String mDeviceAddressIncremented ;
46
+ private String mBootloaderAddress ;
47
+ private boolean mFound ;
48
+
49
+ @ Override
50
+ public String searchFor (final String deviceAddress ) {
51
+ final String firstBytes = deviceAddress .substring (0 , 15 );
52
+ final String lastByte = deviceAddress .substring (15 ); // assuming that the device address is correct
53
+ final String lastByteIncremented = String .format (Locale .US , "%02X" , (Integer .valueOf (lastByte , 16 ) + ADDRESS_DIFF ) & 0xFF );
54
+
55
+ mDeviceAddress = deviceAddress ;
56
+ mDeviceAddressIncremented = firstBytes + lastByteIncremented ;
57
+ mBootloaderAddress = null ;
58
+ mFound = false ;
59
+
60
+ // Add timeout
61
+ new Thread (new Runnable () {
62
+ @ Override
63
+ public void run () {
64
+ try {
65
+ Thread .sleep (BootloaderScanner .TIMEOUT );
66
+ } catch (final InterruptedException e ) {
67
+ // do nothing
68
+ }
69
+
70
+ if (mFound )
71
+ return ;
72
+
73
+ mBootloaderAddress = null ;
74
+ mFound = true ;
75
+
76
+ // Notify the waiting thread
77
+ synchronized (mLock ) {
78
+ mLock .notifyAll ();
79
+ }
80
+ }
81
+ }, "Scanner timer" ).start ();
82
+
83
+ final BluetoothAdapter adapter = BluetoothAdapter .getDefaultAdapter ();
84
+ if (adapter == null || adapter .getState () != BluetoothAdapter .STATE_ON )
85
+ return null ;
86
+ final BluetoothLeScanner scanner = adapter .getBluetoothLeScanner ();
87
+ if (scanner == null )
88
+ return null ;
89
+ /*
90
+ * Android 8.1 onwards, stops unfiltered BLE scanning on screen off. Therefore we must add a filter to
91
+ * get scan results in case the device screen is turned off as this may affect users wanting scan/connect to the device in background.
92
+ * See {@linktourl https://android.googlesource.com/platform/packages/apps/Bluetooth/+/319aeae6f4ebd13678b4f77375d1804978c4a1e1}
93
+ */
94
+ final ScanSettings settings = new ScanSettings .Builder ().setScanMode (ScanSettings .SCAN_MODE_LOW_LATENCY ).build ();
95
+ if (adapter .isOffloadedFilteringSupported () && Build .VERSION .SDK_INT >= Build .VERSION_CODES .O_MR1 ) {
96
+ final List <ScanFilter > filters = new ArrayList <>();
97
+ filters .add (new ScanFilter .Builder ().setDeviceAddress (mDeviceAddress ).build ());
98
+ filters .add (new ScanFilter .Builder ().setDeviceAddress (mDeviceAddressIncremented ).build ());
99
+ scanner .startScan (filters , settings , this );
100
+ } else {
101
+ /*
102
+ * Scanning with filters does not work on Nexus 9 (Android 5.1). No devices are found and scanner terminates on timeout.
103
+ * We will match the device address in the callback method instead. It's not like it should be, but at least it works.
104
+ */
105
+ scanner .startScan (null , settings , this );
106
+ }
107
+
108
+ try {
109
+ synchronized (mLock ) {
110
+ while (!mFound )
111
+ mLock .wait ();
112
+ }
113
+ } catch (final InterruptedException e ) {
114
+ // do nothing
115
+ }
116
+
117
+ scanner .stopScan (this );
118
+ return mBootloaderAddress ;
119
+ }
120
+
121
+ @ Override
122
+ public void onScanResult (final int callbackType , final ScanResult result ) {
123
+ final String address = result .getDevice ().getAddress ();
124
+
125
+ if (mDeviceAddress .equals (address ) || mDeviceAddressIncremented .equals (address )) {
126
+ mBootloaderAddress = address ;
127
+ mFound = true ;
128
+
129
+ // Notify the waiting thread
130
+ synchronized (mLock ) {
131
+ mLock .notifyAll ();
132
+ }
133
+ }
134
+ }
123
135
}
0 commit comments