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; |
8 import android.bluetooth.BluetoothAdapter; | 9 import android.bluetooth.BluetoothAdapter; |
| 10 import android.bluetooth.BluetoothDevice; |
| 11 import android.bluetooth.le.BluetoothLeScanner; |
| 12 import android.bluetooth.le.ScanCallback; |
| 13 import android.bluetooth.le.ScanFilter; |
| 14 import android.bluetooth.le.ScanResult; |
| 15 import android.bluetooth.le.ScanSettings; |
9 import android.content.Context; | 16 import android.content.Context; |
10 import android.content.pm.PackageManager; | 17 import android.content.pm.PackageManager; |
| 18 import android.os.Build; |
11 | 19 |
12 import org.chromium.base.CalledByNative; | 20 import org.chromium.base.CalledByNative; |
13 import org.chromium.base.JNINamespace; | 21 import org.chromium.base.JNINamespace; |
14 import org.chromium.base.Log; | 22 import org.chromium.base.Log; |
15 | 23 |
| 24 import java.util.ArrayList; |
| 25 import java.util.List; |
| 26 |
16 /** | 27 /** |
17 * Wrapper classes around android.bluetooth.* classes that provide an | 28 * Wrapper classes around android.bluetooth.* classes that provide an |
18 * indirection layer enabling fake implementations when running tests. | 29 * indirection layer enabling fake implementations when running tests. |
19 * | 30 * |
20 * Each Wrapper base class accepts an Android API object and passes through | 31 * Each Wrapper base class accepts an Android API object and passes through |
21 * calls to it. When under test, Fake subclasses override all methods that | 32 * calls to it. When under test, Fake subclasses override all methods that |
22 * pass through to the Android object and instead provide fake implementations. | 33 * pass through to the Android object and instead provide fake implementations. |
23 */ | 34 */ |
24 @JNINamespace("device") | 35 @JNINamespace("device") |
| 36 @TargetApi(Build.VERSION_CODES.LOLLIPOP) |
25 class Wrappers { | 37 class Wrappers { |
26 private static final String TAG = "cr.Bluetooth"; | 38 private static final String TAG = "cr.Bluetooth"; |
27 | 39 |
28 /** | 40 /** |
29 * Wraps android.bluetooth.BluetoothAdapter. | 41 * Wraps android.bluetooth.BluetoothAdapter. |
30 */ | 42 */ |
31 static class BluetoothAdapterWrapper { | 43 static class BluetoothAdapterWrapper { |
32 private final BluetoothAdapter mAdapter; | 44 private final BluetoothAdapter mAdapter; |
| 45 protected final BluetoothLeScannerWrapper mScanner; |
33 | 46 |
34 /** | 47 /** |
35 * Creates a BluetoothAdapterWrapper using the default | 48 * Creates a BluetoothAdapterWrapper using the default |
36 * android.bluetooth.BluetoothAdapter. May fail if the default adapter | 49 * android.bluetooth.BluetoothAdapter. May fail if the default adapter |
37 * is not available or if the application does not have sufficient | 50 * is not available or if the application does not have sufficient |
38 * permissions. | 51 * permissions. |
39 */ | 52 */ |
40 @CalledByNative("BluetoothAdapterWrapper") | 53 @CalledByNative("BluetoothAdapterWrapper") |
41 public static BluetoothAdapterWrapper createWithDefaultAdapter(Context c
ontext) { | 54 public static BluetoothAdapterWrapper createWithDefaultAdapter(Context c
ontext) { |
| 55 final boolean hasMinAPI = Build.VERSION.SDK_INT >= Build.VERSION_COD
ES.LOLLIPOP; |
| 56 if (!hasMinAPI) { |
| 57 Log.i(TAG, "BluetoothAdapterWrapper.create failed: SDK version (
%d) too low.", |
| 58 Build.VERSION.SDK_INT); |
| 59 return null; |
| 60 } |
| 61 |
42 final boolean hasPermissions = | 62 final boolean hasPermissions = |
43 context.checkCallingOrSelfPermission(Manifest.permission.BLU
ETOOTH) | 63 context.checkCallingOrSelfPermission(Manifest.permission.BLU
ETOOTH) |
44 == PackageManager.PERMISSION_GRANTED | 64 == PackageManager.PERMISSION_GRANTED |
45 && context.checkCallingOrSelfPermission(Manifest.permission.
BLUETOOTH_ADMIN) | 65 && context.checkCallingOrSelfPermission(Manifest.permission.
BLUETOOTH_ADMIN) |
46 == PackageManager.PERMISSION_GRANTED; | 66 == PackageManager.PERMISSION_GRANTED; |
47 if (!hasPermissions) { | 67 if (!hasPermissions) { |
48 Log.w(TAG, "BluetoothAdapterWrapper.create failed: Lacking Bluet
ooth permissions."); | 68 Log.w(TAG, "BluetoothAdapterWrapper.create failed: Lacking Bluet
ooth permissions."); |
49 return null; | 69 return null; |
50 } | 70 } |
51 | 71 |
| 72 // Only Low Energy currently supported, see BluetoothAdapterAndroid
class note. |
| 73 final boolean hasLowEnergyFeature = |
| 74 Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2 |
| 75 && context.getPackageManager().hasSystemFeature( |
| 76 PackageManager.FEATURE_BLUETOOTH_LE); |
| 77 if (!hasLowEnergyFeature) { |
| 78 Log.i(TAG, "BluetoothAdapterWrapper.create failed: No Low Energy
support."); |
| 79 return null; |
| 80 } |
| 81 |
52 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); | 82 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); |
53 if (adapter == null) { | 83 if (adapter == null) { |
54 Log.i(TAG, "BluetoothAdapterWrapper.create failed: Default adapt
er not found."); | 84 Log.i(TAG, "BluetoothAdapterWrapper.create failed: Default adapt
er not found."); |
55 return null; | 85 return null; |
56 } else { | 86 } else { |
57 return new BluetoothAdapterWrapper(adapter); | 87 return new BluetoothAdapterWrapper( |
| 88 adapter, new BluetoothLeScannerWrapper(adapter.getBlueto
othLeScanner())); |
58 } | 89 } |
59 } | 90 } |
60 | 91 |
61 public BluetoothAdapterWrapper(BluetoothAdapter adapter) { | 92 public BluetoothAdapterWrapper( |
| 93 BluetoothAdapter adapter, BluetoothLeScannerWrapper scanner) { |
62 mAdapter = adapter; | 94 mAdapter = adapter; |
| 95 mScanner = scanner; |
| 96 } |
| 97 |
| 98 public BluetoothLeScannerWrapper getBluetoothLeScanner() { |
| 99 return mScanner; |
63 } | 100 } |
64 | 101 |
65 public boolean isEnabled() { | 102 public boolean isEnabled() { |
66 return mAdapter.isEnabled(); | 103 return mAdapter.isEnabled(); |
67 } | 104 } |
68 | 105 |
69 public String getAddress() { | 106 public String getAddress() { |
70 return mAdapter.getAddress(); | 107 return mAdapter.getAddress(); |
71 } | 108 } |
72 | 109 |
73 public String getName() { | 110 public String getName() { |
74 return mAdapter.getName(); | 111 return mAdapter.getName(); |
75 } | 112 } |
76 | 113 |
77 public int getScanMode() { | 114 public int getScanMode() { |
78 return mAdapter.getScanMode(); | 115 return mAdapter.getScanMode(); |
79 } | 116 } |
80 | 117 |
81 public boolean isDiscovering() { | 118 public boolean isDiscovering() { |
82 return mAdapter.isDiscovering(); | 119 return mAdapter.isDiscovering(); |
83 } | 120 } |
84 } | 121 } |
| 122 |
| 123 /** |
| 124 * Wraps android.bluetooth.BluetoothLeScanner. |
| 125 */ |
| 126 static class BluetoothLeScannerWrapper { |
| 127 private final BluetoothLeScanner mScanner; |
| 128 |
| 129 public BluetoothLeScannerWrapper(BluetoothLeScanner scanner) { |
| 130 mScanner = scanner; |
| 131 } |
| 132 |
| 133 public void startScan( |
| 134 List<ScanFilter> filters, ScanSettings settings, ScanCallbackWra
pper callback) { |
| 135 mScanner.startScan(filters, settings, callback); |
| 136 } |
| 137 |
| 138 public void stopScan(ScanCallbackWrapper callback) { |
| 139 mScanner.stopScan(callback); |
| 140 } |
| 141 } |
| 142 |
| 143 /** |
| 144 * Wraps android.bluetooth.le.ScanCallback. The ScanCallback methods: |
| 145 * - onBatchScanResults |
| 146 * - onScanResult |
| 147 * are implemented to wrap the incoming android.bluetooth.le types into thei
r |
| 148 * wrapper types and then call the wrapper versions: |
| 149 * - onBatchScanResultWrappers |
| 150 * - onScanResultWrapper |
| 151 * Subclasses must implement these Wrapper versions. |
| 152 * |
| 153 * The Wrapper name variations are used because Java doesn't support |
| 154 * overloading by differing Generics. |
| 155 */ |
| 156 public abstract static class ScanCallbackWrapper extends ScanCallback { |
| 157 public abstract void onBatchScanResultWrappers(List<ScanResultWrapper> r
esults); |
| 158 public abstract void onScanResultWrapper(int callbackType, ScanResultWra
pper result); |
| 159 |
| 160 @Override |
| 161 public void onBatchScanResults(List<ScanResult> results) { |
| 162 ArrayList<ScanResultWrapper> resultsWrapped = |
| 163 new ArrayList<ScanResultWrapper>(results.size()); |
| 164 for (ScanResult result : results) { |
| 165 resultsWrapped.add(new ScanResultWrapper(result)); |
| 166 } |
| 167 onBatchScanResultWrappers(resultsWrapped); |
| 168 } |
| 169 |
| 170 @Override |
| 171 public void onScanResult(int callbackType, ScanResult result) { |
| 172 onScanResultWrapper(callbackType, new ScanResultWrapper(result)); |
| 173 } |
| 174 } |
| 175 |
| 176 /** |
| 177 * Wraps android.bluetooth.le.ScanResult. |
| 178 */ |
| 179 static class ScanResultWrapper { |
| 180 private final ScanResult mScanResult; |
| 181 |
| 182 public ScanResultWrapper(ScanResult scanResult) { |
| 183 mScanResult = scanResult; |
| 184 } |
| 185 |
| 186 public BluetoothDeviceWrapper getDevice() { |
| 187 return new BluetoothDeviceWrapper(mScanResult.getDevice()); |
| 188 } |
| 189 } |
| 190 |
| 191 /** |
| 192 * Wraps android.bluetooth.BluetoothDevice. |
| 193 */ |
| 194 static class BluetoothDeviceWrapper { |
| 195 private final BluetoothDevice mDevice; |
| 196 |
| 197 public BluetoothDeviceWrapper(BluetoothDevice device) { |
| 198 mDevice = device; |
| 199 } |
| 200 |
| 201 public String getAddress() { |
| 202 return mDevice.getAddress(); |
| 203 } |
| 204 |
| 205 public String getName() { |
| 206 return mDevice.getName(); |
| 207 } |
| 208 } |
85 } | 209 } |
OLD | NEW |