1 /* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.cts.verifier.bluetooth; 18 19 import android.app.Service; 20 import android.bluetooth.BluetoothAdapter; 21 import android.bluetooth.BluetoothManager; 22 import android.bluetooth.le.AdvertiseSettings; 23 import android.bluetooth.le.BluetoothLeScanner; 24 import android.bluetooth.le.ScanCallback; 25 import android.bluetooth.le.ScanFilter; 26 import android.bluetooth.le.ScanRecord; 27 import android.bluetooth.le.ScanResult; 28 import android.bluetooth.le.ScanSettings; 29 import android.content.Context; 30 import android.content.Intent; 31 import android.os.Handler; 32 import android.os.IBinder; 33 import android.os.ParcelUuid; 34 import android.util.Log; 35 import android.widget.Toast; 36 37 import java.util.ArrayList; 38 import java.util.List; 39 import java.util.Map; 40 41 public class BleScannerService extends Service { 42 43 public static final boolean DEBUG = true; 44 public static final String TAG = "BleScannerService"; 45 46 public static final int COMMAND_POWER_LEVEL = 1; 47 public static final int COMMAND_SCAN_WITH_FILTER = 2; 48 public static final int COMMAND_SCAN_WITHOUT_FILTER = 3; 49 50 public static final String BLE_PRIVACY_NEW_MAC_RECEIVE = 51 "com.android.cts.verifier.bluetooth.BLE_PRIVACY_NEW_MAC_RECEIVE"; 52 public static final String BLE_MAC_ADDRESS = 53 "com.android.cts.verifier.bluetooth.BLE_MAC_ADDRESS"; 54 public static final String BLE_POWER_LEVEL = 55 "com.android.cts.verifier.bluetooth.BLE_POWER_LEVEL"; 56 public static final String BLE_SCAN_RESP = 57 "com.android.cts.verifier.bluetooth.BLE_SCAN_RESP"; 58 public static final String BLE_SCAN_RESULT = 59 "com.android.cts.verifier.bluetooth.BLE_SCAN_RESULT"; 60 61 public static final String EXTRA_COMMAND = 62 "com.google.cts.verifier.bluetooth.EXTRA_COMMAND"; 63 public static final String EXTRA_MAC_ADDRESS = 64 "com.google.cts.verifier.bluetooth.EXTRA_MAC_ADDRESS"; 65 public static final String EXTRA_RSSI = 66 "com.google.cts.verifier.bluetooth.EXTRA_RSSI"; 67 public static final String EXTRA_POWER_LEVEL = 68 "com.google.cts.verifier.bluetooth.EXTRA_POWER_LEVEL"; 69 public static final String EXTRA_POWER_LEVEL_BIT = 70 "com.google.cts.verifier.bluetooth.EXTRA_POWER_LEVEL_BIT"; 71 public static final String EXTRA_UUID = 72 "com.google.cts.verifier.bluetooth.EXTRA_UUID"; 73 public static final String EXTRA_DATA = 74 "com.google.cts.verifier.bluetooth.EXTRA_DATA"; 75 76 private static final byte MANUFACTURER_TEST_ID = (byte)0x07; 77 78 private BluetoothManager mBluetoothManager; 79 private BluetoothAdapter mAdapter; 80 private BluetoothLeScanner mScanner; 81 private ScanCallback mCallback; 82 private Handler mHandler; 83 private String mOldMac; 84 85 @Override onCreate()86 public void onCreate() { 87 super.onCreate(); 88 89 mCallback = new BLEScanCallback(); 90 mHandler = new Handler(); 91 mOldMac = null; 92 93 mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); 94 mAdapter = mBluetoothManager.getAdapter(); 95 mScanner = mAdapter.getBluetoothLeScanner(); 96 } 97 98 @Override onStartCommand(Intent intent, int flags, int startId)99 public int onStartCommand(Intent intent, int flags, int startId) { 100 if (mScanner != null) { 101 List<ScanFilter> filters = new ArrayList<ScanFilter>(); 102 ScanSettings.Builder settingBuilder = new ScanSettings.Builder(); 103 104 int command = intent.getIntExtra(EXTRA_COMMAND, -1); 105 switch (command) { 106 case COMMAND_POWER_LEVEL: 107 filters.add(new ScanFilter.Builder() 108 .setManufacturerData(MANUFACTURER_TEST_ID, 109 new byte[]{MANUFACTURER_TEST_ID, 0}) 110 .setServiceData(new ParcelUuid(BleAdvertiserService.POWER_LEVEL_UUID), 111 BleAdvertiserService.POWER_LEVEL_DATA, 112 BleAdvertiserService.POWER_LEVEL_MASK) 113 .build()); 114 settingBuilder.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY); 115 break; 116 case COMMAND_SCAN_WITH_FILTER: 117 mScanner.stopScan(mCallback); 118 filters.add(new ScanFilter.Builder() 119 .setManufacturerData(MANUFACTURER_TEST_ID, 120 new byte[]{MANUFACTURER_TEST_ID, 0}) 121 .setServiceData(new ParcelUuid(BleAdvertiserService.SCANNABLE_UUID), 122 BleAdvertiserService.SCANNABLE_DATA) 123 .build()); 124 settingBuilder.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY); 125 break; 126 case COMMAND_SCAN_WITHOUT_FILTER: 127 mScanner.stopScan(mCallback); 128 settingBuilder.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY); 129 break; 130 } 131 mOldMac = null; 132 mScanner.startScan(filters, settingBuilder.build(), mCallback); 133 } 134 return START_NOT_STICKY; 135 } 136 137 @Override onBind(Intent intent)138 public IBinder onBind(Intent intent) { 139 return null; 140 } 141 142 @Override onDestroy()143 public void onDestroy() { 144 super.onDestroy(); 145 if (mScanner != null) { 146 mScanner.stopScan(mCallback); 147 } 148 } 149 showMessage(final String msg)150 private void showMessage(final String msg) { 151 mHandler.post(new Runnable() { 152 public void run() { 153 Toast.makeText(BleScannerService.this, msg, Toast.LENGTH_SHORT).show(); 154 } 155 }); 156 } 157 158 private class BLEScanCallback extends ScanCallback { 159 @Override onScanResult(int callBackType, ScanResult result)160 public void onScanResult(int callBackType, ScanResult result) { 161 if (callBackType != ScanSettings.CALLBACK_TYPE_ALL_MATCHES) { 162 Log.e(TAG, "onScanResult fail. callBackType is not CALLBACK_TYPE_ALL_MATCHES"); 163 return; 164 } 165 166 ScanRecord record = result.getScanRecord(); 167 String mac = result.getDevice().getAddress(); 168 Map<ParcelUuid, byte[]> serviceData = record.getServiceData(); 169 170 if (serviceData.get(new ParcelUuid(BleAdvertiserService.POWER_LEVEL_UUID)) != null) { 171 byte[] data = 172 serviceData.get(new ParcelUuid(BleAdvertiserService.POWER_LEVEL_UUID)); 173 if (data.length == BleAdvertiserService.POWER_LEVEL_DATA.length) { 174 Intent powerIntent = new Intent(BLE_POWER_LEVEL); 175 powerIntent.putExtra(EXTRA_MAC_ADDRESS, result.getDevice().getAddress()); 176 powerIntent.putExtra(EXTRA_POWER_LEVEL, record.getTxPowerLevel()); 177 powerIntent.putExtra(EXTRA_RSSI, new Integer(result.getRssi()).toString()); 178 powerIntent.putExtra(EXTRA_POWER_LEVEL_BIT, (int)data[2]); 179 sendBroadcast(powerIntent); 180 181 // Check privacy mac. 182 if (data[2] == AdvertiseSettings.ADVERTISE_TX_POWER_HIGH) { 183 String newMac = result.getDevice().getAddress(); 184 if (mOldMac == null) { 185 mOldMac = newMac; 186 } else if (!mOldMac.equals(mac)) { 187 mOldMac = newMac; 188 Intent newIntent = new Intent(BLE_PRIVACY_NEW_MAC_RECEIVE); 189 sendBroadcast(newIntent); 190 } 191 } 192 } 193 } 194 195 if (serviceData.get(new ParcelUuid(BleAdvertiserService.SCAN_RESP_UUID)) != null) { 196 Intent responseIntent = new Intent(BLE_SCAN_RESP); 197 sendBroadcast(responseIntent); 198 } 199 200 byte[] data = null; 201 String uuid = ""; 202 if (serviceData.containsKey(new ParcelUuid(BleAdvertiserService.SCANNABLE_UUID))) { 203 uuid = BleAdvertiserService.SCANNABLE_UUID.toString(); 204 data = serviceData.get(new ParcelUuid(BleAdvertiserService.SCANNABLE_UUID)); 205 } 206 if (serviceData.containsKey(new ParcelUuid(BleAdvertiserService.UNSCANNABLE_UUID))) { 207 uuid = BleAdvertiserService.UNSCANNABLE_UUID.toString(); 208 data = serviceData.get(new ParcelUuid(BleAdvertiserService.UNSCANNABLE_UUID)); 209 } 210 if (uuid.length() > 0) { 211 Intent scanIntent = new Intent(BLE_SCAN_RESULT); 212 scanIntent.putExtra(EXTRA_UUID, uuid); 213 String dataStr = "{"; 214 for (byte x : data) { 215 dataStr = dataStr + " " + x; 216 } 217 dataStr = dataStr + "}"; 218 scanIntent.putExtra(EXTRA_DATA, dataStr); 219 sendBroadcast(scanIntent); 220 } 221 } 222 onScanFailed(int errorCode)223 public void onScanFailed(int errorCode) { 224 Log.e(TAG, "Scan fail. Error code: " + new Integer(errorCode).toString()); 225 } 226 227 } 228 } 229