OLD | NEW |
---|---|
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 package org.chromium.device.bluetooth; | 5 package org.chromium.device.bluetooth; |
6 | 6 |
7 import android.Manifest; | 7 import android.Manifest; |
8 import android.bluetooth.le.ScanCallback; | |
9 import android.bluetooth.le.ScanResult; | |
10 import android.bluetooth.le.ScanSettings; | |
8 import android.content.Context; | 11 import android.content.Context; |
9 import android.content.ContextWrapper; | 12 import android.content.ContextWrapper; |
10 import android.content.pm.PackageManager; | 13 import android.content.pm.PackageManager; |
14 import android.os.Build; | |
11 | 15 |
12 import org.chromium.base.CalledByNative; | 16 import org.chromium.base.CalledByNative; |
13 import org.chromium.base.JNINamespace; | 17 import org.chromium.base.JNINamespace; |
14 import org.chromium.base.Log; | 18 import org.chromium.base.Log; |
15 | 19 |
20 import java.util.List; | |
21 | |
16 /** | 22 /** |
17 * Exposes android.bluetooth.BluetoothAdapter as necessary for C++ | 23 * Exposes android.bluetooth.BluetoothAdapter as necessary for C++ |
18 * device::BluetoothAdapterAndroid. | 24 * device::BluetoothAdapterAndroid. |
19 */ | 25 */ |
20 @JNINamespace("device") | 26 @JNINamespace("device") |
21 final class BluetoothAdapter { | 27 final class BluetoothAdapter { |
22 private static final String TAG = Log.makeTag("Bluetooth"); | 28 private static final String TAG = Log.makeTag("Bluetooth"); |
23 | 29 |
24 private final boolean mHasBluetoothPermission; | 30 private final boolean mHasBluetoothCapability; |
25 private android.bluetooth.BluetoothAdapter mAdapter; | 31 private android.bluetooth.BluetoothAdapter mAdapter; |
32 private int mNumDiscoverySessions = 0; | |
33 private ScanCallback mLeScanCallback; | |
34 | |
35 // ------------------------------------------------------------------------- -------------------- | |
36 // Construction: | |
26 | 37 |
27 @CalledByNative | 38 @CalledByNative |
28 private static BluetoothAdapter create(Context context) { | 39 private static BluetoothAdapter create(Context context) { |
29 return new BluetoothAdapter(context); | 40 return new BluetoothAdapter(context); |
30 } | 41 } |
31 | 42 |
32 @CalledByNative | 43 @CalledByNative |
33 private static BluetoothAdapter createWithoutPermissionForTesting(Context co ntext) { | 44 private static BluetoothAdapter createWithoutPermissionForTesting(Context co ntext) { |
34 Context contextWithoutPermission = new ContextWrapper(context) { | 45 Context contextWithoutPermission = new ContextWrapper(context) { |
35 @Override | 46 @Override |
36 public int checkCallingOrSelfPermission(String permission) { | 47 public int checkCallingOrSelfPermission(String permission) { |
37 return PackageManager.PERMISSION_DENIED; | 48 return PackageManager.PERMISSION_DENIED; |
38 } | 49 } |
39 }; | 50 }; |
40 return new BluetoothAdapter(contextWithoutPermission); | 51 return new BluetoothAdapter(contextWithoutPermission); |
41 } | 52 } |
42 | 53 |
43 // Constructs a BluetoothAdapter. | 54 // Constructs a BluetoothAdapter. |
44 private BluetoothAdapter(Context context) { | 55 private BluetoothAdapter(Context context) { |
45 mHasBluetoothPermission = | 56 final boolean hasMinAPI = Build.VERSION.SDK_INT >= Build.VERSION_CODES.L OLLIPOP; |
57 final boolean hasPermissions = | |
46 context.checkCallingOrSelfPermission(Manifest.permission.BLUETOO TH) | 58 context.checkCallingOrSelfPermission(Manifest.permission.BLUETOO TH) |
47 == PackageManager.PERMISSION_GRANTED | 59 == PackageManager.PERMISSION_GRANTED |
48 && context.checkCallingOrSelfPermission(Manifest.permission.BLUE TOOTH_ADMIN) | 60 && context.checkCallingOrSelfPermission(Manifest.permission.BLUE TOOTH_ADMIN) |
49 == PackageManager.PERMISSION_GRANTED; | 61 == PackageManager.PERMISSION_GRANTED; |
50 if (!mHasBluetoothPermission) { | 62 final boolean hasLowEnergyFeature = |
51 Log.w(TAG, | 63 context.getPackageManager().hasSystemFeature(PackageManager.FEAT URE_BLUETOOTH_LE); |
52 "Bluetooth API disabled; BLUETOOTH and BLUETOOTH_ADMIN permi ssions required."); | 64 mHasBluetoothCapability = hasMinAPI && hasPermissions && hasLowEnergyFea ture; |
65 if (!mHasBluetoothCapability) { | |
66 if (!hasMinAPI) { | |
67 Log.i(TAG, "Bluetooth API disabled; SDK version (%d) too low.", | |
ortuno
2015/05/21 16:48:53
You are logging a lot of stuff. We should probably
scheib
2015/05/22 01:26:46
I've moved the verbose bits to .d and .v, which ar
| |
68 Build.VERSION.SDK_INT); | |
69 } else if (!hasPermissions) { | |
70 Log.w(TAG, "Bluetooth API disabled; BLUETOOTH and BLUETOOTH_ADMI N permissions " | |
71 + "required."); | |
72 } else if (!hasLowEnergyFeature) { | |
73 Log.i(TAG, "Bluetooth API disabled; Low Energy not supported on system."); | |
74 } | |
53 return; | 75 return; |
54 } | 76 } |
55 | 77 |
56 mAdapter = android.bluetooth.BluetoothAdapter.getDefaultAdapter(); | 78 mAdapter = android.bluetooth.BluetoothAdapter.getDefaultAdapter(); |
57 if (mAdapter == null) Log.i(TAG, "No adapter found."); | 79 if (mAdapter == null) { |
58 } | 80 Log.i(TAG, "No adapter found."); |
59 | 81 } else { |
60 @CalledByNative | 82 Log.i(TAG, "BluetoothAdapter successfully constructed."); |
61 private boolean hasBluetoothPermission() { | 83 } |
62 return mHasBluetoothPermission; | |
63 } | 84 } |
64 | 85 |
65 // ------------------------------------------------------------------------- -------------------- | 86 // ------------------------------------------------------------------------- -------------------- |
66 // BluetoothAdapterAndroid.h interface: | 87 // Accessors @CalledByNative for BluetoothAdapterAndroid: |
88 | |
89 @CalledByNative | |
90 private boolean hasBluetoothCapability() { | |
91 return mHasBluetoothCapability; | |
92 } | |
93 | |
94 // ------------------------------------------------------------------------- -------------------- | |
95 // BluetoothAdapterAndroid interface @CalledByNative for BluetoothAdapterAnd roid: | |
67 | 96 |
68 @CalledByNative | 97 @CalledByNative |
69 private String getAddress() { | 98 private String getAddress() { |
70 if (isPresent()) { | 99 if (isPresent()) { |
71 return mAdapter.getAddress(); | 100 return mAdapter.getAddress(); |
72 } else { | 101 } else { |
73 return ""; | 102 return ""; |
74 } | 103 } |
75 } | 104 } |
76 | 105 |
(...skipping 20 matching lines...) Expand all Loading... | |
97 private boolean isDiscoverable() { | 126 private boolean isDiscoverable() { |
98 return isPresent() | 127 return isPresent() |
99 && mAdapter.getScanMode() | 128 && mAdapter.getScanMode() |
100 == android.bluetooth.BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISC OVERABLE; | 129 == android.bluetooth.BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISC OVERABLE; |
101 } | 130 } |
102 | 131 |
103 @CalledByNative | 132 @CalledByNative |
104 private boolean isDiscovering() { | 133 private boolean isDiscovering() { |
105 return isPresent() && mAdapter.isDiscovering(); | 134 return isPresent() && mAdapter.isDiscovering(); |
106 } | 135 } |
136 | |
137 @CalledByNative | |
138 private boolean addDiscoverySession() { | |
ortuno
2015/05/21 16:48:53
nit: Add a comment for this function.
scheib
2015/05/22 01:26:46
Done.
| |
139 if (!isPowered()) { | |
140 Log.i(TAG, "addDiscoverySession: Fails: !isPowered"); | |
141 return false; | |
142 } | |
143 | |
144 if (mNumDiscoverySessions > 0) { | |
145 Log.i(TAG, "addDiscoverySession: Already scanning."); | |
146 return true; | |
147 } | |
148 Log.i(TAG, "addDiscoverySession"); | |
149 mNumDiscoverySessions++; | |
150 | |
151 ScanSettings.Builder scanSettingsBuilder = new ScanSettings.Builder(); | |
ortuno
2015/05/21 16:48:53
I would refactor this a bit:
ScanSettings scanSet
scheib
2015/05/22 01:26:46
Done.
scheib
2015/05/22 01:26:46
Done.
| |
152 // Note: SCAN_FAILED_FEATURE_UNSUPPORTED is caused (at least on some | |
153 // devices) if scanSettingsBuilder.setReportDelay() is set or if | |
154 // SCAN_MODE_LOW_LATENCY isn't used. | |
155 scanSettingsBuilder.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY); | |
156 | |
157 if (mLeScanCallback == null) mLeScanCallback = new DiscoveryScanCallback (); | |
ortuno
2015/05/21 16:48:53
I think you need braces here:
https://google-styl
scheib
2015/05/22 01:26:45
Done.
| |
158 mAdapter.getBluetoothLeScanner().startScan( | |
159 null /* filters */, scanSettingsBuilder.build(), mLeScanCallback ); | |
160 return true; | |
161 } | |
162 | |
163 @CalledByNative | |
164 private boolean removeDiscoverySession() { | |
165 Log.i(TAG, "removeDiscoverySession"); | |
166 switch (--mNumDiscoverySessions) { | |
ortuno
2015/05/21 16:48:53
nit: I think it would be clearer this way:
if (mN
scheib
2015/05/22 01:26:46
Done.
| |
167 case -1: | |
168 assert false; | |
169 Log.w(TAG, "removeDiscoverySession: No scan in progress."); | |
170 mNumDiscoverySessions = 0; | |
171 return false; | |
172 case 0: | |
173 mAdapter.getBluetoothLeScanner().stopScan(mLeScanCallback); | |
174 } | |
175 return true; | |
176 } | |
177 | |
178 // ------------------------------------------------------------------------- -------------------- | |
179 // Implementation details: | |
180 | |
181 private class DiscoveryScanCallback extends ScanCallback { | |
182 @Override | |
183 public void onBatchScanResults(List<ScanResult> results) { | |
184 Log.i(TAG, "onBatchScanResults"); | |
185 } | |
186 | |
187 @Override | |
188 public void onScanResult(int callbackType, ScanResult result) { | |
189 Log.i(TAG, "onScanResult %s %s", result.getDevice().getAddress(), | |
190 result.getDevice().getName()); | |
191 } | |
192 | |
193 @Override | |
194 public void onScanFailed(int errorCode) { | |
195 Log.w(TAG, "onScanFailed: %d", errorCode); | |
196 // DISCUSS IN CODE REVIEW. | |
197 // | |
198 // TODO(scheib): Current device/bluetooth API doesn't support a way to communicate | |
199 // this asynchronous failure. If there was a way to communicate asyn chronous | |
200 // success, then the response to AddDiscoverySession would be delaye d until then or | |
201 // this error. But without only the error we must presume success. | |
202 // | |
203 // NEED ISSUE NUMBER. | |
204 } | |
205 } | |
107 } | 206 } |
OLD | NEW |