blob: ee6342bacdd09c8104d34dfeb3f79278acfb7a6e [file] [log] [blame]
/*
* Copyright 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.cts.verifier.bluetooth;
import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattServer;
import android.bluetooth.BluetoothGattServerCallback;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.bluetooth.le.AdvertiseCallback;
import android.bluetooth.le.AdvertiseData;
import android.bluetooth.le.AdvertiseSettings;
import android.bluetooth.le.BluetoothLeAdvertiser;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.ParcelUuid;
import android.util.Log;
import android.widget.Toast;
import com.android.cts.verifier.R;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Set;
import java.util.Timer;
import java.util.UUID;
public class BleCocServerService extends Service {
public static final boolean DEBUG = true;
public static final String TAG = "BleCocServerService";
public static final int COMMAND_ADD_SERVICE = 0;
public static final int COMMAND_WRITE_CHARACTERISTIC = 1;
public static final int COMMAND_WRITE_DESCRIPTOR = 2;
public static final int TEST_DATA_EXCHANGE_BUFSIZE = 8 * 1024;
public static final String BLE_BLUETOOTH_MISMATCH_SECURE =
"com.android.cts.verifier.bluetooth.BLE_BLUETOOTH_MISMATCH_SECURE";
public static final String BLE_BLUETOOTH_MISMATCH_INSECURE =
"com.android.cts.verifier.bluetooth.BLE_BLUETOOTH_MISMATCH_INSECURE";
public static final String BLE_BLUETOOTH_DISABLED =
"com.android.cts.verifier.bluetooth.BLE_BLUETOOTH_DISABLED";
public static final String BLE_ACTION_COC_SERVER_INSECURE =
"com.android.cts.verifier.bluetooth.BLE_ACTION_COC_SERVER_INSECURE";
public static final String BLE_ACTION_COC_SERVER_SECURE =
"com.android.cts.verifier.bluetooth.BLE_ACTION_COC_SERVER_SECURE";
public static final String BLE_ACTION_SERVER_SECURE =
"com.android.cts.verifier.bluetooth.BLE_ACTION_SERVER_SECURE";
public static final String BLE_ACTION_SERVER_NON_SECURE =
"com.android.cts.verifier.bluetooth.BLE_ACTION_SERVER_NON_SECURE";
public static final String BLE_LE_CONNECTED =
"com.android.cts.verifier.bluetooth.BLE_LE_CONNECTED";
public static final String BLE_COC_LISTENER_CREATED =
"com.android.cts.verifier.bluetooth.BLE_COC_LISTENER_CREATED";
public static final String BLE_PSM_READ =
"com.android.cts.verifier.bluetooth.BLE_PSM_READ";
public static final String BLE_COC_CONNECTED =
"com.android.cts.verifier.bluetooth.BLE_COC_CONNECTED";
public static final String BLE_CONNECTION_TYPE_CHECKED =
"com.android.cts.verifier.bluetooth.BLE_CONNECTION_TYPE_CHECKED";
public static final String BLE_DATA_8BYTES_READ =
"com.android.cts.verifier.bluetooth.BLE_DATA_8BYTES_READ";
public static final String BLE_DATA_LARGEBUF_READ =
"com.android.cts.verifier.bluetooth.BLE_DATA_LARGEBUF_READ";
public static final String BLE_DATA_8BYTES_SENT =
"com.android.cts.verifier.bluetooth.BLE_DATA_8BYTES_SENT";
public static final String BLE_LE_DISCONNECTED =
"com.android.cts.verifier.bluetooth.BLE_LE_DISCONNECTED";
public static final String BLE_COC_SERVER_ACTION_SEND_DATA_8BYTES =
"com.android.cts.verifier.bluetooth.BLE_COC_SERVER_ACTION_SEND_DATA_8BYTES";
public static final String BLE_COC_SERVER_ACTION_EXCHANGE_DATA =
"com.android.cts.verifier.bluetooth.BLE_COC_SERVER_ACTION_EXCHANGE_DATA";
public static final String BLE_COC_SERVER_ACTION_DISCONNECT =
"com.android.cts.verifier.bluetooth.BLE_COC_SERVER_ACTION_DISCONNECT";
public static final String BLE_SERVER_DISCONNECTED =
"com.android.cts.verifier.bluetooth.BLE_SERVER_DISCONNECTED";
public static final String BLE_OPEN_FAIL =
"com.android.cts.verifier.bluetooth.BLE_OPEN_FAIL";
public static final String BLE_ADVERTISE_UNSUPPORTED =
"com.android.cts.verifier.bluetooth.BLE_ADVERTISE_UNSUPPORTED";
public static final String BLE_ADD_SERVICE_FAIL =
"com.android.cts.verifier.bluetooth.BLE_ADD_SERVICE_FAIL";
private static final UUID SERVICE_UUID =
UUID.fromString("00009999-0000-1000-8000-00805f9b34fb");
private static final UUID CHARACTERISTIC_UUID =
UUID.fromString("00009998-0000-1000-8000-00805f9b34fb");
private static final UUID CHARACTERISTIC_RESULT_UUID =
UUID.fromString("00009974-0000-1000-8000-00805f9b34fb");
private static final UUID UPDATE_CHARACTERISTIC_UUID =
UUID.fromString("00009997-0000-1000-8000-00805f9b34fb");
private static final UUID DESCRIPTOR_UUID =
UUID.fromString("00009996-0000-1000-8000-00805f9b34fb");
public static final UUID ADV_COC_SERVICE_UUID=
UUID.fromString("00003334-0000-1000-8000-00805f9b34fb");
private static final UUID SERVICE_UUID_ADDITIONAL =
UUID.fromString("00009995-0000-1000-8000-00805f9b34fb");
private static final UUID SERVICE_UUID_INCLUDED =
UUID.fromString("00009994-0000-1000-8000-00805f9b34fb");
// Variable for registration permission of Descriptor
private static final UUID DESCRIPTOR_NO_READ_UUID =
UUID.fromString("00009973-0000-1000-8000-00805f9b34fb");
private static final UUID DESCRIPTOR_NO_WRITE_UUID =
UUID.fromString("00009972-0000-1000-8000-00805f9b34fb");
private static final UUID DESCRIPTOR_NEED_ENCRYPTED_READ_UUID =
UUID.fromString("00009969-0000-1000-8000-00805f9b34fb");
private static final UUID DESCRIPTOR_NEED_ENCRYPTED_WRITE_UUID =
UUID.fromString("00009968-0000-1000-8000-00805f9b34fb");
private static final int CONN_INTERVAL = 150; // connection interval 150ms
private static final int EXECUTION_DELAY = 1500;
// Delay of notification when secure test failed to start.
private static final long NOTIFICATION_DELAY_OF_SECURE_TEST_FAILURE = 5 * 1000;
public static final String WRITE_VALUE = "SERVER_TEST";
private static final String NOTIFY_VALUE = "NOTIFY_TEST";
private static final String INDICATE_VALUE = "INDICATE_TEST";
public static final String READ_NO_PERMISSION = "READ_NO_CHAR";
public static final String WRITE_NO_PERMISSION = "WRITE_NO_CHAR";
public static final String DESCRIPTOR_READ_NO_PERMISSION = "READ_NO_DESC";
public static final String DESCRIPTOR_WRITE_NO_PERMISSION = "WRITE_NO_DESC";
private BluetoothManager mBluetoothManager;
private BluetoothGattServer mGattServer;
private BluetoothGattService mService;
private BluetoothDevice mDevice;
private Handler mHandler;
private BluetoothLeAdvertiser mAdvertiser;
private boolean mSecure;
private int mMtuSize = -1;
private BluetoothServerSocket mServerSocket;
private int mPsm = -1;
private BluetoothGattCharacteristic mLePsmCharacteristic;
BluetoothChatService mChatService;
private int mNextReadExpectedLen = -1;
private String mNextReadCompletionIntent;
private int mTotalReadLen = 0;
private byte mNextReadByte;
private int mNextWriteExpectedLen = -1;
private String mNextWriteCompletionIntent = null;
// Handler for communicating task with peer.
private TestTaskQueue mTaskQueue;
// current test category
private String mCurrentAction;
// Task to notify failure of starting secure test.
// Secure test calls BluetoothDevice#createBond() when devices were not paired.
// createBond() causes onConnectionStateChange() twice, and it works as strange sequence.
// At the first onConnectionStateChange(), target device is not paired (bond state is
// BluetoothDevice.BOND_NONE).
// At the second onConnectionStateChange(), target devices is paired (bond state is
// BluetoothDevice.BOND_BONDED).
// CTS Verifier will perform lazy check of bond state. Verifier checks bond state
// after NOTIFICATION_DELAY_OF_SECURE_TEST_FAILURE from the first onConnectionStateChange().
private Runnable mNotificationTaskOfSecureTestStartFailure;
@Override
public void onCreate() {
super.onCreate();
mTaskQueue = new TestTaskQueue(getClass().getName() + "_taskHandlerThread");
mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mAdvertiser = mBluetoothManager.getAdapter().getBluetoothLeAdvertiser();
mGattServer = mBluetoothManager.openGattServer(this, mCallbacks);
mService = createService();
mDevice = null;
mHandler = new Handler();
if (!mBluetoothManager.getAdapter().isEnabled()) {
notifyBluetoothDisabled();
} else if (mGattServer == null) {
notifyOpenFail();
} else if (mAdvertiser == null) {
notifyAdvertiseUnsupported();
} else {
// start adding services
mSecure = false;
if (!mGattServer.addService(mService)) {
notifyAddServiceFail();
}
}
}
private void notifyBluetoothDisabled() {
Intent intent = new Intent(BLE_BLUETOOTH_DISABLED);
sendBroadcast(intent);
}
private void notifyMismatchSecure() {
Intent intent = new Intent(BLE_BLUETOOTH_MISMATCH_SECURE);
sendBroadcast(intent);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
String action = intent.getAction();
if (action != null) {
if (DEBUG) {
Log.d(TAG, "onStartCommand: action=" + action);
}
mTaskQueue.addTask(new Runnable() {
@Override
public void run() {
onTestFinish(intent.getAction());
}
}, EXECUTION_DELAY);
}
return START_NOT_STICKY;
}
private void startServerTest(boolean secure) {
mSecure = secure;
if (mBluetoothManager.getAdapter().isEnabled() && (mChatService == null)) {
createChatService();
}
if (mBluetoothManager.getAdapter().isEnabled() && (mAdvertiser != null)) {
startAdvertise();
}
}
private void sendMessage(byte[] buf) {
mChatService.write(buf);
}
private void sendData8bytes() {
if (DEBUG) Log.d(TAG, "sendData8bytes");
final byte[] buf = new byte[]{1,2,3,4,5,6,7,8};
mNextWriteExpectedLen = 8;
mNextWriteCompletionIntent = BLE_DATA_8BYTES_SENT;
sendMessage(buf);
}
private void sendDataLargeBuf() {
final int len = BleCocServerService.TEST_DATA_EXCHANGE_BUFSIZE;
if (DEBUG) Log.d(TAG, "sendDataLargeBuf of size=" + len);
byte[] buf = new byte[len];
for (int i = 0; i < len; i++) {
buf[i] = (byte)(i + 1);
}
mNextWriteExpectedLen = len;
mNextWriteCompletionIntent = null;
sendMessage(buf);
}
private void onTestFinish(String action) {
mCurrentAction = action;
if (mCurrentAction != null) {
switch (mCurrentAction) {
case BLE_ACTION_COC_SERVER_INSECURE:
startServerTest(false);
break;
case BLE_ACTION_COC_SERVER_SECURE:
startServerTest(true);
break;
case BLE_COC_SERVER_ACTION_SEND_DATA_8BYTES:
sendData8bytes();
break;
case BLE_COC_SERVER_ACTION_EXCHANGE_DATA:
sendDataLargeBuf();
readDataLargeBuf();
break;
case BLE_COC_SERVER_ACTION_DISCONNECT:
if (mChatService != null) {
mChatService.stop();
}
break;
default:
Log.e(TAG, "Error: Unhandled or invalid action=" + mCurrentAction);
}
}
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onDestroy() {
super.onDestroy();
if (mChatService != null) {
mChatService.stop();
}
cancelNotificationTaskOfSecureTestStartFailure();
stopAdvertise();
mTaskQueue.quit();
if (mGattServer == null) {
return;
}
if (mDevice != null) {
mGattServer.cancelConnection(mDevice);
}
mGattServer.clearServices();
mGattServer.close();
}
private void notifyOpenFail() {
if (DEBUG) {
Log.d(TAG, "notifyOpenFail");
}
Intent intent = new Intent(BLE_OPEN_FAIL);
sendBroadcast(intent);
}
private void notifyAddServiceFail() {
if (DEBUG) {
Log.d(TAG, "notifyAddServiceFail");
}
Intent intent = new Intent(BLE_ADD_SERVICE_FAIL);
sendBroadcast(intent);
}
private void notifyAdvertiseUnsupported() {
if (DEBUG) {
Log.d(TAG, "notifyAdvertiseUnsupported");
}
Intent intent = new Intent(BLE_ADVERTISE_UNSUPPORTED);
sendBroadcast(intent);
}
private void notifyConnected() {
if (DEBUG) {
Log.d(TAG, "notifyConnected");
}
Intent intent = new Intent(BLE_LE_CONNECTED);
sendBroadcast(intent);
}
private void notifyDisconnected() {
if (DEBUG) {
Log.d(TAG, "notifyDisconnected");
}
Intent intent = new Intent(BLE_SERVER_DISCONNECTED);
sendBroadcast(intent);
}
private BluetoothGattService createService() {
BluetoothGattService service =
new BluetoothGattService(SERVICE_UUID, BluetoothGattService.SERVICE_TYPE_PRIMARY);
BluetoothGattCharacteristic characteristic =
new BluetoothGattCharacteristic(CHARACTERISTIC_UUID, 0x0A, 0x11);
characteristic.setValue(WRITE_VALUE.getBytes());
BluetoothGattDescriptor descriptor = new BluetoothGattDescriptor(DESCRIPTOR_UUID, 0x11);
descriptor.setValue(WRITE_VALUE.getBytes());
characteristic.addDescriptor(descriptor);
BluetoothGattDescriptor descriptor_permission =
new BluetoothGattDescriptor(DESCRIPTOR_NO_READ_UUID, 0x10);
characteristic.addDescriptor(descriptor_permission);
descriptor_permission = new BluetoothGattDescriptor(DESCRIPTOR_NO_WRITE_UUID, 0x01);
characteristic.addDescriptor(descriptor_permission);
service.addCharacteristic(characteristic);
// Registered the characteristic of PSM Value
mLePsmCharacteristic =
new BluetoothGattCharacteristic(BleCocClientService.LE_PSM_CHARACTERISTIC_UUID,
BluetoothGattCharacteristic.PROPERTY_READ,
BluetoothGattCharacteristic.PERMISSION_READ);
service.addCharacteristic(mLePsmCharacteristic);
return service;
}
private void showMessage(final String msg) {
mHandler.post(new Runnable() {
public void run() {
Toast.makeText(BleCocServerService.this, msg, Toast.LENGTH_SHORT).show();
}
});
}
private synchronized void cancelNotificationTaskOfSecureTestStartFailure() {
if (mNotificationTaskOfSecureTestStartFailure != null) {
mHandler.removeCallbacks(mNotificationTaskOfSecureTestStartFailure);
mNotificationTaskOfSecureTestStartFailure = null;
}
}
private final BluetoothGattServerCallback mCallbacks = new BluetoothGattServerCallback() {
@Override
public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
if (DEBUG) {
Log.d(TAG, "onConnectionStateChange: newState=" + newState);
}
if (status == BluetoothGatt.GATT_SUCCESS) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
mDevice = device;
boolean bonded = false;
Set<BluetoothDevice> pairedDevices =
mBluetoothManager.getAdapter().getBondedDevices();
if (pairedDevices.size() > 0) {
for (BluetoothDevice target : pairedDevices) {
if (target.getAddress().equals(device.getAddress())) {
bonded = true;
break;
}
}
}
if (mSecure && ((device.getBondState() == BluetoothDevice.BOND_NONE) ||
!bonded)) {
// not pairing and execute Secure Test
Log.e(TAG, "BluetoothGattServerCallback.onConnectionStateChange: "
+ "Not paired but execute secure test");
cancelNotificationTaskOfSecureTestStartFailure();
} else if (!mSecure && ((device.getBondState() != BluetoothDevice.BOND_NONE)
|| bonded)) {
// already pairing and execute Insecure Test
Log.e(TAG, "BluetoothGattServerCallback.onConnectionStateChange: "
+ "Paired but execute insecure test");
} else {
cancelNotificationTaskOfSecureTestStartFailure();
}
notifyConnected();
} else if (status == BluetoothProfile.STATE_DISCONNECTED) {
notifyDisconnected();
mDevice = null;
}
}
}
@Override
public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset,
BluetoothGattCharacteristic characteristic) {
if (mGattServer == null) {
if (DEBUG) {
Log.d(TAG, "GattServer is null, return");
}
return;
}
if (DEBUG) {
Log.d(TAG, "onCharacteristicReadRequest()");
}
boolean finished = false;
byte[] value = null;
if (mMtuSize > 0) {
byte[] buf = characteristic.getValue();
if (buf != null) {
int len = Math.min((buf.length - offset), mMtuSize);
if (len > 0) {
value = Arrays.copyOfRange(buf, offset, (offset + len));
}
finished = ((offset + len) >= buf.length);
if (finished) {
Log.d(TAG, "sent whole data: " + (new String(characteristic.getValue())));
}
}
} else {
value = characteristic.getValue();
finished = true;
}
mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value);
UUID uid = characteristic.getUuid();
if (uid.equals(BleCocClientService.LE_PSM_CHARACTERISTIC_UUID)) {
Log.d(TAG, "onCharacteristicReadRequest: reading PSM");
}
}
};
private void leCheckConnectionType() {
if (mChatService == null) {
Log.e(TAG, "leCheckConnectionType: no LE Coc connection");
return;
}
int type = mChatService.getSocketConnectionType();
if (type != BluetoothSocket.TYPE_L2CAP) {
Log.e(TAG, "leCheckConnectionType: invalid connection type=" + type);
return;
}
showMessage("LE CoC Connection Type Checked");
Intent intent = new Intent(BLE_CONNECTION_TYPE_CHECKED);
sendBroadcast(intent);
}
private void readData8bytes() {
mNextReadExpectedLen = 8;
mTotalReadLen = 0;
mNextReadCompletionIntent = BLE_DATA_8BYTES_READ;
mNextReadByte = 1;
}
private void readDataLargeBuf() {
mNextReadExpectedLen = BleCocServerService.TEST_DATA_EXCHANGE_BUFSIZE;
mTotalReadLen = 0;
mNextReadCompletionIntent = BLE_DATA_LARGEBUF_READ;
mNextReadByte = 1;
}
private void processChatStateChange(int newState) {
Intent intent;
if (DEBUG) {
Log.d(TAG, "processChatStateChange: newState=" + newState);
}
switch (newState) {
case BluetoothChatService.STATE_LISTEN:
intent = new Intent(BLE_COC_LISTENER_CREATED);
sendBroadcast(intent);
break;
case BluetoothChatService.STATE_CONNECTED:
intent = new Intent(BLE_COC_CONNECTED);
sendBroadcast(intent);
// Check the connection type
leCheckConnectionType();
// Prepare the next data read
readData8bytes();
break;
}
}
private boolean checkReadBufContent(byte[] buf, int len) {
// Check that the content is correct
for (int i = 0; i < len; i++) {
if (buf[i] != mNextReadByte) {
Log.e(TAG, "handleMessageRead: Error: wrong byte content. buf["
+ i + "]=" + buf[i] + " not equal to " + mNextReadByte);
return false;
}
mNextReadByte++;
}
return true;
}
private void handleMessageRead(Message msg) {
byte[] buf = (byte[])msg.obj;
int len = msg.arg1;
if (len <= 0) {
return;
}
mTotalReadLen += len;
if (DEBUG) {
Log.d(TAG, "handleMessageRead: receive buffer of length=" + len + ", mTotalReadLen="
+ mTotalReadLen + ", mNextReadExpectedLen=" + mNextReadExpectedLen);
}
if (mNextReadExpectedLen == mTotalReadLen) {
if (!checkReadBufContent(buf, len)) {
mNextReadExpectedLen = -1;
return;
}
showMessage("Read " + len + " bytes");
if (DEBUG) {
Log.d(TAG, "handleMessageRead: broadcast intent " + mNextReadCompletionIntent);
}
Intent intent = new Intent(mNextReadCompletionIntent);
sendBroadcast(intent);
mNextReadExpectedLen = -1;
mNextReadCompletionIntent = null;
mTotalReadLen = 0;
} else if (mNextReadExpectedLen > mTotalReadLen) {
if (!checkReadBufContent(buf, len)) {
mNextReadExpectedLen = -1;
return;
}
} else if (mNextReadExpectedLen < mTotalReadLen) {
Log.e(TAG, "handleMessageRead: Unexpected receive buffer of length=" + len
+ ", expected len=" + mNextReadExpectedLen);
}
}
private void handleMessageWrite(Message msg) {
byte[] buffer = (byte[]) msg.obj;
int len = buffer.length;
showMessage("LE CoC Server wrote " + len + " bytes" + ", mNextWriteExpectedLen="
+ mNextWriteExpectedLen);
if (len == mNextWriteExpectedLen) {
if (mNextWriteCompletionIntent != null) {
Intent intent = new Intent(mNextWriteCompletionIntent);
sendBroadcast(intent);
}
} else {
Log.d(TAG, "handleMessageWrite: unrecognized length=" + len);
}
mNextWriteCompletionIntent = null;
mNextWriteExpectedLen = -1;
}
private class ChatHandler extends Handler {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (DEBUG) {
Log.d(TAG, "ChatHandler.handleMessage: msg=" + msg);
}
switch (msg.what) {
case BluetoothChatService.MESSAGE_STATE_CHANGE:
processChatStateChange(msg.arg1);
break;
case BluetoothChatService.MESSAGE_READ:
handleMessageRead(msg);
break;
case BluetoothChatService.MESSAGE_WRITE:
handleMessageWrite(msg);
break;
}
}
}
/* Start the Chat Service to create the Bluetooth Server Socket for LE CoC */
private void createChatService() {
mChatService = new BluetoothChatService(this, new ChatHandler(), true);
mChatService.start(mSecure);
mPsm = mChatService.getPsm(mSecure);
if (DEBUG) {
Log.d(TAG, "createChatService: assigned PSM=" + mPsm);
}
if (mPsm > 0x00ff) {
Log.e(TAG, "createChatService: Invalid PSM=" + mPsm);
}
// Notify that the PSM is read
Intent intent = new Intent(BLE_PSM_READ);
sendBroadcast(intent);
// Set the PSM value in the PSM characteristics in the GATT Server.
mLePsmCharacteristic.setValue(mPsm, BluetoothGattCharacteristic.FORMAT_UINT8, 0);
}
private void startAdvertise() {
if (DEBUG) {
Log.d(TAG, "startAdvertise");
}
AdvertiseData data = new AdvertiseData.Builder()
.addServiceData(new ParcelUuid(ADV_COC_SERVICE_UUID), new byte[]{1,2,3})
.addServiceUuid(new ParcelUuid(ADV_COC_SERVICE_UUID))
.build();
AdvertiseSettings setting = new AdvertiseSettings.Builder()
.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY)
.setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM)
.setConnectable(true)
.build();
mAdvertiser.startAdvertising(setting, data, mAdvertiseCallback);
}
private void stopAdvertise() {
if (DEBUG) {
Log.d(TAG, "stopAdvertise");
}
if (mAdvertiser != null) {
mAdvertiser.stopAdvertising(mAdvertiseCallback);
}
}
private final AdvertiseCallback mAdvertiseCallback = new AdvertiseCallback(){
@Override
public void onStartFailure(int errorCode) {
// Implementation for API Test.
super.onStartFailure(errorCode);
if (DEBUG) {
Log.d(TAG, "onStartFailure");
}
if (errorCode == ADVERTISE_FAILED_FEATURE_UNSUPPORTED) {
notifyAdvertiseUnsupported();
} else {
notifyOpenFail();
}
}
@Override
public void onStartSuccess(AdvertiseSettings settingsInEffect) {
// Implementation for API Test.
super.onStartSuccess(settingsInEffect);
if (DEBUG) {
Log.d(TAG, "onStartSuccess");
}
}
};
/*protected*/ static void dumpService(BluetoothGattService service, int level) {
String indent = "";
for (int i = 0; i < level; ++i) {
indent += " ";
}
Log.d(TAG, indent + "[service]");
Log.d(TAG, indent + "UUID: " + service.getUuid());
Log.d(TAG, indent + " [characteristics]");
for (BluetoothGattCharacteristic ch : service.getCharacteristics()) {
Log.d(TAG, indent + " UUID: " + ch.getUuid());
Log.d(TAG, indent + " properties: "
+ String.format("0x%02X", ch.getProperties()));
Log.d(TAG, indent + " permissions: "
+ String.format("0x%02X", ch.getPermissions()));
Log.d(TAG, indent + " [descriptors]");
for (BluetoothGattDescriptor d : ch.getDescriptors()) {
Log.d(TAG, indent + " UUID: " + d.getUuid());
Log.d(TAG, indent + " permissions: "
+ String.format("0x%02X", d.getPermissions()));
}
}
if (service.getIncludedServices() != null) {
Log.d(TAG, indent + " [included services]");
for (BluetoothGattService s : service.getIncludedServices()) {
dumpService(s, level + 1);
}
}
}
}