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.HashMap; |
| 26 import java.util.List; |
| 27 |
16 /** | 28 /** |
17 * Wrapper classes around android.bluetooth.* classes that provide an | 29 * Wrapper classes around android.bluetooth.* classes that provide an |
18 * indirection layer enabling fake implementations when running tests. | 30 * indirection layer enabling fake implementations when running tests. |
19 * | 31 * |
20 * Each Wrapper base class accepts an Android API object and passes through | 32 * 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 | 33 * calls to it. When under test, Fake subclasses override all methods that |
22 * pass through to the Android object and instead provide fake implementations. | 34 * pass through to the Android object and instead provide fake implementations. |
23 */ | 35 */ |
24 @JNINamespace("device") | 36 @JNINamespace("device") |
| 37 @TargetApi(Build.VERSION_CODES.LOLLIPOP) |
25 class Wrappers { | 38 class Wrappers { |
26 private static final String TAG = "cr.Bluetooth"; | 39 private static final String TAG = "cr.Bluetooth"; |
27 | 40 |
28 /** | 41 /** |
29 * Wraps android.bluetooth.BluetoothAdapter. | 42 * Wraps android.bluetooth.BluetoothAdapter. |
30 */ | 43 */ |
31 static class BluetoothAdapterWrapper { | 44 static class BluetoothAdapterWrapper { |
32 private final BluetoothAdapter mAdapter; | 45 private final BluetoothAdapter mAdapter; |
| 46 protected final BluetoothLeScannerWrapper mScanner; |
33 | 47 |
34 /** | 48 /** |
35 * Creates a BluetoothAdapterWrapper using the default | 49 * Creates a BluetoothAdapterWrapper using the default |
36 * android.bluetooth.BluetoothAdapter. May fail if the default adapter | 50 * android.bluetooth.BluetoothAdapter. May fail if the default adapter |
37 * is not available or if the application does not have sufficient | 51 * is not available or if the application does not have sufficient |
38 * permissions. | 52 * permissions. |
39 */ | 53 */ |
40 @CalledByNative("BluetoothAdapterWrapper") | 54 @CalledByNative("BluetoothAdapterWrapper") |
41 public static BluetoothAdapterWrapper createWithDefaultAdapter(Context c
ontext) { | 55 public static BluetoothAdapterWrapper createWithDefaultAdapter(Context c
ontext) { |
| 56 final boolean hasMinAPI = Build.VERSION.SDK_INT >= Build.VERSION_COD
ES.LOLLIPOP; |
| 57 if (!hasMinAPI) { |
| 58 Log.i(TAG, "BluetoothAdapterWrapper.create failed: SDK version (
%d) too low.", |
| 59 Build.VERSION.SDK_INT); |
| 60 return null; |
| 61 } |
| 62 |
42 final boolean hasPermissions = | 63 final boolean hasPermissions = |
43 context.checkCallingOrSelfPermission(Manifest.permission.BLU
ETOOTH) | 64 context.checkCallingOrSelfPermission(Manifest.permission.BLU
ETOOTH) |
44 == PackageManager.PERMISSION_GRANTED | 65 == PackageManager.PERMISSION_GRANTED |
45 && context.checkCallingOrSelfPermission(Manifest.permission.
BLUETOOTH_ADMIN) | 66 && context.checkCallingOrSelfPermission(Manifest.permission.
BLUETOOTH_ADMIN) |
46 == PackageManager.PERMISSION_GRANTED; | 67 == PackageManager.PERMISSION_GRANTED; |
47 if (!hasPermissions) { | 68 if (!hasPermissions) { |
48 Log.w(TAG, "BluetoothAdapterWrapper.create failed: Lacking Bluet
ooth permissions."); | 69 Log.w(TAG, "BluetoothAdapterWrapper.create failed: Lacking Bluet
ooth permissions."); |
49 return null; | 70 return null; |
50 } | 71 } |
51 | 72 |
| 73 // Only Low Energy currently supported, see BluetoothAdapterAndroid
class note. |
| 74 final boolean hasLowEnergyFeature = |
| 75 Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2 |
| 76 && context.getPackageManager().hasSystemFeature( |
| 77 PackageManager.FEATURE_BLUETOOTH_LE); |
| 78 if (!hasLowEnergyFeature) { |
| 79 Log.i(TAG, "BluetoothAdapterWrapper.create failed: No Low Energy
support."); |
| 80 return null; |
| 81 } |
| 82 |
52 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); | 83 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); |
53 if (adapter == null) { | 84 if (adapter == null) { |
54 Log.i(TAG, "BluetoothAdapterWrapper.create failed: Default adapt
er not found."); | 85 Log.i(TAG, "BluetoothAdapterWrapper.create failed: Default adapt
er not found."); |
55 return null; | 86 return null; |
56 } else { | 87 } else { |
57 return new BluetoothAdapterWrapper(adapter); | 88 return new BluetoothAdapterWrapper( |
| 89 adapter, new BluetoothLeScannerWrapper(adapter.getBlueto
othLeScanner())); |
58 } | 90 } |
59 } | 91 } |
60 | 92 |
61 public BluetoothAdapterWrapper(BluetoothAdapter adapter) { | 93 public BluetoothAdapterWrapper( |
| 94 BluetoothAdapter adapter, BluetoothLeScannerWrapper scanner) { |
62 mAdapter = adapter; | 95 mAdapter = adapter; |
| 96 mScanner = scanner; |
| 97 } |
| 98 |
| 99 public BluetoothLeScannerWrapper getBluetoothLeScanner() { |
| 100 return mScanner; |
63 } | 101 } |
64 | 102 |
65 public boolean isEnabled() { | 103 public boolean isEnabled() { |
66 return mAdapter.isEnabled(); | 104 return mAdapter.isEnabled(); |
67 } | 105 } |
68 | 106 |
69 public String getAddress() { | 107 public String getAddress() { |
70 return mAdapter.getAddress(); | 108 return mAdapter.getAddress(); |
71 } | 109 } |
72 | 110 |
73 public String getName() { | 111 public String getName() { |
74 return mAdapter.getName(); | 112 return mAdapter.getName(); |
75 } | 113 } |
76 | 114 |
77 public int getScanMode() { | 115 public int getScanMode() { |
78 return mAdapter.getScanMode(); | 116 return mAdapter.getScanMode(); |
79 } | 117 } |
80 | 118 |
81 public boolean isDiscovering() { | 119 public boolean isDiscovering() { |
82 return mAdapter.isDiscovering(); | 120 return mAdapter.isDiscovering(); |
83 } | 121 } |
84 } | 122 } |
| 123 |
| 124 /** |
| 125 * Wraps android.bluetooth.BluetoothLeScanner. |
| 126 */ |
| 127 static class BluetoothLeScannerWrapper { |
| 128 private final BluetoothLeScanner mScanner; |
| 129 private final HashMap<ScanCallbackWrapper, ScanCallbackImpl> mCallbacks; |
| 130 |
| 131 public BluetoothLeScannerWrapper(BluetoothLeScanner scanner) { |
| 132 mScanner = scanner; |
| 133 mCallbacks = new HashMap<ScanCallbackWrapper, ScanCallbackImpl>(); |
| 134 } |
| 135 |
| 136 public void startScan( |
| 137 List<ScanFilter> filters, int scanSettingsScanMode, ScanCallback
Wrapper callback) { |
| 138 ScanSettings settings = |
| 139 new ScanSettings.Builder().setScanMode(scanSettingsScanMode)
.build(); |
| 140 |
| 141 ScanCallbackImpl callbackImpl = new ScanCallbackImpl(callback); |
| 142 mCallbacks.put(callback, callbackImpl); |
| 143 |
| 144 mScanner.startScan(filters, settings, callbackImpl); |
| 145 } |
| 146 |
| 147 public void stopScan(ScanCallbackWrapper callback) { |
| 148 ScanCallbackImpl callbackImpl = mCallbacks.remove(callback); |
| 149 mScanner.stopScan(callbackImpl); |
| 150 } |
| 151 } |
| 152 |
| 153 /** |
| 154 * Implements android.bluetooth.le.ScanCallback and passes calls through to
a |
| 155 * provided ScanCallbackWrapper instance. |
| 156 * |
| 157 * This class is required so that Fakes can use ScanCallbackWrapper without |
| 158 * it extending from ScanCallback. Fakes must function even on Android |
| 159 * versions where ScanCallback class is not defined. |
| 160 */ |
| 161 static class ScanCallbackImpl extends ScanCallback { |
| 162 final ScanCallbackWrapper mWrapperCallback; |
| 163 |
| 164 ScanCallbackImpl(ScanCallbackWrapper wrapperCallback) { |
| 165 mWrapperCallback = wrapperCallback; |
| 166 } |
| 167 |
| 168 @Override |
| 169 public void onBatchScanResults(List<ScanResult> results) { |
| 170 ArrayList<ScanResultWrapper> resultsWrapped = |
| 171 new ArrayList<ScanResultWrapper>(results.size()); |
| 172 for (ScanResult result : results) { |
| 173 resultsWrapped.add(new ScanResultWrapper(result)); |
| 174 } |
| 175 mWrapperCallback.onBatchScanResult(resultsWrapped); |
| 176 } |
| 177 |
| 178 @Override |
| 179 public void onScanResult(int callbackType, ScanResult result) { |
| 180 mWrapperCallback.onScanResult(callbackType, new ScanResultWrapper(re
sult)); |
| 181 } |
| 182 |
| 183 @Override |
| 184 public void onScanFailed(int errorCode) { |
| 185 mWrapperCallback.onScanFailed(errorCode); |
| 186 } |
| 187 } |
| 188 |
| 189 /** |
| 190 * Wraps android.bluetooth.le.ScanCallback, being called by ScanCallbackImpl
. |
| 191 */ |
| 192 abstract static class ScanCallbackWrapper { |
| 193 public abstract void onBatchScanResult(List<ScanResultWrapper> results); |
| 194 public abstract void onScanResult(int callbackType, ScanResultWrapper re
sult); |
| 195 public abstract void onScanFailed(int errorCode); |
| 196 } |
| 197 |
| 198 /** |
| 199 * Wraps android.bluetooth.le.ScanResult. |
| 200 */ |
| 201 static class ScanResultWrapper { |
| 202 private final ScanResult mScanResult; |
| 203 |
| 204 public ScanResultWrapper(ScanResult scanResult) { |
| 205 mScanResult = scanResult; |
| 206 } |
| 207 |
| 208 public BluetoothDeviceWrapper getDevice() { |
| 209 return new BluetoothDeviceWrapper(mScanResult.getDevice()); |
| 210 } |
| 211 } |
| 212 |
| 213 /** |
| 214 * Wraps android.bluetooth.BluetoothDevice. |
| 215 */ |
| 216 static class BluetoothDeviceWrapper { |
| 217 private final BluetoothDevice mDevice; |
| 218 |
| 219 public BluetoothDeviceWrapper(BluetoothDevice device) { |
| 220 mDevice = device; |
| 221 } |
| 222 |
| 223 public String getAddress() { |
| 224 return mDevice.getAddress(); |
| 225 } |
| 226 |
| 227 public String getName() { |
| 228 return mDevice.getName(); |
| 229 } |
| 230 } |
85 } | 231 } |
OLD | NEW |