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.annotation.TargetApi; | |
9 import android.bluetooth.le.ScanCallback; | |
10 import android.bluetooth.le.ScanResult; | |
11 import android.bluetooth.le.ScanSettings; | |
8 import android.content.Context; | 12 import android.content.Context; |
9 import android.content.ContextWrapper; | 13 import android.content.ContextWrapper; |
10 import android.content.pm.PackageManager; | 14 import android.content.pm.PackageManager; |
15 import android.os.Build; | |
11 | 16 |
12 import org.chromium.base.CalledByNative; | 17 import org.chromium.base.CalledByNative; |
13 import org.chromium.base.JNINamespace; | 18 import org.chromium.base.JNINamespace; |
14 import org.chromium.base.Log; | 19 import org.chromium.base.Log; |
15 | 20 |
21 import java.util.List; | |
22 | |
16 /** | 23 /** |
17 * Exposes android.bluetooth.BluetoothAdapter as necessary for C++ | 24 * Exposes android.bluetooth.BluetoothAdapter as necessary for C++ |
18 * device::BluetoothAdapterAndroid. | 25 * device::BluetoothAdapterAndroid. |
19 */ | 26 */ |
20 @JNINamespace("device") | 27 @JNINamespace("device") |
28 @TargetApi(Build.VERSION_CODES.LOLLIPOP) | |
21 final class BluetoothAdapter { | 29 final class BluetoothAdapter { |
22 private static final String TAG = Log.makeTag("Bluetooth"); | 30 private static final String TAG = Log.makeTag("Bluetooth"); |
23 | 31 |
24 private final boolean mHasBluetoothPermission; | 32 private final long mNativeCPPObject; |
Ted C
2015/05/27 01:13:39
Normally, we'd do mNativeBluetoothAdapter
scheib
2015/05/27 02:21:54
Done.
| |
33 private final boolean mHasBluetoothCapability; | |
25 private android.bluetooth.BluetoothAdapter mAdapter; | 34 private android.bluetooth.BluetoothAdapter mAdapter; |
35 private int mNumDiscoverySessions; | |
36 private ScanCallback mLeScanCallback; | |
37 | |
38 // ------------------------------------------------------------------------- -------------------- | |
39 // Construction: | |
26 | 40 |
27 @CalledByNative | 41 @CalledByNative |
28 private static BluetoothAdapter create(Context context) { | 42 private static BluetoothAdapter create(Context context, long nativeCPPObject ) { |
29 return new BluetoothAdapter(context); | 43 return new BluetoothAdapter(context, nativeCPPObject); |
30 } | 44 } |
31 | 45 |
32 @CalledByNative | 46 @CalledByNative |
33 private static BluetoothAdapter createWithoutPermissionForTesting(Context co ntext) { | 47 private static BluetoothAdapter createWithoutPermissionForTesting( |
48 Context context, long nativeCPPObject) { | |
34 Context contextWithoutPermission = new ContextWrapper(context) { | 49 Context contextWithoutPermission = new ContextWrapper(context) { |
35 @Override | 50 @Override |
36 public int checkCallingOrSelfPermission(String permission) { | 51 public int checkCallingOrSelfPermission(String permission) { |
37 return PackageManager.PERMISSION_DENIED; | 52 return PackageManager.PERMISSION_DENIED; |
38 } | 53 } |
39 }; | 54 }; |
40 return new BluetoothAdapter(contextWithoutPermission); | 55 return new BluetoothAdapter(contextWithoutPermission, nativeCPPObject); |
41 } | 56 } |
42 | 57 |
43 // Constructs a BluetoothAdapter. | 58 // Constructs a BluetoothAdapter. |
44 private BluetoothAdapter(Context context) { | 59 private BluetoothAdapter(Context context, long nativeCPPObject) { |
45 mHasBluetoothPermission = | 60 mNativeCPPObject = nativeCPPObject; |
61 final boolean hasMinAPI = Build.VERSION.SDK_INT >= Build.VERSION_CODES.L OLLIPOP; | |
62 final boolean hasPermissions = | |
46 context.checkCallingOrSelfPermission(Manifest.permission.BLUETOO TH) | 63 context.checkCallingOrSelfPermission(Manifest.permission.BLUETOO TH) |
47 == PackageManager.PERMISSION_GRANTED | 64 == PackageManager.PERMISSION_GRANTED |
48 && context.checkCallingOrSelfPermission(Manifest.permission.BLUE TOOTH_ADMIN) | 65 && context.checkCallingOrSelfPermission(Manifest.permission.BLUE TOOTH_ADMIN) |
49 == PackageManager.PERMISSION_GRANTED; | 66 == PackageManager.PERMISSION_GRANTED; |
50 if (!mHasBluetoothPermission) { | 67 final boolean hasLowEnergyFeature = |
51 Log.w(TAG, | 68 Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2 |
52 "Bluetooth API disabled; BLUETOOTH and BLUETOOTH_ADMIN permi ssions required."); | 69 && context.getPackageManager().hasSystemFeature( |
70 PackageManager.FEATURE_BLUETOOTH_LE); | |
71 mHasBluetoothCapability = hasMinAPI && hasPermissions && hasLowEnergyFea ture; | |
72 if (!mHasBluetoothCapability) { | |
73 if (!hasMinAPI) { | |
74 Log.i(TAG, "Bluetooth API disabled; SDK version (%d) too low.", | |
75 Build.VERSION.SDK_INT); | |
76 } else if (!hasPermissions) { | |
77 Log.w(TAG, "Bluetooth API disabled; BLUETOOTH and BLUETOOTH_ADMI N permissions " | |
78 + "required."); | |
Ted C
2015/05/27 01:13:39
this is indented too much...should be 8
scheib
2015/05/27 02:21:54
This is enforced by 'git cl format', and reset if
| |
79 } else if (!hasLowEnergyFeature) { | |
80 Log.i(TAG, "Bluetooth API disabled; Low Energy not supported on system."); | |
81 } | |
53 return; | 82 return; |
54 } | 83 } |
55 | 84 |
56 mAdapter = android.bluetooth.BluetoothAdapter.getDefaultAdapter(); | 85 mAdapter = android.bluetooth.BluetoothAdapter.getDefaultAdapter(); |
57 if (mAdapter == null) Log.i(TAG, "No adapter found."); | 86 if (mAdapter == null) { |
58 } | 87 Log.i(TAG, "No adapter found."); |
59 | 88 } else { |
60 @CalledByNative | 89 Log.i(TAG, "BluetoothAdapter successfully constructed."); |
61 private boolean hasBluetoothPermission() { | 90 } |
62 return mHasBluetoothPermission; | |
63 } | 91 } |
64 | 92 |
65 // ------------------------------------------------------------------------- -------------------- | 93 // ------------------------------------------------------------------------- -------------------- |
66 // BluetoothAdapterAndroid.h interface: | 94 // BluetoothAdapterAndroid C++ methods declared for access from java: |
67 | 95 |
96 // Binds to BluetoothAdapterAndroid::OnScanFailed. | |
97 private native void nativeOnScanFailed(long nativeBluetoothAdapterAndroid); | |
Ted C
2015/05/27 01:13:39
We typically put native ones at the bottom since t
scheib
2015/05/27 02:21:54
Done.
| |
98 | |
99 // ------------------------------------------------------------------------- -------------------- | |
100 // BluetoothAdapterAndroid methods implemented in java: | |
101 | |
102 // Implements BluetoothAdapterAndroid::HasBluetoothCapability. | |
103 @CalledByNative | |
104 private boolean hasBluetoothCapability() { | |
105 return mHasBluetoothCapability; | |
106 } | |
107 | |
108 // Implements BluetoothAdapterAndroid::GetAddress. | |
68 @CalledByNative | 109 @CalledByNative |
69 private String getAddress() { | 110 private String getAddress() { |
70 if (isPresent()) { | 111 if (isPresent()) { |
71 return mAdapter.getAddress(); | 112 return mAdapter.getAddress(); |
72 } else { | 113 } else { |
73 return ""; | 114 return ""; |
74 } | 115 } |
75 } | 116 } |
76 | 117 |
118 // Implements BluetoothAdapterAndroid::GetName. | |
77 @CalledByNative | 119 @CalledByNative |
78 private String getName() { | 120 private String getName() { |
79 if (isPresent()) { | 121 if (isPresent()) { |
80 return mAdapter.getName(); | 122 return mAdapter.getName(); |
81 } else { | 123 } else { |
82 return ""; | 124 return ""; |
83 } | 125 } |
84 } | 126 } |
85 | 127 |
128 // Implements BluetoothAdapterAndroid::IsPresent. | |
86 @CalledByNative | 129 @CalledByNative |
87 private boolean isPresent() { | 130 private boolean isPresent() { |
88 return mAdapter != null; | 131 return mAdapter != null; |
89 } | 132 } |
90 | 133 |
134 // Implements BluetoothAdapterAndroid::IsPowered. | |
91 @CalledByNative | 135 @CalledByNative |
92 private boolean isPowered() { | 136 private boolean isPowered() { |
93 return isPresent() && mAdapter.isEnabled(); | 137 return isPresent() && mAdapter.isEnabled(); |
94 } | 138 } |
95 | 139 |
140 // Implements BluetoothAdapterAndroid::IsDiscoverable. | |
96 @CalledByNative | 141 @CalledByNative |
97 private boolean isDiscoverable() { | 142 private boolean isDiscoverable() { |
98 return isPresent() | 143 return isPresent() |
99 && mAdapter.getScanMode() | 144 && mAdapter.getScanMode() |
100 == android.bluetooth.BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISC OVERABLE; | 145 == android.bluetooth.BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISC OVERABLE; |
101 } | 146 } |
102 | 147 |
148 // Implements BluetoothAdapterAndroid::IsDiscovering. | |
103 @CalledByNative | 149 @CalledByNative |
104 private boolean isDiscovering() { | 150 private boolean isDiscovering() { |
105 return isPresent() && mAdapter.isDiscovering(); | 151 return isPresent() && mAdapter.isDiscovering(); |
106 } | 152 } |
153 | |
154 // Implements BluetoothAdapterAndroid::AddDiscoverySession. | |
155 @CalledByNative | |
156 private boolean addDiscoverySession() { | |
157 if (!isPowered()) { | |
158 Log.d(TAG, "addDiscoverySession: Fails: !isPowered"); | |
159 return false; | |
160 } | |
161 | |
162 mNumDiscoverySessions++; | |
163 Log.d(TAG, "addDiscoverySession: Now %d sessions", mNumDiscoverySessions ); | |
164 if (mNumDiscoverySessions > 1) { | |
165 return true; | |
166 } | |
167 | |
168 // ScanSettings Note: SCAN_FAILED_FEATURE_UNSUPPORTED is caused (at leas t on some devices) | |
169 // if setReportDelay() is used or if SCAN_MODE_LOW_LATENCY isn't used. | |
170 ScanSettings scanSettings = | |
171 new ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LO W_LATENCY).build(); | |
172 | |
173 if (mLeScanCallback == null) { | |
174 mLeScanCallback = new DiscoveryScanCallback(); | |
175 } | |
176 mAdapter.getBluetoothLeScanner().startScan( | |
177 null /* filters */, scanSettings, mLeScanCallback); | |
178 return true; | |
179 } | |
180 | |
181 // Implements BluetoothAdapterAndroid::RemoveDiscoverySession. | |
182 @CalledByNative | |
183 private boolean removeDiscoverySession() { | |
Ted C
2015/05/27 01:13:39
is this guaranteed to be called if during the dest
scheib
2015/05/27 02:21:54
Done. The scan will now be stopped upon C++ object
| |
184 if (mNumDiscoverySessions == 0) { | |
185 assert false; | |
186 Log.w(TAG, "removeDiscoverySession: No scan in progress."); | |
187 return false; | |
188 } | |
189 | |
190 --mNumDiscoverySessions; | |
191 | |
192 if (mNumDiscoverySessions == 0) { | |
193 Log.d(TAG, "removeDiscoverySession: Stopping scan."); | |
194 mAdapter.getBluetoothLeScanner().stopScan(mLeScanCallback); | |
195 } else { | |
196 Log.d(TAG, "removeDiscoverySession: Now %d sessions", mNumDiscoveryS essions); | |
197 } | |
198 | |
199 return true; | |
200 } | |
201 | |
202 // ------------------------------------------------------------------------- -------------------- | |
203 // Implementation details: | |
204 | |
205 private class DiscoveryScanCallback extends ScanCallback { | |
206 @Override | |
207 public void onBatchScanResults(List<ScanResult> results) { | |
208 Log.v(TAG, "onBatchScanResults"); | |
209 } | |
210 | |
211 @Override | |
212 public void onScanResult(int callbackType, ScanResult result) { | |
213 Log.v(TAG, "onScanResult %s %s", result.getDevice().getAddress(), | |
214 result.getDevice().getName()); | |
215 } | |
216 | |
217 @Override | |
218 public void onScanFailed(int errorCode) { | |
219 Log.w(TAG, "onScanFailed: %d", errorCode); | |
220 // DISCUSS IN CODE REVIEW. | |
221 // | |
222 // TODO(scheib): Current device/bluetooth API doesn't support a way to communicate | |
223 // this asynchronous failure. If there was a way to communicate asyn chronous | |
224 // success, then the response to AddDiscoverySession would be delaye d until then or | |
225 // this error. But without only the error we must presume success. | |
226 // | |
227 // | |
228 // NEED ISSUE NUMBER. | |
229 nativeOnScanFailed(mNativeCPPObject); | |
230 } | |
231 } | |
107 } | 232 } |
OLD | NEW |