1 /* 2 * Copyright (C) 2014 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.AlertDialog; 20 import android.app.Dialog; 21 import android.app.ProgressDialog; 22 import android.bluetooth.BluetoothAdapter; 23 import android.bluetooth.BluetoothManager; 24 import android.content.BroadcastReceiver; 25 import android.content.Context; 26 import android.content.DialogInterface; 27 import android.content.Intent; 28 import android.content.IntentFilter; 29 import android.os.Bundle; 30 import android.os.Handler; 31 import android.widget.ListView; 32 33 import com.android.cts.verifier.PassFailButtons; 34 import com.android.cts.verifier.R; 35 36 import java.util.ArrayList; 37 import java.util.List; 38 import android.util.Log; 39 40 public class BleClientTestBaseActivity extends PassFailButtons.Activity { 41 public static final String TAG = "BleClientTestBase"; 42 43 private static final boolean STEP_EXECUTION = false; 44 45 private static final int PASS_FLAG_CONNECT = 0x1; 46 private static final int PASS_FLAG_DISCOVER = 0x2; 47 private static final int PASS_FLAG_READ_CHARACTERISTIC = 0x4; 48 private static final int PASS_FLAG_WRITE_CHARACTERISTIC = 0x8; 49 private static final int PASS_FLAG_RELIABLE_WRITE = 0x10; 50 private static final int PASS_FLAG_NOTIFY_CHARACTERISTIC = 0x20; 51 private static final int PASS_FLAG_READ_DESCRIPTOR = 0x40; 52 private static final int PASS_FLAG_WRITE_DESCRIPTOR = 0x80; 53 private static final int PASS_FLAG_READ_RSSI = 0x100; 54 private static final int PASS_FLAG_DISCONNECT = 0x200; 55 private static final int PASS_FLAG_READ_CHARACTERISTIC_NO_PERMISSION = 0x400; 56 private static final int PASS_FLAG_WRITE_CHARACTERISTIC_NO_PERMISSION = 0x800; 57 private static final int PASS_FLAG_READ_DESCRIPTOR_NO_PERMISSION = 0x1000; 58 private static final int PASS_FLAG_WRITE_DESCRIPTOR_NO_PERMISSION = 0x2000; 59 private static final int PASS_FLAG_MTU_CHANGE_23BYTES = 0x4000; 60 private static final int PASS_FLAG_INDICATE_CHARACTERISTIC = 0x8000; 61 private static final int PASS_FLAG_MTU_CHANGE_512BYTES = 0x10000; 62 private static final int PASS_FLAG_RELIABLE_WRITE_BAD_RESP = 0x20000; 63 private static final int PASS_FLAG_ALL = 0x3FFFF; 64 65 private final int BLE_CLIENT_CONNECT = 0; 66 private final int BLE_BLE_DISCOVER_SERVICE = 1; 67 private final int BLE_READ_CHARACTERISTIC = 2; 68 private final int BLE_WRITE_CHARACTERISTIC = 3; 69 private final int BLE_REQUEST_MTU_23BYTES = 4; 70 private final int BLE_REQUEST_MTU_512BYTES = 5; 71 private final int BLE_READ_CHARACTERISTIC_NO_PERMISSION = 6; 72 private final int BLE_WRITE_CHARACTERISTIC_NO_PERMISSION = 7; 73 private final int BLE_RELIABLE_WRITE = 8; 74 private final int BLE_RELIABLE_WRITE_BAD_RESP = 9; 75 private final int BLE_NOTIFY_CHARACTERISTIC = 9; //10; 76 private final int BLE_INDICATE_CHARACTERISTIC = 10; //11; 77 private final int BLE_READ_DESCRIPTOR = 11; //12; 78 private final int BLE_WRITE_DESCRIPTOR = 12; //13; 79 private final int BLE_READ_DESCRIPTOR_NO_PERMISSION = 13; //14; 80 private final int BLE_WRITE_DESCRIPTOR_NO_PERMISSION = 14; //15; 81 private final int BLE_READ_RSSI = 15; //16; 82 private final int BLE_CLIENT_DISCONNECT = 15; //16; //17; 83 84 private TestAdapter mTestAdapter; 85 private long mPassed; 86 private Dialog mDialog; 87 private Handler mHandler; 88 89 @Override onCreate(Bundle savedInstanceState)90 public void onCreate(Bundle savedInstanceState) { 91 super.onCreate(savedInstanceState); 92 setContentView(R.layout.ble_server_start); 93 setPassFailButtonClickListeners(); 94 getPassButton().setEnabled(false); 95 96 mTestAdapter = new TestAdapter(this, setupTestList()); 97 ListView listView = (ListView) findViewById(R.id.ble_server_tests); 98 listView.setAdapter(mTestAdapter); 99 100 mPassed = 0; 101 mHandler = new Handler(); 102 } 103 104 @Override onResume()105 public void onResume() { 106 super.onResume(); 107 108 IntentFilter filter = new IntentFilter(); 109 filter.addAction(BleClientService.BLE_BLUETOOTH_CONNECTED); 110 filter.addAction(BleClientService.BLE_BLUETOOTH_DISCONNECTED); 111 filter.addAction(BleClientService.BLE_SERVICES_DISCOVERED); 112 filter.addAction(BleClientService.BLE_MTU_CHANGED_23BYTES); 113 filter.addAction(BleClientService.BLE_MTU_CHANGED_512BYTES); 114 filter.addAction(BleClientService.BLE_CHARACTERISTIC_READ); 115 filter.addAction(BleClientService.BLE_CHARACTERISTIC_WRITE); 116 filter.addAction(BleClientService.BLE_CHARACTERISTIC_CHANGED); 117 filter.addAction(BleClientService.BLE_DESCRIPTOR_READ); 118 filter.addAction(BleClientService.BLE_DESCRIPTOR_WRITE); 119 filter.addAction(BleClientService.BLE_RELIABLE_WRITE_COMPLETED); 120 filter.addAction(BleClientService.BLE_RELIABLE_WRITE_BAD_RESP_COMPLETED); 121 filter.addAction(BleClientService.BLE_READ_REMOTE_RSSI); 122 filter.addAction(BleClientService.BLE_CHARACTERISTIC_READ_NOPERMISSION); 123 filter.addAction(BleClientService.BLE_CHARACTERISTIC_WRITE_NOPERMISSION); 124 filter.addAction(BleClientService.BLE_DESCRIPTOR_READ_NOPERMISSION); 125 filter.addAction(BleClientService.BLE_DESCRIPTOR_WRITE_NOPERMISSION); 126 filter.addAction(BleClientService.BLE_CHARACTERISTIC_INDICATED); 127 filter.addAction(BleClientService.BLE_BLUETOOTH_DISABLED); 128 filter.addAction(BleClientService.BLE_BLUETOOTH_MISMATCH_SECURE); 129 filter.addAction(BleClientService.BLE_BLUETOOTH_MISMATCH_INSECURE); 130 filter.addAction(BleClientService.BLE_CLIENT_ERROR); 131 132 registerReceiver(mBroadcast, filter); 133 } 134 135 @Override onPause()136 public void onPause() { 137 super.onPause(); 138 unregisterReceiver(mBroadcast); 139 closeDialog(); 140 } 141 closeDialog()142 private synchronized void closeDialog() { 143 if (mDialog != null) { 144 mDialog.dismiss(); 145 mDialog = null; 146 } 147 } 148 showProgressDialog()149 private synchronized void showProgressDialog() { 150 closeDialog(); 151 152 ProgressDialog dialog = new ProgressDialog(this); 153 dialog.setTitle(R.string.ble_test_running); 154 dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER); 155 dialog.setMessage(getString(R.string.ble_test_running_message)); 156 dialog.setCanceledOnTouchOutside(false); 157 mDialog = dialog; 158 mDialog.show(); 159 } 160 setupTestList()161 private List<Integer> setupTestList() { 162 ArrayList<Integer> testList = new ArrayList<Integer>(); 163 testList.add(R.string.ble_client_connect_name); 164 testList.add(R.string.ble_discover_service_name); 165 testList.add(R.string.ble_read_characteristic_name); 166 testList.add(R.string.ble_write_characteristic_name); 167 testList.add(R.string.ble_mtu_23_name); 168 testList.add(R.string.ble_mtu_512_name); 169 testList.add(R.string.ble_read_characteristic_nopermission_name); 170 testList.add(R.string.ble_write_characteristic_nopermission_name); 171 testList.add(R.string.ble_reliable_write_name); 172 // testList.add(R.string.ble_reliable_write_bad_resp_name); 173 testList.add(R.string.ble_notify_characteristic_name); 174 testList.add(R.string.ble_indicate_characteristic_name); 175 testList.add(R.string.ble_read_descriptor_name); 176 testList.add(R.string.ble_write_descriptor_name); 177 testList.add(R.string.ble_read_descriptor_nopermission_name); 178 testList.add(R.string.ble_write_descriptor_nopermission_name); 179 // TODO: too flaky b/34951749 180 // testList.add(R.string.ble_read_rssi_name); 181 testList.add(R.string.ble_client_disconnect_name); 182 183 return testList; 184 } 185 showErrorDialog(int titleId, int messageId, boolean finish)186 private void showErrorDialog(int titleId, int messageId, boolean finish) { 187 AlertDialog.Builder builder = new AlertDialog.Builder(this) 188 .setTitle(titleId) 189 .setMessage(messageId); 190 if (finish) { 191 builder.setOnCancelListener(new Dialog.OnCancelListener() { 192 @Override 193 public void onCancel(DialogInterface dialog) { 194 finish(); 195 } 196 }); 197 } 198 builder.create().show(); 199 } 200 shouldRebootBluetoothAfterTest()201 public boolean shouldRebootBluetoothAfterTest() { 202 return false; 203 } 204 205 private BroadcastReceiver mBroadcast = new BroadcastReceiver() { 206 @Override 207 public void onReceive(Context context, Intent intent) { 208 boolean showProgressDialog = false; 209 closeDialog(); 210 211 String action = intent.getAction(); 212 String newAction = null; 213 String actionName = null; 214 long previousPassed = mPassed; 215 final Intent startIntent = new Intent(BleClientTestBaseActivity.this, BleClientService.class); 216 if (action != null) { 217 Log.d(TAG, "Processing " + action); 218 } 219 switch (action) { 220 case BleClientService.BLE_BLUETOOTH_DISABLED: 221 showErrorDialog(R.string.ble_bluetooth_disable_title, R.string.ble_bluetooth_disable_message, true); 222 break; 223 case BleClientService.BLE_BLUETOOTH_CONNECTED: 224 actionName = getString(R.string.ble_client_connect_name); 225 mTestAdapter.setTestPass(BLE_CLIENT_CONNECT); 226 mPassed |= PASS_FLAG_CONNECT; 227 // execute service discovery test 228 newAction = BleClientService.BLE_CLIENT_ACTION_BLE_DISCOVER_SERVICE; 229 break; 230 case BleClientService.BLE_SERVICES_DISCOVERED: 231 actionName = getString(R.string.ble_discover_service_name); 232 mTestAdapter.setTestPass(BLE_BLE_DISCOVER_SERVICE); 233 mPassed |= PASS_FLAG_DISCOVER; 234 // execute MTU requesting test (23bytes) 235 newAction = BleClientService.BLE_CLIENT_ACTION_READ_CHARACTERISTIC; 236 break; 237 case BleClientService.BLE_MTU_CHANGED_23BYTES: 238 actionName = getString(R.string.ble_mtu_23_name); 239 mTestAdapter.setTestPass(BLE_REQUEST_MTU_23BYTES); 240 mPassed |= PASS_FLAG_MTU_CHANGE_23BYTES; 241 // execute MTU requesting test (512bytes) 242 newAction = BleClientService.BLE_CLIENT_ACTION_REQUEST_MTU_512; 243 showProgressDialog = true; 244 break; 245 case BleClientService.BLE_MTU_CHANGED_512BYTES: 246 actionName = getString(R.string.ble_mtu_512_name); 247 mTestAdapter.setTestPass(BLE_REQUEST_MTU_512BYTES); 248 mPassed |= PASS_FLAG_MTU_CHANGE_512BYTES; 249 // execute characteristic reading test 250 newAction = BleClientService.BLE_CLIENT_ACTION_READ_CHARACTERISTIC_NO_PERMISSION; 251 break; 252 case BleClientService.BLE_CHARACTERISTIC_READ: 253 actionName = getString(R.string.ble_read_characteristic_name); 254 mTestAdapter.setTestPass(BLE_READ_CHARACTERISTIC); 255 mPassed |= PASS_FLAG_READ_CHARACTERISTIC; 256 // execute characteristic writing test 257 newAction = BleClientService.BLE_CLIENT_ACTION_WRITE_CHARACTERISTIC; 258 break; 259 case BleClientService.BLE_CHARACTERISTIC_WRITE: 260 actionName = getString(R.string.ble_write_characteristic_name); 261 mTestAdapter.setTestPass(BLE_WRITE_CHARACTERISTIC); 262 mPassed |= PASS_FLAG_WRITE_CHARACTERISTIC; 263 newAction = BleClientService.BLE_CLIENT_ACTION_REQUEST_MTU_23; 264 showProgressDialog = true; 265 break; 266 case BleClientService.BLE_CHARACTERISTIC_READ_NOPERMISSION: 267 actionName = getString(R.string.ble_read_characteristic_nopermission_name); 268 mTestAdapter.setTestPass(BLE_READ_CHARACTERISTIC_NO_PERMISSION); 269 mPassed |= PASS_FLAG_READ_CHARACTERISTIC_NO_PERMISSION; 270 // execute unpermitted characteristic writing test 271 newAction = BleClientService.BLE_CLIENT_ACTION_WRITE_CHARACTERISTIC_NO_PERMISSION; 272 break; 273 case BleClientService.BLE_CHARACTERISTIC_WRITE_NOPERMISSION: 274 actionName = getString(R.string.ble_write_characteristic_nopermission_name); 275 mTestAdapter.setTestPass(BLE_WRITE_CHARACTERISTIC_NO_PERMISSION); 276 mPassed |= PASS_FLAG_WRITE_CHARACTERISTIC_NO_PERMISSION; 277 // execute reliable write test 278 newAction = BleClientService.BLE_CLIENT_ACTION_RELIABLE_WRITE; 279 showProgressDialog = true; 280 break; 281 case BleClientService.BLE_RELIABLE_WRITE_COMPLETED: 282 actionName = getString(R.string.ble_reliable_write_name); 283 mTestAdapter.setTestPass(BLE_RELIABLE_WRITE); 284 mPassed |= PASS_FLAG_RELIABLE_WRITE; 285 // newAction = BleClientService.BLE_CLIENT_ACTION_RELIABLE_WRITE_BAD_RESP; 286 287 // skip Reliable write (bad response) test 288 mPassed |= PASS_FLAG_RELIABLE_WRITE_BAD_RESP; 289 Log.d(TAG, "Skip PASS_FLAG_RELIABLE_WRITE_BAD_RESP."); 290 newAction = BleClientService.BLE_CLIENT_ACTION_NOTIFY_CHARACTERISTIC; 291 showProgressDialog = true; 292 break; 293 case BleClientService.BLE_RELIABLE_WRITE_BAD_RESP_COMPLETED: { 294 actionName = getString(R.string.ble_reliable_write_bad_resp_name); 295 if(!intent.hasExtra(BleClientService.EXTRA_ERROR_MESSAGE)) { 296 mPassed |= PASS_FLAG_RELIABLE_WRITE_BAD_RESP; 297 mTestAdapter.setTestPass(BLE_RELIABLE_WRITE_BAD_RESP); 298 } 299 // execute notification test 300 newAction = BleClientService.BLE_CLIENT_ACTION_NOTIFY_CHARACTERISTIC; 301 showProgressDialog = true; 302 } 303 break; 304 case BleClientService.BLE_CHARACTERISTIC_CHANGED: 305 actionName = getString(R.string.ble_notify_characteristic_name); 306 mTestAdapter.setTestPass(BLE_NOTIFY_CHARACTERISTIC); 307 mPassed |= PASS_FLAG_NOTIFY_CHARACTERISTIC; 308 // execute indication test 309 newAction = BleClientService.BLE_CLIENT_ACTION_INDICATE_CHARACTERISTIC; 310 showProgressDialog = true; 311 break; 312 case BleClientService.BLE_CHARACTERISTIC_INDICATED: 313 actionName = getString(R.string.ble_indicate_characteristic_name); 314 mTestAdapter.setTestPass(BLE_INDICATE_CHARACTERISTIC); 315 mPassed |= PASS_FLAG_INDICATE_CHARACTERISTIC; 316 // execute descriptor reading test 317 newAction = BleClientService.BLE_CLIENT_ACTION_READ_DESCRIPTOR; 318 break; 319 case BleClientService.BLE_DESCRIPTOR_READ: 320 actionName = getString(R.string.ble_read_descriptor_name); 321 mTestAdapter.setTestPass(BLE_READ_DESCRIPTOR); 322 mPassed |= PASS_FLAG_READ_DESCRIPTOR; 323 // execute descriptor writing test 324 newAction = BleClientService.BLE_CLIENT_ACTION_WRITE_DESCRIPTOR; 325 break; 326 case BleClientService.BLE_DESCRIPTOR_WRITE: 327 actionName = getString(R.string.ble_write_descriptor_name); 328 mTestAdapter.setTestPass(BLE_WRITE_DESCRIPTOR); 329 mPassed |= PASS_FLAG_WRITE_DESCRIPTOR; 330 // execute unpermitted descriptor reading test 331 newAction = BleClientService.BLE_CLIENT_ACTION_READ_DESCRIPTOR_NO_PERMISSION; 332 break; 333 case BleClientService.BLE_DESCRIPTOR_READ_NOPERMISSION: 334 actionName = getString(R.string.ble_read_descriptor_nopermission_name); 335 mTestAdapter.setTestPass(BLE_READ_DESCRIPTOR_NO_PERMISSION); 336 mPassed |= PASS_FLAG_READ_DESCRIPTOR_NO_PERMISSION; 337 // execute unpermitted descriptor writing test 338 newAction = BleClientService.BLE_CLIENT_ACTION_WRITE_DESCRIPTOR_NO_PERMISSION; 339 break; 340 case BleClientService.BLE_DESCRIPTOR_WRITE_NOPERMISSION: 341 actionName = getString(R.string.ble_write_descriptor_nopermission_name); 342 mTestAdapter.setTestPass(BLE_WRITE_DESCRIPTOR_NO_PERMISSION); 343 mPassed |= PASS_FLAG_WRITE_DESCRIPTOR_NO_PERMISSION; 344 // TODO: too flaky b/34951749 345 // execute RSSI requesting test 346 // newAction = BleClientService.BLE_CLIENT_ACTION_READ_RSSI; 347 // execute disconnection test 348 mPassed |= PASS_FLAG_READ_RSSI; 349 Log.d(TAG, "Skip PASS_FLAG_READ_RSSI."); 350 newAction = BleClientService.BLE_CLIENT_ACTION_CLIENT_DISCONNECT; 351 break; 352 case BleClientService.BLE_READ_REMOTE_RSSI: 353 actionName = getString(R.string.ble_read_rssi_name); 354 mTestAdapter.setTestPass(BLE_READ_RSSI); 355 mPassed |= PASS_FLAG_READ_RSSI; 356 // execute disconnection test 357 newAction = BleClientService.BLE_CLIENT_ACTION_CLIENT_DISCONNECT; 358 break; 359 case BleClientService.BLE_BLUETOOTH_DISCONNECTED: 360 mTestAdapter.setTestPass(BLE_CLIENT_DISCONNECT); 361 mPassed |= PASS_FLAG_DISCONNECT; 362 // all test done 363 newAction = null; 364 break; 365 case BleClientService.BLE_BLUETOOTH_MISMATCH_SECURE: 366 showErrorDialog(R.string.ble_bluetooth_mismatch_title, R.string.ble_bluetooth_mismatch_secure_message, true); 367 break; 368 case BleClientService.BLE_BLUETOOTH_MISMATCH_INSECURE: 369 showErrorDialog(R.string.ble_bluetooth_mismatch_title, R.string.ble_bluetooth_mismatch_insecure_message, true); 370 break; 371 } 372 373 if (previousPassed != mPassed) { 374 String logMessage = String.format("Passed Flags has changed from 0x%08X to 0x%08X. Delta=0x%08X", 375 previousPassed, mPassed, mPassed ^ previousPassed); 376 Log.d(TAG, logMessage); 377 } 378 379 mTestAdapter.notifyDataSetChanged(); 380 381 if (newAction != null) { 382 Log.d(TAG, "Starting " + newAction); 383 startIntent.setAction(newAction); 384 if (STEP_EXECUTION) { 385 closeDialog(); 386 final boolean showProgressDialogValue = showProgressDialog; 387 mDialog = new AlertDialog.Builder(BleClientTestBaseActivity.this) 388 .setTitle(actionName) 389 .setMessage(R.string.ble_test_finished) 390 .setCancelable(false) 391 .setPositiveButton(R.string.ble_test_next, 392 new DialogInterface.OnClickListener() { 393 @Override 394 public void onClick(DialogInterface dialog, int which) { 395 closeDialog(); 396 if (showProgressDialogValue) { 397 showProgressDialog(); 398 } 399 startService(startIntent); 400 } 401 }) 402 .show(); 403 } else { 404 if (showProgressDialog) { 405 showProgressDialog(); 406 } 407 startService(startIntent); 408 } 409 } else { 410 closeDialog(); 411 } 412 413 if (mPassed == PASS_FLAG_ALL) { 414 Log.d(TAG, "All Tests Passed."); 415 if (shouldRebootBluetoothAfterTest()) { 416 mBtPowerSwitcher.executeSwitching(); 417 } else { 418 getPassButton().setEnabled(true); 419 } 420 } 421 } 422 }; 423 424 private static final long BT_ON_DELAY = 10000; 425 private final BluetoothPowerSwitcher mBtPowerSwitcher = new BluetoothPowerSwitcher(); 426 private class BluetoothPowerSwitcher extends BroadcastReceiver { 427 428 private boolean mIsSwitching = false; 429 private BluetoothAdapter mAdapter; 430 executeSwitching()431 public void executeSwitching() { 432 if (mAdapter == null) { 433 BluetoothManager btMgr = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); 434 mAdapter = btMgr.getAdapter(); 435 } 436 437 if (!mIsSwitching) { 438 IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED); 439 registerReceiver(this, filter); 440 mIsSwitching = true; 441 mHandler.postDelayed(new Runnable() { 442 @Override 443 public void run() { 444 mAdapter.disable(); 445 } 446 }, 1000); 447 showProgressDialog(); 448 } 449 } 450 451 @Override onReceive(Context context, Intent intent)452 public void onReceive(Context context, Intent intent) { 453 if (intent.getAction().equals(BluetoothAdapter.ACTION_STATE_CHANGED)) { 454 int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1); 455 if (state == BluetoothAdapter.STATE_OFF) { 456 mHandler.postDelayed(new Runnable() { 457 @Override 458 public void run() { 459 mAdapter.enable(); 460 } 461 }, BT_ON_DELAY); 462 } else if (state == BluetoothAdapter.STATE_ON) { 463 mIsSwitching = false; 464 unregisterReceiver(this); 465 getPassButton().setEnabled(true); 466 closeDialog(); 467 } 468 } 469 } 470 } 471 472 } 473