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