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