Added Bluetooth LE tests

Added BLE API tests to improve BLE connectivity.
Tests:
- Connection (Client / Server role)
- Read and Write Cararacterustic and Descriptors

Change-Id: I53f29832870fa349319e2549d81feab92f76ad3a
Signed-off-by: Satomi <michitsuta@casio.co.jp>
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 4760d1f..8d4bd63 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -154,209 +154,769 @@
                     android:value="android.software.backup" />
         </activity>
 
-        <activity android:name=".bluetooth.BluetoothTestActivity"
-                android:label="@string/bluetooth_test"
-                android:configChanges="keyboardHidden|orientation|screenSize">
+<!--            CTS Verifier Bluetooth Test Top Screen -->
+        <activity
+            android:name=".bluetooth.BluetoothTestActivity"
+            android:configChanges="keyboardHidden|orientation|screenSize"
+            android:label="@string/bluetooth_test" >
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
+
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
-            <meta-data android:name="test_category" android:value="@string/test_category_networking" />
-            <meta-data android:name="test_required_features" android:value="android.hardware.bluetooth" />
+
+            <meta-data
+                android:name="test_category"
+                android:value="@string/test_category_networking" />
+            <meta-data
+                android:name="test_required_features"
+                android:value="android.hardware.bluetooth" />
         </activity>
 
-        <activity android:name=".bluetooth.BluetoothToggleActivity"
-                android:label="@string/bt_toggle_bluetooth"
-                android:configChanges="keyboardHidden|orientation|screenSize">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.cts.intent.category.MANUAL_TEST" />
-            </intent-filter>
-            <meta-data android:name="test_category" android:value="@string/bt_control" />
-            <meta-data android:name="test_parent" android:value="com.android.cts.verifier.bluetooth.BluetoothTestActivity" />
-            <meta-data android:name="test_excluded_features" android:value="android.software.leanback" />
-        </activity>
-
-        <activity android:name=".bluetooth.SecureServerActivity"
-                android:label="@string/bt_secure_server"
-                android:configChanges="keyboardHidden|orientation|screenSize">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.cts.intent.category.MANUAL_TEST" />
-            </intent-filter>
-            <meta-data android:name="test_category" android:value="@string/bt_device_communication" />
-            <meta-data android:name="test_parent" android:value="com.android.cts.verifier.bluetooth.BluetoothTestActivity" />
-        </activity>
-
-        <activity android:name=".bluetooth.InsecureServerActivity"
-                android:label="@string/bt_insecure_server"
-                android:configChanges="keyboardHidden|orientation|screenSize">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.cts.intent.category.MANUAL_TEST" />
-            </intent-filter>
-            <meta-data android:name="test_category" android:value="@string/bt_device_communication" />
-            <meta-data android:name="test_parent" android:value="com.android.cts.verifier.bluetooth.BluetoothTestActivity" />
-        </activity>
-
-        <activity android:name=".bluetooth.SecureClientActivity"
-                android:label="@string/bt_secure_client"
-                android:configChanges="keyboardHidden|orientation|screenSize">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.cts.intent.category.MANUAL_TEST" />
-            </intent-filter>
-            <meta-data android:name="test_category" android:value="@string/bt_device_communication" />
-            <meta-data android:name="test_parent" android:value="com.android.cts.verifier.bluetooth.BluetoothTestActivity" />
-        </activity>
-
-        <activity android:name=".bluetooth.InsecureClientActivity"
-                android:label="@string/bt_insecure_client"
-                android:configChanges="keyboardHidden|orientation|screenSize">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.cts.intent.category.MANUAL_TEST" />
-            </intent-filter>
-            <meta-data android:name="test_category" android:value="@string/bt_device_communication" />
-            <meta-data android:name="test_parent" android:value="com.android.cts.verifier.bluetooth.BluetoothTestActivity" />
-        </activity>
-
-        <activity android:name=".bluetooth.ConnectionAccessServerActivity"
-                android:label="@string/bt_connection_access_server"
-                android:configChanges="keyboardHidden|orientation|screenSize">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-            </intent-filter>
-            <meta-data android:name="test_category" android:value="@string/bt_device_communication" />
-            <meta-data android:name="test_parent" android:value="com.android.cts.verifier.bluetooth.BluetoothTestActivity" />
-        </activity>
-
-        <activity android:name=".bluetooth.ConnectionAccessClientActivity"
-                android:label="@string/bt_connection_access_client"
-                android:configChanges="keyboardHidden|orientation|screenSize">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-            </intent-filter>
-            <meta-data android:name="test_category" android:value="@string/bt_device_communication" />
-            <meta-data android:name="test_parent" android:value="com.android.cts.verifier.bluetooth.BluetoothTestActivity" />
-        </activity>
-
-        <activity android:name=".bluetooth.DevicePickerActivity"
-                android:label="@string/bt_device_picker"
-                android:configChanges="keyboardHidden|orientation|screenSize" />
-
-        <service android:name=".bluetooth.BleClientService"
-                android:label="@string/ble_client_service_name" />
-
-        <service android:name=".bluetooth.BleServerService"
-                android:label="ble_server_service_name" />
-
-        <service android:name=".bluetooth.BleAdvertiserService"
-                android:label="@string/ble_advertiser_service_name" />
-
-        <service android:name=".bluetooth.BleScannerService"
-                android:label="@string/ble_scanner_service_name" />
-
-        <!-- Uncomment until b/15657182, b/18283088 fixed
-        <activity android:name=".bluetooth.BleClientStartActivity"
-                android:label="@string/ble_client_test_name"
-                android:configChanges="keyboardHidden|orientation|screenSize">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.cts.intent.category.MANUAL_TEST" />
-            </intent-filter>
-            <meta-data android:name="test_category" android:value="@string/bt_le" />
-            <meta-data android:name="test_parent" android:value="com.android.cts.verifier.bluetooth.BluetoothTestActivity" />
-            <meta-data android:name="test_required_features"
-                       android:value="android.hardware.bluetooth_le"/>
-        </activity>
-
-        <activity android:name=".bluetooth.BleServerStartActivity"
-                android:label="@string/ble_server_start_name"
-                android:configChanges="keyboardHidden|orientation|screenSize">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.cts.intent.category.MANUAL_TEST" />
-            </intent-filter>
-            <meta-data android:name="test_category" android:value="@string/bt_le" />
-            <meta-data android:name="test_parent" android:value="com.android.cts.verifier.bluetooth.BluetoothTestActivity" />
-            <meta-data android:name="test_required_features"
-                       android:value="android.hardware.bluetooth_le"/>
-        </activity> -->
-
-        <activity android:name=".bluetooth.BleScannerTestActivity"
-                android:label="@string/ble_scanner_test_name"
-                android:configChanges="keyboardHidden|orientation|screenSize">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.cts.intent.category.MANUAL_TEST" />
-            </intent-filter>
-            <meta-data android:name="test_category" android:value="@string/bt_le" />
-            <meta-data android:name="test_parent" android:value="com.android.cts.verifier.bluetooth.BluetoothTestActivity" />
-            <meta-data android:name="test_required_features"
-                       android:value="android.hardware.bluetooth_le"/>
-        </activity>
-
-        <activity android:name=".bluetooth.BleScannerPowerLevelActivity"
-                android:label="@string/ble_power_level_name"
-                android:configChanges="keyboardHidden|orientation|screenSize">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.cts.intent.category.MANUAL_TEST" />
-            </intent-filter>
-            <meta-data android:name="test_category" android:value="@string/bt_le" />
-            <meta-data android:name="test_parent" android:value="com.android.cts.verifier.bluetooth.BleScannerTestActivity" />
-        </activity>
-
-        <!-- Comment out until we have a better way to validate the hardware scan filter
-        <activity android:name=".bluetooth.BleScannerHardwareScanFilterActivity"
-                android:label="@string/ble_scanner_scan_filter_name"
-                android:configChanges="keyboardHidden|orientation|screenSize">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.cts.intent.category.MANUAL_TEST" />
-            </intent-filter>
-            <meta-data android:name="test_category" android:value="@string/bt_le" />
-            <meta-data android:name="test_parent" android:value="com.android.cts.verifier.bluetooth.BleScannerTestActivity" />
-        </activity>
+        <!--
+             CTS Verifier Bluetooth Toggle Test Screen
+                 test category : bt_control
+                 test parent : BluetoothTestActivity
         -->
-
-        <activity android:name=".bluetooth.BleAdvertiserTestActivity"
-                android:label="@string/ble_advertiser_test_name"
-                android:configChanges="keyboardHidden|orientation|screenSize">
+        <activity
+            android:name=".bluetooth.BluetoothToggleActivity"
+            android:configChanges="keyboardHidden|orientation|screenSize"
+            android:label="@string/bt_toggle_bluetooth" >
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.cts.intent.category.MANUAL_TEST" />
-            </intent-filter>
-            <meta-data android:name="test_category" android:value="@string/bt_le" />
-            <meta-data android:name="test_parent" android:value="com.android.cts.verifier.bluetooth.BluetoothTestActivity" />
-            <meta-data android:name="test_required_features"
-                       android:value="android.hardware.bluetooth_le"/>
-         </activity>
 
-        <activity android:name=".bluetooth.BleAdvertiserPowerLevelActivity"
-                android:label="@string/ble_power_level_name"
-                android:configChanges="keyboardHidden|orientation|screenSize">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
-            <meta-data android:name="test_category" android:value="@string/bt_le" />
-            <meta-data android:name="test_parent" android:value="com.android.cts.verifier.bluetooth.BleAdvertiserTestActivity" />
+
+            <meta-data
+                android:name="test_category"
+                android:value="@string/bt_control" />
+            <meta-data
+                android:name="test_parent"
+                android:value="com.android.cts.verifier.bluetooth.BluetoothTestActivity" />
+            <meta-data
+                android:name="test_excluded_features"
+                android:value="android.software.leanback" />
         </activity>
 
-        <!-- Comment out until we have a better way to validate the hardware scan filter
-        <activity android:name=".bluetooth.BleAdvertiserHardwareScanFilterActivity"
-                android:label="@string/ble_advertiser_scan_filter_name"
-                android:configChanges="keyboardHidden|orientation|screenSize">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.cts.intent.category.MANUAL_TEST" />
-            </intent-filter>
-            <meta-data android:name="test_category" android:value="@string/bt_le" />
-            <meta-data android:name="test_parent" android:value="com.android.cts.verifier.bluetooth.BleAdvertiserTestActivity" />
-        </activity>
+        <!--
+             CTS Verifier Bluetooth Secure Server Test Screen
+                 test category : bt_device_communication
+                 test parent : BluetoothTestActivity
         -->
+        <activity
+            android:name=".bluetooth.SecureServerActivity"
+            android:configChanges="keyboardHidden|orientation|screenSize"
+            android:label="@string/bt_secure_server" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+
+            <meta-data
+                android:name="test_category"
+                android:value="@string/bt_device_communication" />
+            <meta-data
+                android:name="test_parent"
+                android:value="com.android.cts.verifier.bluetooth.BluetoothTestActivity" />
+        </activity>
+
+        <!--
+             CTS Verifier Bluetooth Insecure Server Test Screen
+                 test category : bt_device_communication
+                 test parent : BluetoothTestActivity
+        -->
+        <activity
+            android:name=".bluetooth.InsecureServerActivity"
+            android:configChanges="keyboardHidden|orientation|screenSize"
+            android:label="@string/bt_insecure_server" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+
+            <meta-data
+                android:name="test_category"
+                android:value="@string/bt_device_communication" />
+            <meta-data
+                android:name="test_parent"
+                android:value="com.android.cts.verifier.bluetooth.BluetoothTestActivity" />
+        </activity>
+
+        <!--
+             CTS Verifier Bluetooth Secure Client Test Screen
+                 test category : bt_device_communication
+                 test parent : BluetoothTestActivity
+        -->
+        <activity
+            android:name=".bluetooth.SecureClientActivity"
+            android:configChanges="keyboardHidden|orientation|screenSize"
+            android:label="@string/bt_secure_client" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+
+            <meta-data
+                android:name="test_category"
+                android:value="@string/bt_device_communication" />
+            <meta-data
+                android:name="test_parent"
+                android:value="com.android.cts.verifier.bluetooth.BluetoothTestActivity" />
+        </activity>
+
+        <!--
+             CTS Verifier Bluetooth Insecure Client Test Screen
+                 test category : bt_device_communication
+                 test parent : BluetoothTestActivity
+        -->
+        <activity
+            android:name=".bluetooth.InsecureClientActivity"
+            android:configChanges="keyboardHidden|orientation|screenSize"
+            android:label="@string/bt_insecure_client" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+
+            <meta-data
+                android:name="test_category"
+                android:value="@string/bt_device_communication" />
+            <meta-data
+                android:name="test_parent"
+                android:value="com.android.cts.verifier.bluetooth.BluetoothTestActivity" />
+        </activity>
+
+        <!--
+             CTS Verifier Bluetooth Connection Access Server Test Screen
+                 test category : bt_device_communication
+                 test parent : BluetoothTestActivity
+        -->
+        <!-- ********************* NOT MANUAL TEST! ******************** -->
+        <activity
+            android:name=".bluetooth.ConnectionAccessServerActivity"
+            android:configChanges="keyboardHidden|orientation|screenSize"
+            android:label="@string/bt_connection_access_server" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+            </intent-filter>
+
+            <meta-data
+                android:name="test_category"
+                android:value="@string/bt_device_communication" />
+            <meta-data
+                android:name="test_parent"
+                android:value="com.android.cts.verifier.bluetooth.BluetoothTestActivity" />
+        </activity>
+
+        <!--
+             CTS Verifier Bluetooth Connection Access Client Test Screen
+                 test category : bt_device_communication
+                 test parent : BluetoothTestActivity
+        -->
+        <!-- ********************* NOT MANUAL TEST! ******************** -->
+        <activity
+            android:name=".bluetooth.ConnectionAccessClientActivity"
+            android:configChanges="keyboardHidden|orientation|screenSize"
+            android:label="@string/bt_connection_access_client" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+            </intent-filter>
+
+            <meta-data
+                android:name="test_category"
+                android:value="@string/bt_device_communication" />
+            <meta-data
+                android:name="test_parent"
+                android:value="com.android.cts.verifier.bluetooth.BluetoothTestActivity" />
+        </activity>
+        <activity
+            android:name=".bluetooth.DevicePickerActivity"
+            android:configChanges="keyboardHidden|orientation|screenSize"
+            android:label="@string/bt_device_picker" />
+
+<!--
+     *****************************************************************************************
+     **                          Begin BLE Test Sub Layer Info                            ****
+     *****************************************************************************************
+        -->
+        <!-- CTS Verifier BLE Client Test Service -->
+        <service android:name=".bluetooth.BleClientService" />
+        <!-- CTS Verifier BLE Server Test Service -->
+        <service android:name=".bluetooth.BleServerService" />
+
+        <!-- CTS Verifier BLE Advertiser Test Service -->
+        <service android:name=".bluetooth.BleAdvertiserService" />
+        <!-- CTS Verifier BLE Scanner Test Service -->
+        <service android:name=".bluetooth.BleScannerService" />
+
+        <!-- CTS Verifier BLE Server Connection Priority Test Service -->
+        <service android:name=".bluetooth.BleConnectionPriorityServerService" />
+        <!-- CTS Verifier BLE Client Connection Priority Test Service -->
+        <service android:name=".bluetooth.BleConnectionPriorityClientService" />
+
+        <!-- CTS Verifier BLE Client Encrypted Test Service -->
+        <service android:name=".bluetooth.BleEncryptedClientService" />
+
+        <!-- CTS Verifier BLE Server Encrypted Test Service -->
+        <service android:name=".bluetooth.BleEncryptedServerService" />
+
+        <!--
+             =================================================================================
+             ==                     BLE Insecure Client Test Info                           ==
+             =================================================================================
+        -->
+        <!--
+            CTS Verifier BLE Insecure Client Test Top Screen
+                test category : bt_le
+                test parent : BluetoothTestActivity
+        -->
+        <activity
+            android:name=".bluetooth.BleInsecureClientTestListActivity"
+            android:configChanges="keyboardHidden|orientation|screenSize"
+            android:label="@string/ble_insecure_client_test_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+
+            <meta-data
+                android:name="test_category"
+                android:value="@string/bt_le" />
+            <meta-data
+                android:name="test_parent"
+                android:value="com.android.cts.verifier.bluetooth.BluetoothTestActivity" />
+            <meta-data
+                android:name="test_required_features"
+                android:value="android.hardware.bluetooth_le" />
+        </activity>
+
+
+        <!--
+             CTS Verifier BLE Insecure Client Test List Screen
+                 test category : bt_le
+                 test parent : BleInsecureClientTestListActivity
+        -->
+        <activity
+            android:name=".bluetooth.BleInsecureClientStartActivity"
+            android:configChanges="keyboardHidden|orientation|screenSize"
+            android:label="@string/ble_client_test_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+
+            <meta-data
+                android:name="test_category"
+                android:value="@string/bt_le" />
+            <meta-data
+                android:name="test_parent"
+                android:value="com.android.cts.verifier.bluetooth.BleInsecureClientTestListActivity" />
+            <meta-data
+                android:name="test_required_features"
+                android:value="android.hardware.bluetooth_le" />
+        </activity>
+
+        <!--
+            CTS Verifier BLE Insecure Client Connection Priority Test Screen
+                test category : bt_le
+                test parent : BleInsecureClientTestListActivity
+        -->
+        <activity
+            android:name=".bluetooth.BleInsecureConnectionPriorityClientTestActivity"
+            android:configChanges="keyboardHidden|orientation|screenSize"
+            android:label="@string/ble_connection_priority_client_name"
+            android:windowSoftInputMode="stateAlwaysHidden" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+
+            <meta-data
+                android:name="test_category"
+                android:value="@string/bt_le" />
+            <meta-data
+                android:name="test_parent"
+                android:value="com.android.cts.verifier.bluetooth.BleInsecureClientTestListActivity" />
+            <meta-data
+                android:name="test_required_features"
+                android:value="android.hardware.bluetooth_le" />
+        </activity>
+
+        <!--
+           CTS Verifier BLE Insecure Client Encrypted Test Screen
+               test category : bt_le
+               test parent : BleInsecureClientTestListActivity
+        -->
+        <activity
+            android:name=".bluetooth.BleInsecureEncryptedClientTestActivity"
+            android:configChanges="keyboardHidden|orientation|screenSize"
+            android:label="@string/ble_encrypted_client_name"
+            android:windowSoftInputMode="stateAlwaysHidden" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+
+            <meta-data
+                android:name="test_category"
+                android:value="@string/bt_le" />
+            <meta-data
+                android:name="test_parent"
+                android:value="com.android.cts.verifier.bluetooth.BleInsecureClientTestListActivity" />
+            <meta-data
+                android:name="test_required_features"
+                android:value="android.hardware.bluetooth_le" />
+        </activity>
+
+        <!--
+              =================================================================================
+              ==                     BLE Insecure Server Test Info                           ==
+              =================================================================================
+        -->
+        <!--
+             CTS Verifier BLE Insecure Server Test Top Screen
+                 test category : bt_le
+                 test parent : BluetoothTestActivity
+        -->
+        <activity
+            android:name=".bluetooth.BleInsecureServerTestListActivity"
+            android:configChanges="keyboardHidden|orientation|screenSize"
+            android:label="@string/ble_insecure_server_test_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+
+            <meta-data
+                android:name="test_category"
+                android:value="@string/bt_le" />
+            <meta-data
+                android:name="test_parent"
+                android:value="com.android.cts.verifier.bluetooth.BluetoothTestActivity" />
+            <meta-data
+                android:name="test_required_features"
+                android:value="android.hardware.bluetooth_le" />
+        </activity>
+
+        <!--
+              CTS Verifier BLE Insecure Server Test List Screen
+                  test category : bt_le
+                  test parent : BleInsecureServerTestListActivity
+        -->
+        <activity
+            android:name=".bluetooth.BleInsecureServerStartActivity"
+            android:configChanges="keyboardHidden|orientation|screenSize"
+            android:label="@string/ble_server_start_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+
+            <meta-data
+                android:name="test_category"
+                android:value="@string/bt_le" />
+            <meta-data
+                android:name="test_parent"
+                android:value="com.android.cts.verifier.bluetooth.BleInsecureServerTestListActivity" />
+            <meta-data
+                android:name="test_required_features"
+                android:value="android.hardware.bluetooth_le" />
+        </activity>
+
+        <!--
+            CTS Verifier BLE Insecure Server Connection Priority Test Screen
+                test category : bt_le
+                test parent : BleInsecureServerTestListActivity
+        -->
+        <activity
+            android:name=".bluetooth.BleInsecureConnectionPriorityServerTestActivity"
+            android:configChanges="keyboardHidden|orientation|screenSize"
+            android:label="@string/ble_connection_priority_server_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+
+            <meta-data
+                android:name="test_category"
+                android:value="@string/bt_le" />
+            <meta-data
+                android:name="test_parent"
+                android:value="com.android.cts.verifier.bluetooth.BleInsecureServerTestListActivity" />
+            <meta-data
+                android:name="test_required_features"
+                android:value="android.hardware.bluetooth_le" />
+        </activity>
+
+        <!--
+           CTS Verifier BLE Insecure Server Encrypted Test Screen
+               test category : bt_le
+               test parent : BleInsecureServerTestListActivity
+        -->
+        <activity
+            android:name=".bluetooth.BleInsecureEncryptedServerTestActivity"
+            android:configChanges="keyboardHidden|orientation|screenSize"
+            android:label="@string/ble_encrypted_server_name"
+            android:windowSoftInputMode="stateAlwaysHidden" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+
+            <meta-data
+                android:name="test_category"
+                android:value="@string/bt_le" />
+            <meta-data
+                android:name="test_parent"
+                android:value="com.android.cts.verifier.bluetooth.BleInsecureServerTestListActivity" />
+            <meta-data
+                android:name="test_required_features"
+                android:value="android.hardware.bluetooth_le" />
+        </activity>
+
+        <!--
+             =================================================================================
+             ==                      BLE Secure Client Test Info                            ==
+             =================================================================================
+        -->
+        <!--
+             CTS Verifier BLE Secure Client Test Top Screen
+                 test category : bt_le
+                 test parent : BluetoothTestActivity
+        -->
+        <activity
+            android:name=".bluetooth.BleSecureClientTestListActivity"
+            android:configChanges="keyboardHidden|orientation|screenSize"
+            android:label="@string/ble_secure_client_test_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+
+            <meta-data
+                android:name="test_category"
+                android:value="@string/bt_le" />
+            <meta-data
+                android:name="test_parent"
+                android:value="com.android.cts.verifier.bluetooth.BluetoothTestActivity" />
+            <meta-data
+                android:name="test_required_features"
+                android:value="android.hardware.bluetooth_le" />
+        </activity>
+
+        <!--
+             CTS Verifier BLE Secure Client Test List Screen
+                 test category : bt_le
+                 test parent : BleSecureClientTestListActivity
+        -->
+        <activity
+            android:name=".bluetooth.BleSecureClientStartActivity"
+            android:configChanges="keyboardHidden|orientation|screenSize"
+            android:label="@string/ble_client_test_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+
+            <meta-data
+                android:name="test_category"
+                android:value="@string/bt_le" />
+            <meta-data
+                android:name="test_parent"
+                android:value="com.android.cts.verifier.bluetooth.BleSecureClientTestListActivity" />
+            <meta-data
+                android:name="test_required_features"
+                android:value="android.hardware.bluetooth_le" />
+        </activity>
+
+        <!--
+            CTS Verifier BLE Secure Client Connection Priority Test Screen
+                test category : bt_le
+                test parent : BleSecureClientTestListActivity
+        -->
+        <activity
+            android:name=".bluetooth.BleSecureConnectionPriorityClientTestActivity"
+            android:configChanges="keyboardHidden|orientation|screenSize"
+            android:label="@string/ble_connection_priority_client_name"
+            android:windowSoftInputMode="stateAlwaysHidden" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+
+            <meta-data
+                android:name="test_category"
+                android:value="@string/bt_le" />
+            <meta-data
+                android:name="test_parent"
+                android:value="com.android.cts.verifier.bluetooth.BleSecureClientTestListActivity" />
+            <meta-data
+                android:name="test_required_features"
+                android:value="android.hardware.bluetooth_le" />
+        </activity>
+
+        <!--
+           CTS Verifier BLE Secure Client Encrypted Test Screen
+               test category : bt_le
+               test parent : BleSecureClientTestListActivity
+        -->
+        <activity
+            android:name=".bluetooth.BleSecureEncryptedClientTestActivity"
+            android:configChanges="keyboardHidden|orientation|screenSize"
+            android:label="@string/ble_encrypted_client_name"
+            android:windowSoftInputMode="stateAlwaysHidden" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+
+            <meta-data
+                android:name="test_category"
+                android:value="@string/bt_le" />
+            <meta-data
+                android:name="test_parent"
+                android:value="com.android.cts.verifier.bluetooth.BleSecureClientTestListActivity" />
+            <meta-data
+                android:name="test_required_features"
+                android:value="android.hardware.bluetooth_le" />
+        </activity>
+
+        <!--
+             =================================================================================
+             ==                      BLE Secure Server Test Info                            ==
+             =================================================================================
+        -->
+        <!--
+             CTS Verifier BLE Secure Server Test Top Screen
+                 test category : bt_le
+                 test parent : BluetoothTestActivity
+        -->
+        <activity
+            android:name=".bluetooth.BleSecureServerTestListActivity"
+            android:configChanges="keyboardHidden|orientation|screenSize"
+            android:label="@string/ble_secure_server_test_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+
+            <meta-data
+                android:name="test_category"
+                android:value="@string/bt_le" />
+            <meta-data
+                android:name="test_parent"
+                android:value="com.android.cts.verifier.bluetooth.BluetoothTestActivity" />
+            <meta-data
+                android:name="test_required_features"
+                android:value="android.hardware.bluetooth_le" />
+        </activity>
+
+        <!--
+            CTS Verifier BLE Secure Server Test List Screen
+                test category : bt_le
+                test parent : BleSecureServerTestListActivity
+        -->
+        <activity
+            android:name=".bluetooth.BleSecureServerStartActivity"
+            android:configChanges="keyboardHidden|orientation|screenSize"
+            android:label="@string/ble_server_start_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+
+            <meta-data
+                android:name="test_category"
+                android:value="@string/bt_le" />
+            <meta-data
+                android:name="test_parent"
+                android:value="com.android.cts.verifier.bluetooth.BleSecureServerTestListActivity" />
+            <meta-data
+                android:name="test_required_features"
+                android:value="android.hardware.bluetooth_le" />
+        </activity>
+
+        <!--
+            CTS Verifier BLE Secure Server Connection Priority Test Screen
+                test category : bt_le
+                test parent : BleSecureServerTestListActivity
+        -->
+        <activity
+            android:name=".bluetooth.BleSecureConnectionPriorityServerTestActivity"
+            android:configChanges="keyboardHidden|orientation|screenSize"
+            android:label="@string/ble_connection_priority_server_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+
+            <meta-data
+                android:name="test_category"
+                android:value="@string/bt_le" />
+            <meta-data
+                android:name="test_parent"
+                android:value="com.android.cts.verifier.bluetooth.BleSecureServerTestListActivity" />
+            <meta-data
+                android:name="test_required_features"
+                android:value="android.hardware.bluetooth_le" />
+        </activity>
+
+        <!--
+           CTS Verifier BLE Secure Server Encrypted Test Screen
+               test category : bt_le
+               test parent : BleSecureServerTestListActivity
+        -->
+        <activity
+            android:name=".bluetooth.BleSecureEncryptedServerTestActivity"
+            android:configChanges="keyboardHidden|orientation|screenSize"
+            android:label="@string/ble_encrypted_server_name"
+            android:windowSoftInputMode="stateAlwaysHidden" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+
+            <meta-data
+                android:name="test_category"
+                android:value="@string/bt_le" />
+            <meta-data
+                android:name="test_parent"
+                android:value="com.android.cts.verifier.bluetooth.BleSecureServerTestListActivity" />
+            <meta-data
+                android:name="test_required_features"
+                android:value="android.hardware.bluetooth_le" />
+        </activity>
+
+        <!--
+             =================================================================================
+             ==                      BLE Scanner Test Info                            ==
+             =================================================================================
+        -->
+        <!--
+            CTS Verifier BLE Client Scanner Screen
+                test category : bt_le
+                test parent : BluetoothTestActivity
+        -->
+        <activity
+            android:name=".bluetooth.BleScannerTestActivity"
+            android:configChanges="keyboardHidden|orientation|screenSize"
+            android:label="@string/ble_scanner_test_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+
+            <meta-data
+                android:name="test_category"
+                android:value="@string/bt_le" />
+            <meta-data
+                android:name="test_parent"
+                android:value="com.android.cts.verifier.bluetooth.BluetoothTestActivity" />
+            <meta-data
+                android:name="test_required_features"
+                android:value="android.hardware.bluetooth_le" />
+        </activity>
+
+        <!--
+            CTS Verifier BLE Scanner PowerLevel Test Screen
+                test category : bt_le
+                test parent : BleScannerTestActivity
+        -->
+        <activity
+            android:name=".bluetooth.BleScannerPowerLevelActivity"
+            android:configChanges="keyboardHidden|orientation|screenSize"
+            android:label="@string/ble_power_level_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+
+            <meta-data
+                android:name="test_category"
+                android:value="@string/bt_le" />
+            <meta-data
+                android:name="test_parent"
+                android:value="com.android.cts.verifier.bluetooth.BleScannerTestActivity" />
+        </activity>
+
+
+        <!--
+             =================================================================================
+             ==                      BLE Advertiser Test Info                            ==
+             =================================================================================
+        -->
+        <!--
+            CTS Verifier BLE Advertiser Screen
+                test category : bt_le
+                test parent : BluetoothTestActivity
+        -->
+        <activity
+            android:name=".bluetooth.BleAdvertiserTestActivity"
+            android:configChanges="keyboardHidden|orientation|screenSize"
+            android:label="@string/ble_advertiser_test_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+
+            <meta-data
+                android:name="test_category"
+                android:value="@string/bt_le" />
+            <meta-data
+                android:name="test_parent"
+                android:value="com.android.cts.verifier.bluetooth.BluetoothTestActivity" />
+            <meta-data
+                android:name="test_required_features"
+                android:value="android.hardware.bluetooth_le" />
+        </activity>
+
+        <!--
+            CTS Verifier BLE Advertiser PowerLevel Test Screen
+                test category : bt_le
+                test parent : BleAdvertiserTestActivity
+        -->
+        <activity
+            android:name=".bluetooth.BleAdvertiserPowerLevelActivity"
+            android:configChanges="keyboardHidden|orientation|screenSize"
+            android:label="@string/ble_power_level_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+
+            <meta-data
+                android:name="test_category"
+                android:value="@string/bt_le" />
+            <meta-data
+                android:name="test_parent"
+                android:value="com.android.cts.verifier.bluetooth.BleAdvertiserTestActivity" />
+        </activity>
+
 
         <activity android:name=".suid.SuidFilesActivity"
                 android:label="@string/suid_files"
diff --git a/apps/CtsVerifier/res/layout/ble_connection_priority_client_test.xml b/apps/CtsVerifier/res/layout/ble_connection_priority_client_test.xml
new file mode 100644
index 0000000..6dafbbe
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/ble_connection_priority_client_test.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>

+<!-- Copyright (C) 2016 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.

+-->

+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

+                android:layout_width="match_parent"

+                android:layout_height="match_parent"

+                android:orientation="vertical"

+                android:padding="10dip"

+    >

+    <include android:id="@+id/pass_fail_buttons"

+             android:layout_width="match_parent"

+             android:layout_height="wrap_content"

+             android:layout_alignParentBottom="true"

+             layout="@layout/pass_fail_buttons"

+        />

+    <ListView android:id="@+id/ble_client_connection_tests"

+              android:layout_height="wrap_content"

+              android:layout_width="match_parent"

+              android:layout_above="@id/pass_fail_buttons"

+              android:layout_alignParentTop="true"

+              android:padding="10dip"

+        />

+</RelativeLayout>

diff --git a/apps/CtsVerifier/res/layout/ble_connection_priority_server_test.xml b/apps/CtsVerifier/res/layout/ble_connection_priority_server_test.xml
new file mode 100644
index 0000000..2772ebe
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/ble_connection_priority_server_test.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>

+<!-- Copyright (C) 2016 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.

+-->

+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

+                android:layout_width="match_parent"

+                android:layout_height="match_parent"

+                android:orientation="vertical"

+                android:padding="10dip"

+    >

+    <include android:id="@+id/pass_fail_buttons"

+             android:layout_width="match_parent"

+             android:layout_height="wrap_content"

+             android:layout_alignParentBottom="true"

+             layout="@layout/pass_fail_buttons"

+        />

+    <ListView android:id="@+id/ble_server_connection_tests"

+              android:layout_height="wrap_content"

+              android:layout_width="match_parent"

+              android:layout_above="@id/pass_fail_buttons"

+              android:layout_alignParentTop="true"

+              android:padding="10dip"

+        />

+</RelativeLayout>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/layout/ble_encrypted_client_test.xml b/apps/CtsVerifier/res/layout/ble_encrypted_client_test.xml
new file mode 100644
index 0000000..7d42381
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/ble_encrypted_client_test.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>

+<!-- Copyright (C) 2016 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.

+-->

+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

+                android:layout_width="match_parent"

+                android:layout_height="match_parent"

+                android:orientation="vertical"

+                android:padding="10dip"

+    >

+    <include android:id="@+id/pass_fail_buttons"

+             android:layout_width="match_parent"

+             android:layout_height="wrap_content"

+             android:layout_alignParentBottom="true"

+             layout="@layout/pass_fail_buttons"

+        />

+    <ListView android:id="@+id/ble_client_enctypted_tests"

+              android:layout_height="wrap_content"

+              android:layout_width="match_parent"

+              android:layout_above="@id/pass_fail_buttons"

+              android:layout_alignParentTop="true"

+              android:padding="10dip"

+        />

+</RelativeLayout>

diff --git a/apps/CtsVerifier/res/layout/ble_encrypted_server_test.xml b/apps/CtsVerifier/res/layout/ble_encrypted_server_test.xml
new file mode 100644
index 0000000..35a8a5e
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/ble_encrypted_server_test.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>

+<!-- Copyright (C) 2016 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.

+-->

+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

+                android:layout_width="match_parent"

+                android:layout_height="match_parent"

+                android:orientation="vertical"

+                android:padding="10dip"

+    >

+    <include android:id="@+id/pass_fail_buttons"

+             android:layout_width="match_parent"

+             android:layout_height="wrap_content"

+             android:layout_alignParentBottom="true"

+             layout="@layout/pass_fail_buttons"

+        />

+    <ListView android:id="@+id/ble_server_enctypted_tests"

+              android:layout_height="wrap_content"

+              android:layout_width="match_parent"

+              android:layout_above="@id/pass_fail_buttons"

+              android:layout_alignParentTop="true"

+              android:padding="10dip"

+        />

+</RelativeLayout>

diff --git a/apps/CtsVerifier/res/layout/ble_insecure_encrypted_server_test.xml b/apps/CtsVerifier/res/layout/ble_insecure_encrypted_server_test.xml
new file mode 100644
index 0000000..2be5f69
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/ble_insecure_encrypted_server_test.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>

+<!-- Copyright (C) 2016 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.

+-->

+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

+                android:layout_width="match_parent"

+                android:layout_height="match_parent"

+                android:orientation="vertical"

+                android:padding="10dip"

+    >

+    <include android:id="@+id/pass_fail_buttons"

+             android:layout_width="match_parent"

+             android:layout_height="wrap_content"

+             android:layout_alignParentBottom="true"

+             layout="@layout/pass_fail_buttons"

+        />

+    <TextView android:id="@+id/ble_insecure_server_enctypted_text"

+              android:layout_height="wrap_content"

+              android:layout_width="wrap_content"

+              android:layout_above="@id/pass_fail_buttons"

+              android:layout_alignParentTop="true"

+              android:text="@string/ble_insecure_server_enctypted_info"

+              android:padding="10dip"

+        />

+</RelativeLayout>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 52da8c4..40af01b 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -191,15 +191,26 @@
 
     <!-- Strings for BluetoothActivity -->
     <string name="bluetooth_test">Bluetooth Test</string>
-    <string name="bluetooth_test_info">The Bluetooth Control tests check whether or not the device
-        can disable and enable Bluetooth properly.\n\nThe Device Communication tests require two
+    <string name="bluetooth_test_info">
+        The Bluetooth Control tests check whether or not the device
+        can disable and enable Bluetooth properly.
+        \n\nThe Bluetooth tests require two devices, and Bluetooth data is exchanged between them.
+        \nThere are two types of connections: Insecure and Secure. There are two types of roles: Server and Client. You must pass all connection and role combinations.
+        \nThis is a list of the tests:
+        \nThis Device x Other Device
+        \n\n\"Bluetooth LE Insecure Client Test\" x \"Bluetooth LE Insecure Server Test\"
+        \n\n\"Bluetooth LE Insecure Server Test\" x \"Bluetooth LE Insecure Client Test\"
+        \n\n\"Bluetooth LE Secure Client Test\" x \"Bluetooth LE Secure Server Test\"
+        \n\n\"Bluetooth LE Secure Server Test\" x \"Bluetooth LE Secure Client Test\"
+        \n\nThe Device Communication tests require two
         devices to pair and exchange messages. The two devices must be:
         \n\n1. a candidate device implementation running the software build to be tested
-        \n\n2. a separate device implementation already known to be compatible</string>
+        \n\n2. a separate device implementation already known to be compatible
+    </string>
 
     <string name="bt_control">Bluetooth Control</string>
     <string name="bt_device_communication">Device Communication</string>
-    <string name="bt_le">Bluetooth Low Energy</string>
+    <string name="bt_le">Bluetooth LE</string>
 
     <string name="bt_toggle_bluetooth">Toggle Bluetooth</string>
     <string name="bt_toggle_instructions">Disable and enable Bluetooth to successfully complete this test.</string>
@@ -247,6 +258,12 @@
     <string name="bt_pick_server">Pick Server</string>
     <string name="bt_insecure_pairing_error_title">Pairing dialog shown?</string>
     <string name="bt_insecure_pairing_error_message">Insecure connections should not show the pairing dialog!</string>
+    <string name="bt_advertise_unsupported_title">Advertising is not supported</string>
+    <string name="bt_advertise_unsupported_message">Advertising is not supported on this device.\nTest finishes.</string>
+    <string name="bt_open_failed_title">BLE open failed</string>
+    <string name="bt_open_failed_message">Cannot open BLE GattService.\nTest finishes.</string>
+    <string name="bt_add_service_failed_title">Add service failed</string>
+    <string name="bt_add_service_failed_message">Failed to add services.\nTest finishes.</string>
 
     <string name="bt_secure_client">Secure Client</string>
     <string name="bt_insecure_client">Insecure Client</string>
@@ -262,18 +279,22 @@
 
     <!-- BLE client side strings -->
     <string name="ble_client_service_name">Bluetooth LE GATT Client Handler Service</string>
-    <string name="ble_client_test_name">BLE Client Test</string>
-    <string name="ble_client_connect_name">BLE Client Connect</string>
-    <string name="ble_discover_service_name">BLE Discover Service</string>
-    <string name="ble_read_characteristic_name">BLE Read Characteristic</string>
-    <string name="ble_write_characteristic_name">BLE Write Characteristic</string>
-    <string name="ble_reliable_write_name">BLE Reliable Write</string>
-    <string name="ble_notify_characteristic_name">BLE Notify Characteristic</string>
-    <string name="ble_read_descriptor_name">BLE Read Descriptor</string>
-    <string name="ble_write_descriptor_name">BLE Write Descriptor</string>
-    <string name="ble_read_rssi_name">BLE Read RSSI</string>
-    <string name="ble_client_disconnect_name">BLE Client Disconnect</string>
-    <string name="ble_client_test_info">The BLE test must be done simultaneously on two devices. This device is the client. All tests listed here must be done in order.</string>
+    <string name="ble_client_test_name">01 Bluetooth LE Client Test</string>
+    <string name="ble_client_connect_name">Bluetooth LE Client Connect</string>
+    <string name="ble_discover_service_name">Bluetooth LE Discover Service</string>
+    <string name="ble_read_characteristic_name">Bluetooth LE Read Characteristic</string>
+    <string name="ble_write_characteristic_name">Bluetooth LE Write Characteristic</string>
+    <string name="ble_reliable_write_name">Bluetooth LE Reliable Write</string>
+    <string name="ble_reliable_write_bad_resp_name">Bluetooth LE Reliable Write (receive bad response)</string>
+    <string name="ble_notify_characteristic_name">Bluetooth LE Notify Characteristic</string>
+    <string name="ble_read_descriptor_name">Bluetooth LE Read Descriptor</string>
+    <string name="ble_write_descriptor_name">Bluetooth LE Write Descriptor</string>
+    <string name="ble_read_rssi_name">Bluetooth LE Read RSSI</string>
+    <string name="ble_client_disconnect_name">Bluetooth LE Client Disconnect</string>
+    <string name="ble_client_test_info">
+        The Bluetooth LE test must be done simultaneously on two devices. This device is the client.
+        All tests listed here must be done with out pairing.
+    </string>
     <string name="ble_client_send_connect_info">Type in the Bluetooth address of the remote device to connect to, and verify that the devices are connected.</string>
     <string name="ble_discover_service_info">Verify that the service is discovered when you press the "Discover Service" button.</string>
     <string name="ble_read_write_info">Write values to and read values from the server to verify that the write and read functionalities are working correctly.</string>
@@ -296,32 +317,82 @@
     <string name="ble_read_rssi">Read RSSI</string>
     <string name="ble_disconnect">Disconnect</string>
     <string name="ble_test_text">TEST</string>
+    <string name="ble_test_finished">Test finished</string>
+    <string name="ble_test_next">Next</string>
+    <string name="ble_test_running">Test Running</string>
+    <string name="ble_test_running_message">This test requires a few minutes. Don\'t interrupt the test.</string>
+    <string name="ble_mtu_23_name">Bluetooth LE Request MTU(23bytes)</string>
+    <string name="ble_mtu_512_name">Bluetooth LE Request MTU(512bytes)</string>
 
     <!-- BLE server side strings -->
     <string name="ble_server_service_name">Bluetooth LE GATT Server Handler Service</string>
-    <string name="ble_server_start_name">BLE Server Test</string>
-    <string name="ble_server_start_info">The BLE test must be done simultaneously on two devices, a server device and a client device. This device is the server.</string>
-    <string name="ble_server_receiving_connect">Waiting on connection from BLE client.</string>
-    <string name="ble_server_add_service">Adding service to BLE server.</string>
+    <string name="ble_server_start_name">01 Bluetooth LE Server Test</string>
+    <string name="ble_server_start_info">
+        The Bluetooth LE test must be done simultaneously on two devices, a server device and a client device. This device is the server.
+    </string>
+    <string name="ble_server_receiving_connect">Waiting on connection from Bluetooth LE client.</string>
+    <string name="ble_server_add_service">Adding service to Bluetooth LE server.</string>
     <string name="ble_server_write_characteristic">Waiting on write characteristic request</string>
     <string name="ble_server_read_characteristic">Waiting on read characteristic request</string>
     <string name="ble_server_write_descriptor">Waiting on write descriptor request</string>
     <string name="ble_server_read_descriptor">Waiting on read descriptor request</string>
     <string name="ble_server_reliable_write">Waiting on reliable write from client</string>
-    <string name="ble_server_receiving_disconnect">Waiting on disconnection from BLE client</string>
+    <string name="ble_server_reliable_write_bad_resp">Waiting on reliable write from client (send bad response)</string>
+    <string name="ble_server_receiving_disconnect">Waiting on disconnection from Bluetooth LE client</string>
+    <string name="ble_connection_priority_server_name">02 Bluetooth LE Connection Priority Server Test</string>
+    <string name="ble_connection_priority_server_info">Bluetooth LE Connection Priority Server receive message from message in 3 different priority.</string>
+    <string name="ble_server_notify_characteristic">Waiting on notify characteristic request</string>
+    <string name="ble_server_write_characteristic_without_permission">Waiting on write characteristic request without permission</string>
+    <string name="ble_server_read_characteristic_without_permission">Waiting on read characteristic request without permission</string>
+    <string name="ble_server_write_descriptor_without_permission">Waiting on write descriptor request without permission</string>
+    <string name="ble_server_read_descriptor_without_permission"> Waiting on read descriptor request without permission</string>
+    <string name="ble_server_write_characteristic_need_encrypted">Waiting on write encrypted characteristic request</string>
+    <string name="ble_server_read_characteristic_need_encrypted">Waiting on read encryptedcharacteristic request</string>
+    <string name="ble_server_write_descriptor_need_encrypted">Waiting on write encrypted descriptor request</string>
+    <string name="ble_server_read_descriptor_need_encrypted"> Waiting on read encrypted descriptor request</string>
+    <string name="ble_server_indicate_characteristic">Waiting on indicate characteristic request</string>
+    <string name="ble_server_mtu_23bytes">Waiting on MTU request(23 bytes)</string>
+    <string name="ble_server_mtu_512bytes">Waiting on MTU request(512 bytes)</string>
+    <string name="ble_encrypted_server_name">03 Bluetooth LE Encrypted Server Test</string>
+    <string name="ble_encrypted_server_info">Bluetooth LE Encrypted Server Waiting on read/write characteristic and descriptor request need encrypted.</string>
+    <string name="ble_insecure_server_enctypted_info">Bluetooth LE Server is in operation.\nThis test does not change server state.\n\nIf Bluetooth pairing request was notified by system, you must cancel it.\n\nOnce the client tests are all successful, please change the state of the server-side to the "success".</string>
+    <string name="ble_insecure_server_test_list_name">Bluetooth LE Insecure Server Test</string>
+    <string name="ble_insecure_server_test_list_info">
+        This test is mostly automated, but requires some user interaction.
+        Once the list items below have check marks, the test is complete.
+        \n\nTap \"01 Bluetooth LE Server Test\" on this device, then tap \"01 Bluetooth LE Client Test\" on the other device.
+        \nWhen the test is complete, move to the next item. You must complete all tests.
+    </string>
+    <string name="ble_secure_server_test_list_name">Bluetooth LE Secure Server Test</string>
+    <string name="ble_secure_server_test_list_info">
+        This test is mostly automated, but requires some user interaction.
+        You can pass this test once the list items below are checked.
+        \n\nTap \"01 Bluetooth LE Server Test\" on this device, then tap \"01 Bluetooth LE Client Test \"on other device.
+        \nTest completed, then test next item. You must be done all tests.
+    </string>
 
     <!-- BLE advertiser side strings -->
-    <string name="ble_advertiser_test_name">BLE Advertiser Test</string>
-    <string name="ble_advertiser_test_info">The BLE test must be done simultaneously on two devices, an advertiser and a scanner. This device is the advertiser.</string>
+    <string name="ble_advertiser_test_name">Bluetooth LE Advertiser Test</string>
+    <string name="ble_advertiser_test_info">
+        The Bluetooth LE Advertiser Test and Scanner Test is a paired test.
+        \nTap \"Bluetooth LE Advertiser Test\" on this device. Once it is passed, tap \"Bluetooth LE Scanner Test\".
+        \nTap \"Bluetooth LE Scanner Test\" on this device. Once it is passed, tap \"Bluetooth LE Advertiser Test\".
+    </string>
     <string name="ble_advertiser_service_name">Bluetooth LE Advertiser Handler Service</string>
-    <string name="ble_privacy_mac_name">BLE Privacy Mac</string>
-    <string name="ble_privacy_mac_info">BLE Advertiser should advertise in non-repeating MAC address.</string>
-    <string name="ble_advertiser_privacy_mac_instruction">Click start to start advertising, you can disconnect USB and lock the screen of advertiser. Counts and mac address will show on scanner. You may receive message that this device does not support BLE advertising.</string>
-    <string name="ble_power_level_name">BLE Tx Power Level</string>
-    <string name="ble_power_level_info">BLE Advertiser advertises in 4 different power levels. Scanner should receive them in different strength of Rssi, cannot receive weak signals beyond several feet.</string>
-    <string name="ble_advertiser_power_level_instruction">Click start to start multi-advertising. Data packets are advertised in 4 different power levels. You may receive message that this device does not support multi advertising. If advertiser does not advertise in 4 power levels, neither you receive the error message, you may not stop the advertising in previous test, or this device does not support 4 advertisers at the same time. Try rebooting the device and run the test to free those advertisers in use.</string>
-    <string name="ble_advertiser_scan_filter_name">BLE Hardware Scan Filter</string>
-    <string name="ble_advertiser_scan_filter_info">BLE Advertiser advertises with 2 different data separately. One can wake up the scanner, the other cannot. This test cares about behavior on scanner only.</string>
+    <string name="ble_privacy_mac_name">Bluetooth LE Privacy Mac</string>
+    <string name="ble_privacy_mac_info">Bluetooth LE Advertiser should advertise in non-repeating MAC address.</string>
+    <string name="ble_advertiser_privacy_mac_instruction">Click start to start advertising, you can disconnect USB and lock the screen of advertiser. Counts and mac address will show on scanner. You may receive message that this device does not support Bluetooth LE advertising.</string>
+    <string name="ble_power_level_name">Bluetooth LE Tx Power Level</string>
+    <string name="ble_power_level_info">Bluetooth LE Advertiser advertises in 4 different power levels. Scanner should receive them in different strength of Rssi, cannot receive weak signals beyond several feet.</string>
+    <string name="ble_advertiser_power_level_instruction">
+        Click start to start multi-advertising. Data packets are advertised in 4 different power levels.
+        You may receive a message that this device does not support multi-advertising.
+        If the advertiser does not advertise in 4 power levels, and you do not receive an error message,
+        you may not have stopped advertising in the previous test, or this device may not support 4 advertisers at the same time.
+        Try rebooting the device and running the test again to free those advertisers in use.
+    </string>
+    <string name="ble_advertiser_scan_filter_name">Bluetooth LE Hardware Scan Filter</string>
+    <string name="ble_advertiser_scan_filter_info">Bluetooth LE Advertiser advertises with 2 different data separately. One can wake up the scanner, the other cannot. This test cares about behavior on scanner only.</string>
     <string name="ble_advertiser_scannable">Scannable advertising</string>
     <string name="ble_advertiser_scannable_instruction">Start scannable advertising, expect scanner consume more power on Monsoon monitor, or see log of GattService from scanner logcat.</string>
     <string name="ble_advertiser_unscannable">Unscannble advertising</string>
@@ -330,9 +401,9 @@
     <string name="ble_advertiser_stop">Stop</string>
 
     <!-- BLE scanner side strings -->
-    <string name="ble_scanner_test_name">BLE Scanner Test</string>
+    <string name="ble_scanner_test_name">Bluetooth LE Scanner Test</string>
     <string name="ble_scanner_service_name">Bluetooth LE Scanner Handler Service</string>
-    <string name="ble_scanner_test_info">The BLE test must be done simultaneously on two devices, an advertiser and a scanner. This device is the scanner.</string>
+    <string name="ble_scanner_test_info">The Bluetooth LE test must be done simultaneously on two devices, an advertiser and a scanner. This device is the scanner.</string>
     <string name="ble_scanner_privacy_mac">Hold for 15 min to see if receive a different MAC address from advertiser.</string>
     <string name="ble_scanner_privacy_mac_instruction">Mac address, counts are shown on screen. It should continuously receive data packet from advertiser. Every 15 min, a new mac address should show up, which prevents mac address disclosure.</string>
     <string name="ble_ultra_low">Ultra low</string>
@@ -340,7 +411,7 @@
     <string name="ble_medium">Medium</string>
     <string name="ble_high">High</string>
     <string name="ble_scanner_power_level_instruction">Count: Ultra low &lt; low &lt; medium &lt; high\nRssi: Ultra low &lt; low &lt; medium &lt; high\nDistance to see count freezing: Ultra low &lt; low &lt; medium &lt; high\nA common error is ultra low, low and medium behave similarly, with similar rssi, freeze at similar distance.\n\n All power level receive a different mac address. After 15 mins, a green text "Get a new Mac address" will show up.</string>
-    <string name="ble_scanner_scan_filter_name">BLE Hardware Scan Filter</string>
+    <string name="ble_scanner_scan_filter_name">Bluetooth LE Hardware Scan Filter</string>
     <string name="ble_scanner_scan_filter_info">Lock the screen of scanner, and connect to monsoon. It will not wake up when advertiser is advertising unscannable, and scanner is scanning with filter.</string>
     <string name="ble_scanner_scan_filter_instruction">Scan filter is to scan data with service UUID = 0x6666 only. If you scan without scan filter, data with service UUID = 0x5555 and 0x6666 will show up on screen.\nFor monsoon test:\n\tClick scan with filter, lock the screen, connect to monsoon. It will not wake up when advertiser is advertising unscannable data packets, but will show a peak in power usage when advertiser is advertising scannable data.\nFor logcat test:\n\tClick scan with filter, logcat the scanner. No data will be received by GattService when advertiser is advertising unscannable data.</string>
     <string name="ble_scan_with_filter">Scan with filter</string>
@@ -348,6 +419,80 @@
     <string name="ble_scan_start">Start scan</string>
     <string name="ble_scan_stop">Stop scan</string>
 
+    <!-- BLE connection priority test strings -->
+    <string name="ble_client_connection_priority">Testing priority: </string>
+    <string name="ble_connection_priority_balanced">BALANCED</string>
+    <string name="ble_connection_priority_high">HIGH</string>
+    <string name="ble_connection_priority_low">LOW</string>
+    <string name="ble_server_connection_priority_result_passed">All test passed</string>
+    <string name="ble_server_connection_priority_result_failed">Test failed.</string>
+    <string name="ble_server_connection_priority_result_intervals">
+        Transfer interval time (msec):\nHIGH=%1$d\nBALANCED=%2$d\nLOW=%3$d\n\nRequirements:\n HIGH &lt;= BALANCED &lt;= LOW
+    </string>
+
+    <!-- BLE Test Name -->
+    <string name="ble_secure_client_test_name">Bluetooth LE Secure Client Test</string>
+    <string name="ble_insecure_client_test_name">Bluetooth LE Insecure Client Test</string>
+    <string name="ble_secure_server_test_name">Bluetooth LE Secure Server Test</string>
+    <string name="ble_insecure_server_test_name">Bluetooth LE Insecure Server Test</string>
+
+    <string name="ble_read_characteristic_nopermission_name">Bluetooth LE Read Characteristic Without Perrmission</string>
+    <string name="ble_write_characteristic_nopermission_name">Bluetooth LE Write Characteristic Without Permission</string>
+    <string name="ble_read_descriptor_nopermission_name">Bluetooth LE Read Descriptor Without Perrmission</string>
+    <string name="ble_write_descriptor_nopermission_name">Bluetooth LE Write Descriptor Without Permission</string>
+    <string name="ble_connection_priority_client_name">02 Bluetooth LE Connection Priority Client Test</string>
+    <string name="ble_connection_priority_client_info">Bluetooth LE Connection Priority Client send message in 3 different priority.</string>
+    <string name="ble_read_authenticated_characteristic_name">Bluetooth LE Read Encrypted Characteristic</string>
+    <string name="ble_write_authenticated_characteristic_name">Bluetooth LE Write Encrypted Characteristic</string>
+    <string name="ble_read_authenticated_descriptor_name">Bluetooth LE Read Encrypted Descriptor</string>
+    <string name="ble_write_authenticated_descriptor_name">Bluetooth LE Write Encrypted Descriptor</string>
+    <string name="ble_connection_priority_client_high">Bluetooth LE Send With CONNECTION_PRIORITY_HIGH</string>
+    <string name="ble_connection_priority_client_low">Bluetooth LE Send With CONNECTION_PRIORITY_LOW_POWER</string>
+    <string name="ble_connection_priority_client_balanced">Bluetooth LE Send With CONNECTION_PRIORITY_BALANCED</string>
+    <string name="ble_indicate_characteristic_name">Bluetooth LE Indicate Characteristic</string>
+    <string name="ble_encrypted_client_name">03 Bluetooth LE Encrypted Client Test</string>
+    <string name="ble_encrypted_client_info">Bluetooth LE Encrypted Client read/write on characteristic and descriptor need encrypted.</string>
+    <string name="ble_insecure_client_test_list_name">Bluetooth LE Insecure Client Test</string>
+    <string name="ble_insecure_client_test_list_info">
+        The Bluetooth LE test must be done simultaneously on two devices. This device is the client.
+        All tests listed here must be done without pairing. Tap \"Bluetooth LE Insecure Server Test\" on the other device.
+        \n\nTap \"01 Bluetooth LE Client Test\" on this device, then tap \"01 Bluetooth LE Server Test\" on the other device.
+        \nWhen the test is complete, move to the next item. You must complete all tests.
+    </string>
+    <string name="ble_secure_client_test_list_name">Bluetooth LE Secure Client Test</string>
+    <string name="ble_secure_client_test_list_info">
+        The Bluetooth LE test must be done simultaneously on two devices.
+        This device is the client. All tests listed here must be done with pairing.
+        \n\nTap \"01 Bluetooth LE Client Test\" on this device, then tap \"01 Bluetooth LE Server Test\" on the other device.
+        \nWhen the test is complete, move to the next item. You must complete all tests.
+    </string>
+    <string name="ble_encrypted_client_no_encrypted_characteristic">Error!\nThe Characteristics unencrypted.</string>
+    <string name="ble_encrypted_client_no_encrypted_descriptor">Error!\nThe Descriptor unencrypted.</string>
+    <string name="ble_encrypted_client_fail_write_encrypted_characteristic">It failed to write to Characteristic.</string>
+    <string name="ble_encrypted_client_fail_write_encrypted_descriptor">It failed to write to Descriptor.</string>
+    <string name="ble_encrypted_client_fail_read_encrypted_characteristic">It failed to read the Characteristic.</string>
+    <string name="ble_encrypted_client_fail_read_encrypted_descriptor">It failed to read the Descriptor.</string>
+    <string name="ble_secure_client_test_info">
+        The Bluetooth LE test must be done simultaneously on two devices. This device is the client.
+        All tests listed here must be done with pairing.
+    </string>
+
+    <string name="ble_bluetooth_disable_title">Bluetooth Disable!</string>
+    <string name="ble_bluetooth_disable_message">Please set bluetooth enable.</string>
+
+    <string name="ble_bluetooth_mismatch_title">Bluetooth pairing state is a mismatch!</string>
+    <string name="ble_bluetooth_mismatch_secure_message">
+        And even though it has already been trying to run a test of Secure, the device has not been paired.
+        \nGo setting mode, set Bluetooth to pair other device.
+    </string>
+    <string name="ble_bluetooth_mismatch_insecure_message">
+        And even though it has already been trying to run a test of Insecure, the device has already been paired.
+        \nGo setting mode, set Bluetooth to unpair other device.
+    </string>
+
+    <string name="ble_mtu_mismatch_message">MTU is not correct.(Request:%1$d, Actual:%2$d)</string>
+    <string name="ble_mtu_fail_message">MTU test: failed to receive data</string>
+
     <!-- Strings for FeatureSummaryActivity -->
     <string name="feature_summary">Hardware/Software Feature Summary</string>
     <string name="feature_summary_info">This is a test for...</string>
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleAdvertiserTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleAdvertiserTestActivity.java
index 64c50bc..cd7cf70 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleAdvertiserTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleAdvertiserTestActivity.java
@@ -16,13 +16,16 @@
 
 package com.android.cts.verifier.bluetooth;
 
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.bluetooth.BluetoothAdapter;
+import android.content.DialogInterface;
+import android.os.Bundle;
+
 import com.android.cts.verifier.ManifestTestListAdapter;
 import com.android.cts.verifier.PassFailButtons;
 import com.android.cts.verifier.R;
 
-import android.bluetooth.BluetoothAdapter;
-import android.os.Bundle;
-
 import java.util.ArrayList;
 import java.util.List;
 
@@ -44,5 +47,17 @@
 
         setTestListAdapter(new ManifestTestListAdapter(this, getClass().getName(),
                 disabledTest.toArray(new String[disabledTest.size()])));
+        if (!adapter.isEnabled()) {
+            new AlertDialog.Builder(this)
+                    .setTitle(R.string.ble_bluetooth_disable_title)
+                    .setMessage(R.string.ble_bluetooth_disable_message)
+                    .setOnCancelListener(new Dialog.OnCancelListener() {
+                        @Override
+                        public void onCancel(DialogInterface dialog) {
+                            finish();
+                        }
+                    })
+                    .create().show();
+        }
     }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientService.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientService.java
index 10f862d..972ba43 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientService.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientService.java
@@ -16,10 +16,6 @@
 
 package com.android.cts.verifier.bluetooth;
 
-import java.util.Arrays;
-import java.util.UUID;
-import java.util.List;
-
 import android.app.Service;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
@@ -35,54 +31,109 @@
 import android.bluetooth.le.ScanFilter;
 import android.bluetooth.le.ScanResult;
 import android.bluetooth.le.ScanSettings;
+import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Build;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.ParcelUuid;
+import android.text.TextUtils;
 import android.util.Log;
 import android.widget.Toast;
 
+import com.android.cts.verifier.R;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+import java.util.UUID;
+
 public class BleClientService extends Service {
 
     public static final boolean DEBUG = true;
     public static final String TAG = "BleClientService";
 
+    // Android N (2016 July 15, currently) BluetoothGatt#disconnect() does not work correct.
+    // (termination signal will not be sent)
+    // This flag switches to turn Bluetooth off instead of BluetoothGatt#disconnect().
+    // If true, test will turn Bluetooth off. Otherwise, will call BluetoothGatt#disconnect().
+    public static final boolean DISCONNECT_BY_TURN_BT_OFF_ON = (Build.VERSION.SDK_INT > Build.VERSION_CODES.M);
+
+    // for Version 1 test
+//    private static final int TRANSPORT_MODE_FOR_SECURE_CONNECTION = BluetoothDevice.TRANSPORT_AUTO;
+    // for Version 2 test
+    private static final int TRANSPORT_MODE_FOR_SECURE_CONNECTION = BluetoothDevice.TRANSPORT_LE;
+
     public static final int COMMAND_CONNECT = 0;
     public static final int COMMAND_DISCONNECT = 1;
     public static final int COMMAND_DISCOVER_SERVICE = 2;
     public static final int COMMAND_READ_RSSI = 3;
     public static final int COMMAND_WRITE_CHARACTERISTIC = 4;
-    public static final int COMMAND_READ_CHARACTERISTIC = 5;
-    public static final int COMMAND_WRITE_DESCRIPTOR = 6;
-    public static final int COMMAND_READ_DESCRIPTOR = 7;
-    public static final int COMMAND_SET_NOTIFICATION = 8;
-    public static final int COMMAND_BEGIN_WRITE = 9;
-    public static final int COMMAND_EXECUTE_WRITE = 10;
-    public static final int COMMAND_ABORT_RELIABLE = 11;
-    public static final int COMMAND_SCAN_START = 12;
-    public static final int COMMAND_SCAN_STOP = 13;
+    public static final int COMMAND_WRITE_CHARACTERISTIC_BAD_RESP = 5;
+    public static final int COMMAND_READ_CHARACTERISTIC = 6;
+    public static final int COMMAND_WRITE_DESCRIPTOR = 7;
+    public static final int COMMAND_READ_DESCRIPTOR = 8;
+    public static final int COMMAND_SET_NOTIFICATION = 9;
+    public static final int COMMAND_BEGIN_WRITE = 10;
+    public static final int COMMAND_EXECUTE_WRITE = 11;
+    public static final int COMMAND_ABORT_RELIABLE = 12;
+    public static final int COMMAND_SCAN_START = 13;
+    public static final int COMMAND_SCAN_STOP = 14;
 
+    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_BLUETOOTH_CONNECTED =
             "com.android.cts.verifier.bluetooth.BLE_BLUETOOTH_CONNECTED";
     public static final String BLE_BLUETOOTH_DISCONNECTED =
             "com.android.cts.verifier.bluetooth.BLE_BLUETOOTH_DISCONNECTED";
     public static final String BLE_SERVICES_DISCOVERED =
             "com.android.cts.verifier.bluetooth.BLE_SERVICES_DISCOVERED";
+    public static final String BLE_MTU_CHANGED_23BYTES =
+            "com.android.cts.verifier.bluetooth.BLE_MTU_CHANGED_23BYTES";
+    public static final String BLE_MTU_CHANGED_512BYTES =
+            "com.android.cts.verifier.bluetooth.BLE_MTU_CHANGED_512BYTES";
     public static final String BLE_CHARACTERISTIC_READ =
             "com.android.cts.verifier.bluetooth.BLE_CHARACTERISTIC_READ";
     public static final String BLE_CHARACTERISTIC_WRITE =
             "com.android.cts.verifier.bluetooth.BLE_CHARACTERISTIC_WRITE";
     public static final String BLE_CHARACTERISTIC_CHANGED =
             "com.android.cts.verifier.bluetooth.BLE_CHARACTERISTIC_CHANGED";
+    public static final String BLE_CHARACTERISTIC_INDICATED =
+            "com.android.cts.verifier.bluetooth.BLE_CHARACTERISTIC_INDICATED";
     public static final String BLE_DESCRIPTOR_READ =
             "com.android.cts.verifier.bluetooth.BLE_DESCRIPTOR_READ";
     public static final String BLE_DESCRIPTOR_WRITE =
             "com.android.cts.verifier.bluetooth.BLE_DESCRIPTOR_WRITE";
     public static final String BLE_RELIABLE_WRITE_COMPLETED =
             "com.android.cts.verifier.bluetooth.BLE_RELIABLE_WRITE_COMPLETED";
+    public static final String BLE_RELIABLE_WRITE_BAD_RESP_COMPLETED =
+            "com.android.cts.verifier.bluetooth.BLE_RELIABLE_WRITE_BAD_RESP_COMPLETED";
     public static final String BLE_READ_REMOTE_RSSI =
             "com.android.cts.verifier.bluetooth.BLE_READ_REMOTE_RSSI";
+    public static final String BLE_CHARACTERISTIC_READ_NOPERMISSION =
+            "com.android.cts.verifier.bluetooth.BLE_CHARACTERISTIC_READ_NOPERMISSION";
+    public static final String BLE_CHARACTERISTIC_WRITE_NOPERMISSION =
+            "com.android.cts.verifier.bluetooth.BLE_CHARACTERISTIC_WRITE_NOPERMISSION";
+    public static final String BLE_DESCRIPTOR_READ_NOPERMISSION =
+            "com.android.cts.verifier.bluetooth.BLE_DESCRIPTOR_READ_NOPERMISSION";
+    public static final String BLE_DESCRIPTOR_WRITE_NOPERMISSION =
+            "com.android.cts.verifier.bluetooth.BLE_DESCRIPTOR_WRITE_NOPERMISSION";
+    public static final String BLE_CHARACTERISTIC_READ_NEED_ENCRYPTED =
+            "com.android.cts.verifier.bluetooth.BLE_CHARACTERISTIC_READ_NEED_ENCRYPTED";
+    public static final String BLE_CHARACTERISTIC_WRITE_NEED_ENCRYPTED =
+            "com.android.cts.verifier.bluetooth.BLE_CHARACTERISTIC_WRITE_NEED_ENCRYPTED";
+    public static final String BLE_DESCRIPTOR_READ_NEED_ENCRYPTED =
+            "com.android.cts.verifier.bluetooth.BLE_DESCRIPTOR_READ_NEED_ENCRYPTED";
+    public static final String BLE_DESCRIPTOR_WRITE_NEED_ENCRYPTED =
+            "com.android.cts.verifier.bluetooth.BLE_DESCRIPTOR_WRITE_NEED_ENCRYPTED";
+    public static final String BLE_CLIENT_ERROR =
+            "com.android.cts.verifier.bluetooth.BLE_CLIENT_ERROR";
 
     public static final String EXTRA_COMMAND =
             "com.android.cts.verifier.bluetooth.EXTRA_COMMAND";
@@ -90,6 +141,56 @@
             "com.android.cts.verifier.bluetooth.EXTRA_WRITE_VALUE";
     public static final String EXTRA_BOOL =
             "com.android.cts.verifier.bluetooth.EXTRA_BOOL";
+
+
+    // Literal for Client Action
+    public static final String BLE_CLIENT_ACTION_CLIENT_CONNECT =
+            "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_CLIENT_CONNECT";
+    public static final String BLE_CLIENT_ACTION_CLIENT_CONNECT_SECURE =
+            "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_CLIENT_CONNECT_SECURE";
+    public static final String BLE_CLIENT_ACTION_BLE_DISVOCER_SERVICE =
+            "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_BLE_DISVOCER_SERVICE";
+    public static final String BLE_CLIENT_ACTION_REQUEST_MTU_23 =
+            "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_REQUEST_MTU_23";
+    public static final String BLE_CLIENT_ACTION_REQUEST_MTU_512 =
+            "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_REQUEST_MTU_512";
+    public static final String BLE_CLIENT_ACTION_READ_CHARACTERISTIC =
+            "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_READ_CHARACTERISTIC";
+    public static final String BLE_CLIENT_ACTION_WRITE_CHARACTERISTIC =
+            "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_WRITE_CHARACTERISTIC";
+    public static final String BLE_CLIENT_ACTION_RELIABLE_WRITE =
+            "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_RELIABLE_WRITE";
+    public static final String BLE_CLIENT_ACTION_RELIABLE_WRITE_BAD_RESP =
+            "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_RELIABLE_WRITE_BAD_RESP";
+    public static final String BLE_CLIENT_ACTION_NOTIFY_CHARACTERISTIC =
+            "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_NOTIFY_CHARACTERISTIC";
+    public static final String BLE_CLIENT_ACTION_INDICATE_CHARACTERISTIC =
+            "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_INDICATE_CHARACTERISTIC";
+    public static final String BLE_CLIENT_ACTION_READ_DESCRIPTOR =
+            "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_READ_DESCRIPTOR";
+    public static final String BLE_CLIENT_ACTION_WRITE_DESCRIPTOR =
+            "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_WRITE_DESCRIPTOR";
+    public static final String BLE_CLIENT_ACTION_READ_RSSI =
+            "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_READ_RSSI";
+    public static final String BLE_CLIENT_ACTION_CLIENT_DISCONNECT =
+            "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_CLIENT_DISCONNECT";
+    public static final String BLE_CLIENT_ACTION_READ_CHARACTERISTIC_NO_PERMISSION =
+            "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_READ_CHARACTERISTIC_NO_PERMISSION";
+    public static final String BLE_CLIENT_ACTION_WRITE_CHARACTERISTIC_NO_PERMISSION =
+            "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_WRITE_CHARACTERISTIC_NO_PERMISSION";
+    public static final String BLE_CLIENT_ACTION_READ_DESCRIPTOR_NO_PERMISSION =
+            "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_READ_DESCRIPTOR_NO_PERMISSION";
+    public static final String BLE_CLIENT_ACTION_WRITE_DESCRIPTOR_NO_PERMISSION =
+            "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_WRITE_DESCRIPTOR_NO_PERMISSION";
+    public static final String BLE_CLIENT_ACTION_READ_AUTHENTICATED_CHARACTERISTIC =
+            "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_READ_AUTHENTICATED_CHARACTERISTIC";
+    public static final String BLE_CLIENT_ACTION_WRITE_AUTHENTICATED_CHARACTERISTIC =
+            "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_WRITE_AUTHENTICATED_CHARACTERISTIC";
+    public static final String BLE_CLIENT_ACTION_READ_AUTHENTICATED_DESCRIPTOR =
+            "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_READ_AUTHENTICATED_DESCRIPTOR";
+    public static final String BLE_CLIENT_ACTION_WRITE_AUTHENTICATED_DESCRIPTOR =
+            "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_WRITE_AUTHENTICATED_DESCRIPTOR";
+
     public static final String EXTRA_CHARACTERISTIC_VALUE =
             "com.android.cts.verifier.bluetooth.EXTRA_CHARACTERISTIC_VALUE";
     public static final String EXTRA_DESCRIPTOR_VALUE =
@@ -99,16 +200,87 @@
     public static final String EXTRA_ERROR_MESSAGE =
             "com.android.cts.verifier.bluetooth.EXTRA_ERROR_MESSAGE";
 
+    public static final String WRITE_VALUE_512BYTES_FOR_MTU = createTestData(512);
+    public static final String WRITE_VALUE_507BYTES_FOR_RELIABLE_WRITE = createTestData(507);
+
     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");
 
-    private static final String WRITE_VALUE = "TEST";
+    private static final UUID SERVICE_UUID_ADDITIONAL =
+            UUID.fromString("00009995-0000-1000-8000-00805f9b34fb");
+
+    // Literal for registration permission of Characteristic
+    private static final UUID CHARACTERISTIC_NO_READ_UUID =
+            UUID.fromString("00009984-0000-1000-8000-00805f9b34fb");
+    private static final UUID CHARACTERISTIC_NO_WRITE_UUID =
+            UUID.fromString("00009983-0000-1000-8000-00805f9b34fb");
+    private static final UUID CHARACTERISTIC_NEED_ENCRYPTED_READ_UUID =
+            UUID.fromString("00009982-0000-1000-8000-00805f9b34fb");
+    private static final UUID CHARACTERISTIC_NEED_ENCRYPTED_WRITE_UUID =
+            UUID.fromString("00009981-0000-1000-8000-00805f9b34fb");
+
+    // Literal 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");
+
+    //  Literal for registration upper limit confirmation of Characteristic
+    private static final UUID UPDATE_CHARACTERISTIC_UUID_1 =
+            UUID.fromString("00009989-0000-1000-8000-00805f9b34fb");
+    private static final UUID UPDATE_CHARACTERISTIC_UUID_2 =
+            UUID.fromString("00009988-0000-1000-8000-00805f9b34fb");
+    private static final UUID UPDATE_CHARACTERISTIC_UUID_3 =
+            UUID.fromString("00009987-0000-1000-8000-00805f9b34fb");
+    private static final UUID UPDATE_CHARACTERISTIC_UUID_4 =
+            UUID.fromString("00009986-0000-1000-8000-00805f9b34fb");
+    private static final UUID UPDATE_CHARACTERISTIC_UUID_5 =
+            UUID.fromString("00009985-0000-1000-8000-00805f9b34fb");
+    private static final UUID UPDATE_CHARACTERISTIC_UUID_6 =
+            UUID.fromString("00009979-0000-1000-8000-00805f9b34fb");
+    private static final UUID UPDATE_CHARACTERISTIC_UUID_7 =
+            UUID.fromString("00009978-0000-1000-8000-00805f9b34fb");
+    private static final UUID UPDATE_CHARACTERISTIC_UUID_8 =
+            UUID.fromString("00009977-0000-1000-8000-00805f9b34fb");
+    private static final UUID UPDATE_CHARACTERISTIC_UUID_9 =
+            UUID.fromString("00009976-0000-1000-8000-00805f9b34fb");
+    private static final UUID UPDATE_CHARACTERISTIC_UUID_10 =
+            UUID.fromString("00009975-0000-1000-8000-00805f9b34fb");
+    private static final UUID UPDATE_CHARACTERISTIC_UUID_11 =
+            UUID.fromString("00009959-0000-1000-8000-00805f9b34fb");
+    private static final UUID UPDATE_CHARACTERISTIC_UUID_12 =
+            UUID.fromString("00009958-0000-1000-8000-00805f9b34fb");
+    private static final UUID UPDATE_CHARACTERISTIC_UUID_13 =
+            UUID.fromString("00009957-0000-1000-8000-00805f9b34fb");
+    private static final UUID UPDATE_CHARACTERISTIC_UUID_14 =
+            UUID.fromString("00009956-0000-1000-8000-00805f9b34fb");
+    private static final UUID UPDATE_CHARACTERISTIC_UUID_15 =
+            UUID.fromString("00009955-0000-1000-8000-00805f9b34fb");
+
+    private static final UUID UPDATE_DESCRIPTOR_UUID =
+            UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
+
+    private static final UUID INDICATE_CHARACTERISTIC_UUID =
+            UUID.fromString("00009971-0000-1000-8000-00805f9b34fb");
+
+    public static final String WRITE_VALUE = "CLIENT_TEST";
+    private static final String NOTIFY_VALUE = "NOTIFY_TEST";
+    public static final String WRITE_VALUE_BAD_RESP = "BAD_RESP_TEST";
+
+    // current test category
+    private String mCurrentAction;
 
     private BluetoothManager mBluetoothManager;
     private BluetoothAdapter mBluetoothAdapter;
@@ -117,24 +289,181 @@
     private BluetoothLeScanner mScanner;
     private Handler mHandler;
     private Context mContext;
+    private boolean mSecure;
+    private int mNotifyCount;
+    private boolean mValidityService;
+    private ReliableWriteState mExecReliableWrite;
+    private byte[] mBuffer;
+
+    // Handler for communicating task with peer.
+    private TestTaskQueue mTaskQueue;
+
+    private enum ReliableWriteState {
+        RELIABLE_WRITE_NONE,
+        RELIABLE_WRITE_WRITE_1ST_DATA,
+        RELIABLE_WRITE_WRITE_2ND_DATA,
+        RELIABLE_WRITE_EXECUTE,
+        RELIABLE_WRITE_BAD_RESP
+    }
 
     @Override
     public void onCreate() {
         super.onCreate();
 
+        registerReceiver(mBondStatusReceiver, new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED));
+
         mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
         mBluetoothAdapter = mBluetoothManager.getAdapter();
         mScanner = mBluetoothAdapter.getBluetoothLeScanner();
         mHandler = new Handler();
         mContext = this;
-        startScan();
+        mNotifyCount = 0;
+
+        mTaskQueue = new TestTaskQueue(getClass().getName() + "_taskHandlerThread");
     }
 
     @Override
-    public int onStartCommand(Intent intent, int flags, int startId) {
+    public int onStartCommand(final Intent intent, int flags, int startId) {
+        if (!mBluetoothAdapter.isEnabled()) {
+            notifyBluetoothDisabled();
+        } else {
+            mTaskQueue.addTask(new Runnable() {
+                @Override
+                public void run() {
+                    onTestFinish(intent.getAction());
+                }
+            }, 1500);
+        }
         return START_NOT_STICKY;
     }
 
+    private void onTestFinish(String action) {
+        mCurrentAction = action;
+        if (mCurrentAction != null) {
+            switch (mCurrentAction) {
+                case BLE_CLIENT_ACTION_CLIENT_CONNECT_SECURE:
+                    mSecure = true;
+                    mExecReliableWrite = ReliableWriteState.RELIABLE_WRITE_NONE;
+                    startScan();
+                    break;
+                case BLE_CLIENT_ACTION_CLIENT_CONNECT:
+                    mExecReliableWrite = ReliableWriteState.RELIABLE_WRITE_NONE;
+                    startScan();
+                    break;
+                case BLE_CLIENT_ACTION_BLE_DISVOCER_SERVICE:
+                    if (mBluetoothGatt != null && mBleState == BluetoothProfile.STATE_CONNECTED) {
+                        mBluetoothGatt.discoverServices();
+                    } else {
+                        showMessage("Bluetooth LE not cnnected.");
+                    }
+                    break;
+                case BLE_CLIENT_ACTION_REQUEST_MTU_23:
+                case BLE_CLIENT_ACTION_REQUEST_MTU_512: // fall through
+                    requestMtu();
+                    break;
+                case BLE_CLIENT_ACTION_READ_CHARACTERISTIC:
+                    readCharacteristic(CHARACTERISTIC_UUID);
+                    break;
+                case BLE_CLIENT_ACTION_WRITE_CHARACTERISTIC:
+                    writeCharacteristic(CHARACTERISTIC_UUID, WRITE_VALUE);
+                    break;
+                case BLE_CLIENT_ACTION_RELIABLE_WRITE:
+                case BLE_CLIENT_ACTION_RELIABLE_WRITE_BAD_RESP: // fall through
+                    mTaskQueue.addTask(new Runnable() {
+                        @Override
+                        public void run() {
+                            reliableWrite();
+                        }
+                    });
+                break;
+                case BLE_CLIENT_ACTION_INDICATE_CHARACTERISTIC:
+                    setNotification(INDICATE_CHARACTERISTIC_UUID, true);
+                    break;
+                case BLE_CLIENT_ACTION_NOTIFY_CHARACTERISTIC:
+                    // Registered the notify to characteristics in the service
+                    mTaskQueue.addTask(new Runnable() {
+                        @Override
+                        public void run() {
+                            mNotifyCount = 16;
+                            setNotification(UPDATE_CHARACTERISTIC_UUID, true);
+                            sleep(1000);
+                            setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_1, true);
+                            sleep(1000);
+                            setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_2, true);
+                            sleep(1000);
+                            setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_3, true);
+                            sleep(1000);
+                            setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_4, true);
+                            sleep(1000);
+                            setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_5, true);
+                            sleep(1000);
+                            setNotification(UPDATE_CHARACTERISTIC_UUID_6, true);
+                            sleep(1000);
+                            setNotification(UPDATE_CHARACTERISTIC_UUID_7, true);
+                            sleep(1000);
+                            setNotification(UPDATE_CHARACTERISTIC_UUID_8, true);
+                            sleep(1000);
+                            setNotification(UPDATE_CHARACTERISTIC_UUID_9, true);
+                            sleep(1000);
+                            setNotification(UPDATE_CHARACTERISTIC_UUID_10, true);
+                            sleep(1000);
+                            setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_11, true);
+                            sleep(1000);
+                            setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_12, true);
+                            sleep(1000);
+                            setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_13, true);
+                            sleep(1000);
+                            setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_14, true);
+                            sleep(1000);
+                            setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_15, true);
+                            sleep(1000);
+                        }
+                    });
+                break;
+                case BLE_CLIENT_ACTION_READ_DESCRIPTOR:
+                    readDescriptor(DESCRIPTOR_UUID);
+                    break;
+                case BLE_CLIENT_ACTION_WRITE_DESCRIPTOR:
+                    writeDescriptor(DESCRIPTOR_UUID, WRITE_VALUE);
+                    break;
+                case BLE_CLIENT_ACTION_READ_RSSI:
+                    if (mBluetoothGatt != null) {
+                        mBluetoothGatt.readRemoteRssi();
+                    }
+                    break;
+                case BLE_CLIENT_ACTION_CLIENT_DISCONNECT:
+                    if (mBluetoothGatt != null) {
+                        mBluetoothGatt.disconnect();
+                    }
+                    break;
+                case BLE_CLIENT_ACTION_READ_CHARACTERISTIC_NO_PERMISSION:
+                    readCharacteristic(CHARACTERISTIC_NO_READ_UUID);
+                    break;
+                case BLE_CLIENT_ACTION_WRITE_CHARACTERISTIC_NO_PERMISSION:
+                    writeCharacteristic(CHARACTERISTIC_NO_WRITE_UUID, WRITE_VALUE);
+                    break;
+                case BLE_CLIENT_ACTION_READ_DESCRIPTOR_NO_PERMISSION:
+                    readDescriptor(DESCRIPTOR_NO_READ_UUID);
+                    break;
+                case BLE_CLIENT_ACTION_WRITE_DESCRIPTOR_NO_PERMISSION:
+                    writeDescriptor(DESCRIPTOR_NO_WRITE_UUID, WRITE_VALUE);
+                    break;
+                case BLE_CLIENT_ACTION_READ_AUTHENTICATED_CHARACTERISTIC:
+                    readCharacteristic(CHARACTERISTIC_NEED_ENCRYPTED_READ_UUID);
+                    break;
+                case BLE_CLIENT_ACTION_WRITE_AUTHENTICATED_CHARACTERISTIC:
+                    writeCharacteristic(CHARACTERISTIC_NEED_ENCRYPTED_WRITE_UUID, WRITE_VALUE);
+                    break;
+                case BLE_CLIENT_ACTION_READ_AUTHENTICATED_DESCRIPTOR:
+                    readDescriptor(CHARACTERISTIC_RESULT_UUID, DESCRIPTOR_NEED_ENCRYPTED_READ_UUID);
+                    break;
+                case BLE_CLIENT_ACTION_WRITE_AUTHENTICATED_DESCRIPTOR:
+                    writeDescriptor(CHARACTERISTIC_RESULT_UUID, DESCRIPTOR_NEED_ENCRYPTED_WRITE_UUID, WRITE_VALUE);
+                    break;
+            }
+        }
+    }
+
     @Override
     public IBinder onBind(Intent intent) {
         return null;
@@ -143,54 +472,183 @@
     @Override
     public void onDestroy() {
         super.onDestroy();
-        mBluetoothGatt.disconnect();
-        mBluetoothGatt.close();
-        mBluetoothGatt = null;
+        if (mBluetoothGatt != null) {
+            mBluetoothGatt.disconnect();
+            mBluetoothGatt.close();
+            mBluetoothGatt = null;
+        }
         stopScan();
+        unregisterReceiver(mBondStatusReceiver);
+
+        mTaskQueue.quit();
     }
 
-    private void writeCharacteristic(String writeValue) {
-        BluetoothGattCharacteristic characteristic = getCharacteristic(CHARACTERISTIC_UUID);
-        if (characteristic == null) return;
-        characteristic.setValue(writeValue);
-        mBluetoothGatt.writeCharacteristic(characteristic);
+    public static BluetoothGatt connectGatt(BluetoothDevice device, Context context, boolean autoConnect, boolean isSecure, BluetoothGattCallback callback) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            if (isSecure) {
+                if (TRANSPORT_MODE_FOR_SECURE_CONNECTION == BluetoothDevice.TRANSPORT_AUTO) {
+                    Toast.makeText(context, "connectGatt(transport=AUTO)", Toast.LENGTH_SHORT).show();
+                } else {
+                    Toast.makeText(context, "connectGatt(transport=LE)", Toast.LENGTH_SHORT).show();
+                }
+                return device.connectGatt(context, autoConnect, callback, TRANSPORT_MODE_FOR_SECURE_CONNECTION);
+            } else {
+                Toast.makeText(context, "connectGatt(transport=LE)", Toast.LENGTH_SHORT).show();
+                return device.connectGatt(context, autoConnect, callback, BluetoothDevice.TRANSPORT_LE);
+            }
+        } else {
+            Toast.makeText(context, "connectGatt", Toast.LENGTH_SHORT).show();
+            return device.connectGatt(context, autoConnect, callback);
+        }
     }
 
-    private void readCharacteristic() {
-        BluetoothGattCharacteristic characteristic = getCharacteristic(CHARACTERISTIC_UUID);
-        if (characteristic != null) mBluetoothGatt.readCharacteristic(characteristic);
+    private void requestMtu() {
+        if (mBluetoothGatt != null) {
+            // MTU request test does not work on Android 6.0 in secure mode.
+            // (BluetoothDevice#createBond() does not work on Android 6.0.
+            //  So devices can't establish Bluetooth LE pairing.)
+            boolean mtuTestExecutable = true;
+            if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) {
+                mtuTestExecutable = !mSecure;
+            }
+
+            if (mtuTestExecutable) {
+                int mtu = 0;
+                if (BLE_CLIENT_ACTION_REQUEST_MTU_23.equals(mCurrentAction)) {
+                    mtu = 23;
+                } else if (BLE_CLIENT_ACTION_REQUEST_MTU_512.equals(mCurrentAction)) {
+                    mtu = 512;
+                } else {
+                    throw new IllegalStateException("unexpected action: " + mCurrentAction);
+                }
+                mBluetoothGatt.requestMtu(mtu);
+            } else {
+                showMessage("Skip MTU test.");
+                notifyMtuChanged();
+            }
+        }
     }
 
-    private void writeDescriptor(String writeValue) {
-        BluetoothGattDescriptor descriptor = getDescriptor();
-        if (descriptor == null) return;
-        descriptor.setValue(writeValue.getBytes());
-        mBluetoothGatt.writeDescriptor(descriptor);
+    private void writeCharacteristic(BluetoothGattCharacteristic characteristic, String writeValue) {
+        if (characteristic != null) {
+            characteristic.setValue(writeValue);
+            mBluetoothGatt.writeCharacteristic(characteristic);
+        }
     }
 
-    private void readDescriptor() {
-        BluetoothGattDescriptor descriptor = getDescriptor();
-        if (descriptor != null) mBluetoothGatt.readDescriptor(descriptor);
+    private void writeCharacteristic(UUID uid, String writeValue) {
+        BluetoothGattCharacteristic characteristic = getCharacteristic(uid);
+        if (characteristic != null){
+            writeCharacteristic(characteristic, writeValue);
+        }
+    }
+
+    private void readCharacteristic(UUID uuid) {
+        BluetoothGattCharacteristic characteristic = getCharacteristic(uuid);
+        if (characteristic != null) {
+            mBluetoothGatt.readCharacteristic(characteristic);
+        }
+    }
+
+    private void writeDescriptor(UUID uid, String writeValue) {
+        BluetoothGattDescriptor descriptor = getDescriptor(uid);
+        if (descriptor != null) {
+            descriptor.setValue(writeValue.getBytes());
+            mBluetoothGatt.writeDescriptor(descriptor);
+        }
+    }
+
+    private void readDescriptor(UUID uuid) {
+        BluetoothGattDescriptor descriptor = getDescriptor(uuid);
+        if (descriptor != null) {
+            mBluetoothGatt.readDescriptor(descriptor);
+        }
+    }
+
+    private void writeDescriptor(UUID cuid, UUID duid, String writeValue) {
+        BluetoothGattDescriptor descriptor = getDescriptor(cuid, duid);
+        if (descriptor != null) {
+            descriptor.setValue(writeValue.getBytes());
+            mBluetoothGatt.writeDescriptor(descriptor);
+        }
+    }
+
+    private void readDescriptor(UUID cuid, UUID duid) {
+        BluetoothGattDescriptor descriptor = getDescriptor(cuid, duid);
+        if (descriptor != null) {
+            mBluetoothGatt.readDescriptor(descriptor);
+        }
+    }
+
+    private void setNotification(BluetoothGattCharacteristic characteristic, boolean enable) {
+        if (characteristic != null) {
+            mBluetoothGatt.setCharacteristicNotification(characteristic, enable);
+            BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UPDATE_DESCRIPTOR_UUID);
+            if (enable) {
+                if (characteristic.getUuid().equals(INDICATE_CHARACTERISTIC_UUID)) {
+                    descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
+                } else {
+                    descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
+                }
+            } else {
+                descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
+            }
+            mBluetoothGatt.writeDescriptor(descriptor);
+        }
     }
 
     private void setNotification(boolean enable) {
         BluetoothGattCharacteristic characteristic = getCharacteristic(UPDATE_CHARACTERISTIC_UUID);
-        if (characteristic != null)
-            mBluetoothGatt.setCharacteristicNotification(characteristic, enable);
+        if (characteristic != null) {
+            setNotification(characteristic, enable);
+        }
+    }
+
+    private void setNotification(UUID serviceUid, UUID characteristicUid,  boolean enable) {
+        BluetoothGattCharacteristic characteristic = getCharacteristic(serviceUid, characteristicUid);
+        if (characteristic != null) {
+            setNotification(characteristic, enable);
+        }
+    }
+
+    private void setNotification(UUID uid, boolean enable) {
+        BluetoothGattCharacteristic characteristic = getCharacteristic(uid);
+        if (characteristic != null) {
+           setNotification(characteristic, enable);
+        }
     }
 
     private void notifyError(String message) {
         showMessage(message);
+        Log.i(TAG, message);
+
+        Intent intent = new Intent(BLE_CLIENT_ERROR);
+        sendBroadcast(intent);
+    }
+
+    private void notifyMismatchSecure() {
+        Intent intent = new Intent(BLE_BLUETOOTH_MISMATCH_SECURE);
+        sendBroadcast(intent);
+    }
+
+    private void notifyMismatchInsecure() {
+        Intent intent = new Intent(BLE_BLUETOOTH_MISMATCH_INSECURE);
+        sendBroadcast(intent);
+    }
+
+    private void notifyBluetoothDisabled() {
+        Intent intent = new Intent(BLE_BLUETOOTH_DISABLED);
+        sendBroadcast(intent);
     }
 
     private void notifyConnected() {
-        showMessage("BLE connected");
+        showMessage("Bluetooth LE connected");
         Intent intent = new Intent(BLE_BLUETOOTH_CONNECTED);
         sendBroadcast(intent);
     }
 
     private void notifyDisconnected() {
-        showMessage("BLE disconnected");
+        showMessage("Bluetooth LE disconnected");
         Intent intent = new Intent(BLE_BLUETOOTH_DISCONNECTED);
         sendBroadcast(intent);
     }
@@ -201,6 +659,18 @@
         sendBroadcast(intent);
     }
 
+    private void notifyMtuChanged() {
+        Intent intent;
+        if (BLE_CLIENT_ACTION_REQUEST_MTU_23.equals(mCurrentAction)) {
+            intent = new Intent(BLE_MTU_CHANGED_23BYTES);
+        } else if (BLE_CLIENT_ACTION_REQUEST_MTU_512.equals(mCurrentAction)) {
+            intent = new Intent(BLE_MTU_CHANGED_512BYTES);
+        } else {
+            throw new IllegalStateException("unexpected action: " + mCurrentAction);
+        }
+        sendBroadcast(intent);
+    }
+
     private void notifyCharacteristicRead(String value) {
         showMessage("Characteristic read: " + value);
         Intent intent = new Intent(BLE_CHARACTERISTIC_READ);
@@ -214,10 +684,39 @@
         sendBroadcast(intent);
     }
 
-    private void notifyCharacteristicChanged(String value) {
-        showMessage("Characteristic changed: " + value);
+    private void notifyCharacteristicReadNoPermission() {
+        showMessage("Characteristic not read: No Permission");
+        Intent intent = new Intent(BLE_CHARACTERISTIC_READ_NOPERMISSION);
+        sendBroadcast(intent);
+    }
+
+    private void notifyCharacteristicWriteNoPermission(String value) {
+        showMessage("Characteristic write: No Permission");
+        Intent intent = new Intent(BLE_CHARACTERISTIC_WRITE_NOPERMISSION);
+        sendBroadcast(intent);
+    }
+
+    private void notifyCharacteristicReadNeedEncrypted(String value) {
+        showMessage("Characteristic read with encrypted: " + value);
+        Intent intent = new Intent(BLE_CHARACTERISTIC_READ_NEED_ENCRYPTED);
+        sendBroadcast(intent);
+    }
+
+    private void notifyCharacteristicWriteNeedEncrypted(String value) {
+        showMessage("Characteristic write with encrypted: " + value);
+        Intent intent = new Intent(BLE_CHARACTERISTIC_WRITE_NEED_ENCRYPTED);
+        sendBroadcast(intent);
+    }
+
+    private void notifyCharacteristicChanged() {
+        showMessage("Characteristic changed");
         Intent intent = new Intent(BLE_CHARACTERISTIC_CHANGED);
-        intent.putExtra(EXTRA_CHARACTERISTIC_VALUE, value);
+        sendBroadcast(intent);
+    }
+
+    private void notifyCharacteristicIndicated() {
+        showMessage("Characteristic Indicated");
+        Intent intent = new Intent(BLE_CHARACTERISTIC_INDICATED);
         sendBroadcast(intent);
     }
 
@@ -234,12 +733,45 @@
         sendBroadcast(intent);
     }
 
+    private void notifyDescriptorReadNoPermission() {
+        showMessage("Descriptor read: No Permission");
+        Intent intent = new Intent(BLE_DESCRIPTOR_READ_NOPERMISSION);
+        sendBroadcast(intent);
+    }
+
+    private void notifyDescriptorWriteNoPermission() {
+        showMessage("Descriptor write: NoPermission");
+        Intent intent = new Intent(BLE_DESCRIPTOR_WRITE_NOPERMISSION);
+        sendBroadcast(intent);
+    }
+
+    private void notifyDescriptorReadNeedEncrypted(String value) {
+        showMessage("Descriptor read with encrypted: " + value);
+        Intent intent = new Intent(BLE_DESCRIPTOR_READ_NEED_ENCRYPTED);
+        sendBroadcast(intent);
+    }
+
+    private void notifyDescriptorWriteNeedEncrypted(String value) {
+        showMessage("Descriptor write with encrypted: " + value);
+        Intent intent = new Intent(BLE_DESCRIPTOR_WRITE_NEED_ENCRYPTED);
+        sendBroadcast(intent);
+    }
+
     private void notifyReliableWriteCompleted() {
         showMessage("Reliable write compelte");
         Intent intent = new Intent(BLE_RELIABLE_WRITE_COMPLETED);
         sendBroadcast(intent);
     }
 
+    private void notifyReliableWriteBadRespCompleted(String err) {
+        showMessage("Reliable write(bad response) compelte");
+        Intent intent = new Intent(BLE_RELIABLE_WRITE_BAD_RESP_COMPLETED);
+        if (err != null) {
+            intent.putExtra(EXTRA_ERROR_MESSAGE, err);
+        }
+        sendBroadcast(intent);
+    }
+
     private void notifyReadRemoteRssi(int rssi) {
         showMessage("Remote rssi read: " + rssi);
         Intent intent = new Intent(BLE_READ_REMOTE_RSSI);
@@ -247,37 +779,77 @@
         sendBroadcast(intent);
     }
 
-    private BluetoothGattService getService() {
-        if (mBluetoothGatt == null) return null;
+    private BluetoothGattService getService(UUID serverUid) {
+        BluetoothGattService service = null;
 
-        BluetoothGattService service = mBluetoothGatt.getService(SERVICE_UUID);
-        if (service == null) {
-            showMessage("Service not found");
-            return null;
+        if (mBluetoothGatt != null) {
+            service = mBluetoothGatt.getService(serverUid);
+            if (service == null) {
+                showMessage("Service not found");
+            }
         }
         return service;
     }
 
-    private BluetoothGattCharacteristic getCharacteristic(UUID uuid) {
-        BluetoothGattService service = getService();
-        if (service == null) return null;
+    private BluetoothGattService getService() {
+        BluetoothGattService service = null;
 
-        BluetoothGattCharacteristic characteristic = service.getCharacteristic(uuid);
-        if (characteristic == null) {
-            showMessage("Characteristic not found");
-            return null;
+        if (mBluetoothGatt != null) {
+            service = mBluetoothGatt.getService(SERVICE_UUID);
+            if (service == null) {
+                showMessage("Service not found");
+            }
+        }
+        return service;
+    }
+
+    private BluetoothGattCharacteristic getCharacteristic(UUID serverUid, UUID characteristicUid) {
+        BluetoothGattCharacteristic characteristic = null;
+
+        BluetoothGattService service = getService(serverUid);
+        if (service != null) {
+            characteristic = service.getCharacteristic(characteristicUid);
+            if (characteristic == null) {
+                showMessage("Characteristic not found");
+            }
+        }
+        return characteristic;
+    }
+    private BluetoothGattCharacteristic getCharacteristic(UUID uuid) {
+        BluetoothGattCharacteristic characteristic = null;
+
+        BluetoothGattService service = getService();
+        if (service != null) {
+            characteristic = service.getCharacteristic(uuid);
+            if (characteristic == null) {
+                showMessage("Characteristic not found");
+            }
         }
         return characteristic;
     }
 
-    private BluetoothGattDescriptor getDescriptor() {
-        BluetoothGattCharacteristic characteristic = getCharacteristic(CHARACTERISTIC_UUID);
-        if (characteristic == null) return null;
+    private BluetoothGattDescriptor getDescriptor(UUID uid) {
+        BluetoothGattDescriptor descriptor = null;
 
-        BluetoothGattDescriptor descriptor = characteristic.getDescriptor(DESCRIPTOR_UUID);
-        if (descriptor == null) {
-            showMessage("Descriptor not found");
-            return null;
+        BluetoothGattCharacteristic characteristic = getCharacteristic(CHARACTERISTIC_UUID);
+        if (characteristic != null) {
+            descriptor = characteristic.getDescriptor(uid);
+            if (descriptor == null) {
+                showMessage("Descriptor not found");
+            }
+        }
+        return descriptor;
+    }
+
+    private BluetoothGattDescriptor getDescriptor(UUID cuid, UUID duid) {
+        BluetoothGattDescriptor descriptor = null;
+
+        BluetoothGattCharacteristic characteristic = getCharacteristic(cuid);
+        if (characteristic != null) {
+            descriptor = characteristic.getDescriptor(duid);
+            if (descriptor == null) {
+                showMessage("Descriptor not found");
+            }
         }
         return descriptor;
     }
@@ -299,141 +871,340 @@
     }
 
     private void reliableWrite() {
+        // aborting test
         mBluetoothGatt.beginReliableWrite();
         sleep(1000);
-        writeCharacteristic(WRITE_VALUE);
-        sleep(1000);
-        if (!mBluetoothGatt.executeReliableWrite()) {
-            Log.w(TAG, "reliable write failed");
-        }
-        sleep(1000);
         mBluetoothGatt.abortReliableWrite();
+
+        // writing test
+        sleep(2000);
+        mBluetoothGatt.beginReliableWrite();
+        sleep(1000);
+
+        if (BLE_CLIENT_ACTION_RELIABLE_WRITE.equals(mCurrentAction)) {
+            mExecReliableWrite = ReliableWriteState.RELIABLE_WRITE_WRITE_1ST_DATA;
+            writeCharacteristic(CHARACTERISTIC_UUID, WRITE_VALUE_507BYTES_FOR_RELIABLE_WRITE);
+        } else {
+            mExecReliableWrite = ReliableWriteState.RELIABLE_WRITE_BAD_RESP;
+            writeCharacteristic(CHARACTERISTIC_UUID, WRITE_VALUE_BAD_RESP);
+        }
     }
 
+    private int mBleState = BluetoothProfile.STATE_DISCONNECTED;
     private final BluetoothGattCallback mGattCallbacks = new BluetoothGattCallback() {
         @Override
         public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
-            if (DEBUG) Log.d(TAG, "onConnectionStateChange");
+            if (DEBUG) Log.d(TAG, "onConnectionStateChange: status= " + status + ", newState= " + newState);
             if (status == BluetoothGatt.GATT_SUCCESS) {
                 if (newState == BluetoothProfile.STATE_CONNECTED) {
-                    notifyConnected();
-                    stopScan();
-                    sleep(1000);
-                    mBluetoothGatt.discoverServices();
+                    mBleState = newState;
+                    int bond = gatt.getDevice().getBondState();
+                    boolean bonded = false;
+                    BluetoothDevice target = gatt.getDevice();
+                    Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
+                    if (pairedDevices.size() > 0) {
+                        for (BluetoothDevice device : pairedDevices) {
+                            if (device.getAddress().equals(target.getAddress())) {
+                                bonded = true;
+                                break;
+                            }
+                        }
+                    }
+                    if (mSecure && ((bond == BluetoothDevice.BOND_NONE) || !bonded)) {
+                        // not pairing and execute Secure Test
+                        mBluetoothGatt.disconnect();
+                        notifyMismatchSecure();
+                    } else if (!mSecure && ((bond != BluetoothDevice.BOND_NONE) || bonded)) {
+                        // already pairing nad execute Insecure Test
+                        mBluetoothGatt.disconnect();
+                        notifyMismatchInsecure();
+                    } else {
+                        notifyConnected();
+                    }
                 } else if (status == BluetoothProfile.STATE_DISCONNECTED) {
+                    mBleState = newState;
+                    mSecure = false;
+                    mBluetoothGatt.close();
                     notifyDisconnected();
                 }
             } else {
-                showMessage("Failed to connect");
+                showMessage("Failed to connect: " + status + " , newState = " + newState);
+                mBluetoothGatt.close();
+                mBluetoothGatt = null;
             }
         }
 
         @Override
         public void onServicesDiscovered(BluetoothGatt gatt, int status) {
-            if (DEBUG) Log.d(TAG, "onServiceDiscovered");
-            if ((status == BluetoothGatt.GATT_SUCCESS) &&
-                (mBluetoothGatt.getService(SERVICE_UUID) != null)) {
+            if (DEBUG){
+                Log.d(TAG, "onServiceDiscovered");
+            }
+            if ((status == BluetoothGatt.GATT_SUCCESS) && (mBluetoothGatt.getService(SERVICE_UUID) != null)) {
                 notifyServicesDiscovered();
-                sleep(1000);
-                writeCharacteristic(WRITE_VALUE);
             }
         }
 
         @Override
-        public void onCharacteristicWrite(BluetoothGatt gatt,
-                                          BluetoothGattCharacteristic characteristic, int status) {
+        public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
+            super.onMtuChanged(gatt, mtu, status);
+            if (DEBUG){
+                Log.d(TAG, "onMtuChanged");
+            }
+            if (status == BluetoothGatt.GATT_SUCCESS) {
+                // verify MTU size
+                int requestedMtu;
+                if (BLE_CLIENT_ACTION_REQUEST_MTU_23.equals(mCurrentAction)) {
+                    requestedMtu = 23;
+                } else if (BLE_CLIENT_ACTION_REQUEST_MTU_512.equals(mCurrentAction)) {
+                    requestedMtu = 512;
+                } else {
+                    throw new IllegalStateException("unexpected action: " + mCurrentAction);
+                }
+                if (mtu != requestedMtu) {
+                    String msg = String.format(getString(R.string.ble_mtu_mismatch_message),
+                            requestedMtu, mtu);
+                    showMessage(msg);
+                }
+
+                // test writing characteristic
+                writeCharacteristic(CHARACTERISTIC_UUID, WRITE_VALUE_512BYTES_FOR_MTU);
+            } else {
+                notifyError("Failed to request mtu: " + status);
+            }
+        }
+
+        @Override
+        public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, final int status) {
             String value = characteristic.getStringValue(0);
-            if (DEBUG) Log.d(TAG, "onCharacteristicWrite: characteristic.val="
-                    + value + " status=" + status);
-            BluetoothGattCharacteristic mCharacteristic = getCharacteristic(CHARACTERISTIC_UUID);
-            if ((status == BluetoothGatt.GATT_SUCCESS) &&
-                (value.equals(mCharacteristic.getStringValue(0)))) {
-                notifyCharacteristicWrite(value);
-                sleep(1000);
-                readCharacteristic();
+            final UUID uid = characteristic.getUuid();
+            if (DEBUG) {
+                Log.d(TAG, "onCharacteristicWrite: characteristic.val=" + value + " status=" + status);
+            }
+
+            if (BLE_CLIENT_ACTION_REQUEST_MTU_512.equals(mCurrentAction) ||
+                    BLE_CLIENT_ACTION_REQUEST_MTU_23.equals(mCurrentAction)) {
+                if (status == BluetoothGatt.GATT_SUCCESS) {
+                    notifyMtuChanged();
+                } else {
+                    notifyError("Failed to write characteristic: " + status + " : " + uid);
+                }
             } else {
-                notifyError("Failed to write characteristic: " + value);
+                switch (mExecReliableWrite) {
+                    case RELIABLE_WRITE_NONE:
+                        if (status == BluetoothGatt.GATT_SUCCESS) {
+                            if (characteristic.getUuid().equals(CHARACTERISTIC_NEED_ENCRYPTED_WRITE_UUID)) {
+                                notifyCharacteristicWriteNeedEncrypted(value);
+                            } else if (!characteristic.getUuid().equals(CHARACTERISTIC_RESULT_UUID)) {
+                                // verify
+                                if (Arrays.equals(BleClientService.WRITE_VALUE.getBytes(), characteristic.getValue())) {
+                                    notifyCharacteristicWrite(value);
+                                } else {
+                                    notifyError("Written data is not correct");
+                                }
+                            }
+                        } else if (status == BluetoothGatt.GATT_WRITE_NOT_PERMITTED) {
+                            if (uid.equals(CHARACTERISTIC_NO_WRITE_UUID)) {
+                                writeCharacteristic(getCharacteristic(CHARACTERISTIC_RESULT_UUID), BleServerService.WRITE_NO_PERMISSION);
+                                notifyCharacteristicWriteNoPermission(value);
+                            } else {
+                                notifyError("Not Permission Write: " + status + " : " + uid);
+                            }
+                        } else if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) {
+                            notifyError("Not Authentication Write: " + status + " : " + uid);
+                        } else {
+                            notifyError("Failed to write characteristic: " + status + " : " + uid);
+                        }
+                        break;
+                    case RELIABLE_WRITE_WRITE_1ST_DATA:
+                        // verify
+                        if (WRITE_VALUE_507BYTES_FOR_RELIABLE_WRITE.equals(value)) {
+                            // write next data
+                            mExecReliableWrite = ReliableWriteState.RELIABLE_WRITE_WRITE_2ND_DATA;
+                            writeCharacteristic(CHARACTERISTIC_UUID, WRITE_VALUE_507BYTES_FOR_RELIABLE_WRITE);
+                        } else {
+                            notifyError("Failed to write characteristic: " + status + " : " + uid);
+                        }
+                        break;
+                    case RELIABLE_WRITE_WRITE_2ND_DATA:
+                        // verify
+                        if (WRITE_VALUE_507BYTES_FOR_RELIABLE_WRITE.equals(value)) {
+                            // execute write
+                            mTaskQueue.addTask(new Runnable() {
+                                @Override
+                                public void run() {
+                                    mExecReliableWrite = ReliableWriteState.RELIABLE_WRITE_EXECUTE;
+                                    if (!mBluetoothGatt.executeReliableWrite()) {
+                                        notifyError("reliable write failed");
+                                    }
+                                }
+                            }, 1000);
+                        } else {
+                            notifyError("Failed to write characteristic: " + status + " : " + uid);
+                        }
+                        break;
+                    case RELIABLE_WRITE_BAD_RESP:
+                        mExecReliableWrite = ReliableWriteState.RELIABLE_WRITE_NONE;
+                        // verify response
+                        //   Server sends empty response for this test.
+                        //   Response must be empty.
+                        String err = null;
+                        if (!TextUtils.isEmpty(value)) {
+                            err = "response is not empty";
+                            showMessage(err);
+                        }
+                        // finish reliable write
+                        final String errValue = err;
+                        mTaskQueue.addTask(new Runnable() {
+                            @Override
+                            public void run() {
+                                mBluetoothGatt.abortReliableWrite();
+                                notifyReliableWriteBadRespCompleted(errValue);
+                            }
+                        }, 1000);
+                        break;
+                }
             }
         }
 
         @Override
-        public void onCharacteristicRead(BluetoothGatt gatt,
-                                         BluetoothGattCharacteristic characteristic, int status) {
-            if (DEBUG) Log.d(TAG, "onCharacteristicRead");
-            if ((status == BluetoothGatt.GATT_SUCCESS) &&
-                (characteristic.getUuid().equals(CHARACTERISTIC_UUID))) {
-                notifyCharacteristicRead(characteristic.getStringValue(0));
-                sleep(1000);
-                writeDescriptor(WRITE_VALUE);
+        public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
+            UUID uid = characteristic.getUuid();
+            if (DEBUG) {
+                Log.d(TAG, "onCharacteristicRead: status=" + status);
+            }
+            if (status == BluetoothGatt.GATT_SUCCESS) {
+                String value = characteristic.getStringValue(0);
+                if (characteristic.getUuid().equals(CHARACTERISTIC_NEED_ENCRYPTED_READ_UUID)) {
+                    notifyCharacteristicReadNeedEncrypted(value);
+                } else {
+                    // verify
+                    if (BleServerService.WRITE_VALUE.equals(value)) {
+                        notifyCharacteristicRead(value);
+                    } else {
+                        notifyError("Read data is not correct");
+                    }
+                }
+            } else if (status == BluetoothGatt.GATT_READ_NOT_PERMITTED) {
+                if (uid.equals(CHARACTERISTIC_NO_READ_UUID)) {
+                    writeCharacteristic(getCharacteristic(CHARACTERISTIC_RESULT_UUID), BleServerService.READ_NO_PERMISSION);
+                    notifyCharacteristicReadNoPermission();
+                } else {
+                    notifyError("Not Permission Read: " + status + " : " + uid);
+                }
+            } else if(status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) {
+                notifyError("Not Authentication Read: " + status + " : " + uid);
             } else {
-                notifyError("Failed to read characteristic");
+                notifyError("Failed to read characteristic: " + status + " : " + uid);
             }
         }
 
         @Override
-        public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor,
-                                      int status) {
-            if (DEBUG) Log.d(TAG, "onDescriptorWrite");
-            if ((status == BluetoothGatt.GATT_SUCCESS) &&
-                (descriptor.getUuid().equals(DESCRIPTOR_UUID))) {
-                notifyDescriptorWrite(new String(descriptor.getValue()));
-                sleep(1000);
-                readDescriptor();
+        public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
+            if (DEBUG) {
+                Log.d(TAG, "onDescriptorWrite");
+            }
+            UUID uid = descriptor.getUuid();
+            if ((status == BluetoothGatt.GATT_SUCCESS)) {
+                if (uid.equals(UPDATE_DESCRIPTOR_UUID)) {
+                    Log.d(TAG, "write in update descriptor.");
+                } else if (uid.equals(DESCRIPTOR_UUID)) {
+                    // verify
+                    if (Arrays.equals(WRITE_VALUE.getBytes(), descriptor.getValue())) {
+                        notifyDescriptorWrite(new String(descriptor.getValue()));
+                    } else {
+                        notifyError("Written data is not correct");
+                    }
+                } else if (uid.equals(DESCRIPTOR_NEED_ENCRYPTED_WRITE_UUID)) {
+                    notifyDescriptorWriteNeedEncrypted(new String(descriptor.getValue()));
+                }
+            } else if (status == BluetoothGatt.GATT_WRITE_NOT_PERMITTED) {
+                if (uid.equals(DESCRIPTOR_NO_WRITE_UUID)) {
+                    writeCharacteristic(getCharacteristic(CHARACTERISTIC_RESULT_UUID), BleServerService.DESCRIPTOR_WRITE_NO_PERMISSION);
+                    notifyDescriptorWriteNoPermission();
+                } else {
+                    notifyError("Not Permission Write: " + status + " : " + descriptor.getUuid());
+                }
             } else {
                 notifyError("Failed to write descriptor");
             }
         }
 
         @Override
-        public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor,
-                                     int status) {
-            if (DEBUG) Log.d(TAG, "onDescriptorRead");
-            if ((status == BluetoothGatt.GATT_SUCCESS) &&
-                (descriptor.getUuid() != null) &&
-                (descriptor.getUuid().equals(DESCRIPTOR_UUID))) {
-                notifyDescriptorRead(new String(descriptor.getValue()));
-                sleep(1000);
-                setNotification(true);
+        public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
+            if (DEBUG) {
+                Log.d(TAG, "onDescriptorRead");
+            }
+
+            UUID uid = descriptor.getUuid();
+            if ((status == BluetoothGatt.GATT_SUCCESS)) {
+                if ((uid != null) && (uid.equals(DESCRIPTOR_UUID))) {
+                    // verify
+                    if (Arrays.equals(BleServerService.WRITE_VALUE.getBytes(), descriptor.getValue())) {
+                        notifyDescriptorRead(new String(descriptor.getValue()));
+                    } else {
+                        notifyError("Read data is not correct");
+                    }
+                } else if (uid.equals(DESCRIPTOR_NEED_ENCRYPTED_READ_UUID)) {
+                    notifyDescriptorReadNeedEncrypted(new String(descriptor.getValue()));
+                }
+            } else if (status == BluetoothGatt.GATT_READ_NOT_PERMITTED) {
+                if (uid.equals(DESCRIPTOR_NO_READ_UUID)) {
+                    writeCharacteristic(getCharacteristic(CHARACTERISTIC_RESULT_UUID), BleServerService.DESCRIPTOR_READ_NO_PERMISSION);
+                    notifyDescriptorReadNoPermission();
+                } else {
+                    notifyError("Not Permission Read: " + status + " : " + descriptor.getUuid());
+                }
             } else {
-                notifyError("Failed to read descriptor");
+                notifyError("Failed to read descriptor: " + status);
             }
         }
 
         @Override
-        public void onCharacteristicChanged(BluetoothGatt gatt,
-                                            BluetoothGattCharacteristic characteristic) {
-            if (DEBUG) Log.d(TAG, "onCharacteristicChanged");
-            if ((characteristic.getUuid() != null) &&
-                (characteristic.getUuid().equals(UPDATE_CHARACTERISTIC_UUID))) {
-                notifyCharacteristicChanged(characteristic.getStringValue(0));
-                setNotification(false);
-                sleep(1000);
-                mBluetoothGatt.readRemoteRssi();
+        public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
+            UUID uid = characteristic.getUuid();
+            if (DEBUG) {
+                Log.d(TAG, "onCharacteristicChanged: " + uid);
+            }
+            if (uid != null) {
+                if (uid.equals(INDICATE_CHARACTERISTIC_UUID)) {
+                    setNotification(characteristic, false);
+                    notifyCharacteristicIndicated();
+                } else {
+                    mNotifyCount--;
+                    setNotification(characteristic, false);
+                    if (mNotifyCount == 0) {
+                        notifyCharacteristicChanged();
+                    }
+                }
             }
         }
 
         @Override
         public void onReliableWriteCompleted(BluetoothGatt gatt, int status) {
-            if (DEBUG) Log.d(TAG, "onReliableWriteComplete: " + status);
-            if (status == BluetoothGatt.GATT_SUCCESS) {
-                notifyReliableWriteCompleted();
-            } else {
-                notifyError("Failed to complete reliable write: " + status);
+            if (DEBUG) {
+                Log.d(TAG, "onReliableWriteComplete: " + status);
             }
-            sleep(1000);
-            mBluetoothGatt.disconnect();
+
+            if (mExecReliableWrite != ReliableWriteState.RELIABLE_WRITE_NONE) {
+                if (status == BluetoothGatt.GATT_SUCCESS) {
+                    notifyReliableWriteCompleted();
+                } else {
+                    notifyError("Failed to complete reliable write: " + status);
+                }
+                mExecReliableWrite = ReliableWriteState.RELIABLE_WRITE_NONE;
+            }
         }
 
         @Override
         public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
-            if (DEBUG) Log.d(TAG, "onReadRemoteRssi");
+            if (DEBUG) {
+                Log.d(TAG, "onReadRemoteRssi");
+            }
             if (status == BluetoothGatt.GATT_SUCCESS) {
                 notifyReadRemoteRssi(rssi);
             } else {
                 notifyError("Failed to read remote rssi");
             }
-            sleep(1000);
-            reliableWrite();
         }
     };
 
@@ -441,7 +1212,33 @@
         @Override
         public void onScanResult(int callbackType, ScanResult result) {
             if (mBluetoothGatt == null) {
-                mBluetoothGatt = result.getDevice().connectGatt(mContext, false, mGattCallbacks);
+                // verify the validity of the advertisement packet.
+                mValidityService = false;
+                List<ParcelUuid> uuids = result.getScanRecord().getServiceUuids();
+                for (ParcelUuid uuid : uuids) {
+                    if (uuid.getUuid().equals(BleServerService.ADV_SERVICE_UUID)) {
+                        mValidityService = true;
+                        break;
+                    }
+                }
+                if (mValidityService) {
+                    stopScan();
+
+                    BluetoothDevice device = result.getDevice();
+                    if (mSecure) {
+                        if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
+                            if (!device.createBond()) {
+                                notifyError("Failed to call create bond");
+                            }
+                        } else {
+                            mBluetoothGatt = connectGatt(result.getDevice(), mContext, false, mSecure, mGattCallbacks);
+                        }
+                    } else {
+                        mBluetoothGatt = connectGatt(result.getDevice(), mContext, false, mSecure, mGattCallbacks);
+                    }
+                } else {
+                    notifyError("There is no validity to Advertise servie.");
+                }
             }
         }
     };
@@ -457,6 +1254,40 @@
 
     private void stopScan() {
         if (DEBUG) Log.d(TAG, "stopScan");
-        mScanner.stopScan(mScanCallback);
+        if (mScanner != null) {
+            mScanner.stopScan(mScanCallback);
+        }
     }
+
+    private static String createTestData(int length) {
+        StringBuilder builder = new StringBuilder();
+        builder.append("REQUEST_MTU");
+        int len = length - builder.length();
+        for (int i = 0; i < len; ++i) {
+            builder.append(""+(i%10));
+        }
+        return builder.toString();
+    }
+
+    private final BroadcastReceiver mBondStatusReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (intent.getAction().equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED)) {
+                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+                int state = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.BOND_NONE);
+                switch (state) {
+                    case BluetoothDevice.BOND_BONDED:
+                        mBluetoothGatt = connectGatt(device, mContext, false, mSecure, mGattCallbacks);
+                        break;
+                    case BluetoothDevice.BOND_NONE:
+                        notifyError("Failed to create bond.");
+                        break;
+                    case BluetoothDevice.BOND_BONDING:
+                    default:    // fall through
+                        // wait for next state
+                        break;
+                }
+            }
+        }
+    };
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientStartActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientStartActivity.java
deleted file mode 100644
index 5a4e327..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientStartActivity.java
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Copyright (C) 2014 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 com.android.cts.verifier.PassFailButtons;
-import com.android.cts.verifier.R;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Bundle;
-import android.os.Handler;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.BaseAdapter;
-import android.widget.ImageView;
-import android.widget.ListView;
-import android.widget.TextView;
-import android.widget.Toast;
-
-public class BleClientStartActivity extends PassFailButtons.Activity {
-
-    private TestAdapter mTestAdapter;
-    private int mAllPassed;
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.ble_server_start);
-        setPassFailButtonClickListeners();
-        setInfoResources(R.string.ble_server_start_name,
-                         R.string.ble_server_start_info, -1);
-        getPassButton().setEnabled(false);
-
-        mTestAdapter = new TestAdapter(this, setupTestList());
-        ListView listView = (ListView) findViewById(R.id.ble_server_tests);
-        listView.setAdapter(mTestAdapter);
-
-        mAllPassed = 0;
-        startService(new Intent(this, BleClientService.class));
-    }
-
-    @Override
-    public void onResume() {
-        super.onResume();
-
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(BleClientService.BLE_BLUETOOTH_CONNECTED);
-        filter.addAction(BleClientService.BLE_BLUETOOTH_DISCONNECTED);
-        filter.addAction(BleClientService.BLE_SERVICES_DISCOVERED);
-        filter.addAction(BleClientService.BLE_CHARACTERISTIC_READ);
-        filter.addAction(BleClientService.BLE_CHARACTERISTIC_WRITE);
-        filter.addAction(BleClientService.BLE_CHARACTERISTIC_CHANGED);
-        filter.addAction(BleClientService.BLE_DESCRIPTOR_READ);
-        filter.addAction(BleClientService.BLE_DESCRIPTOR_WRITE);
-        filter.addAction(BleClientService.BLE_RELIABLE_WRITE_COMPLETED);
-        filter.addAction(BleClientService.BLE_READ_REMOTE_RSSI);
-        registerReceiver(onBroadcast, filter);
-    }
-
-    @Override
-    public void onPause() {
-        super.onPause();
-        unregisterReceiver(onBroadcast);
-    }
-
-    @Override
-    public void onDestroy() {
-        super.onDestroy();
-        stopService(new Intent(this, BleClientService.class));
-    }
-
-    private List<Integer> setupTestList() {
-        ArrayList<Integer> testList = new ArrayList<Integer>();
-        testList.add(R.string.ble_client_connect_name);
-        testList.add(R.string.ble_discover_service_name);
-        testList.add(R.string.ble_read_characteristic_name);
-        testList.add(R.string.ble_write_characteristic_name);
-        testList.add(R.string.ble_reliable_write_name);
-        testList.add(R.string.ble_notify_characteristic_name);
-        testList.add(R.string.ble_read_descriptor_name);
-        testList.add(R.string.ble_write_descriptor_name);
-        testList.add(R.string.ble_read_rssi_name);
-        testList.add(R.string.ble_client_disconnect_name);
-        return testList;
-    }
-
-    private BroadcastReceiver onBroadcast = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            if (action == BleClientService.BLE_BLUETOOTH_CONNECTED) {
-                mTestAdapter.setTestPass(0);
-                mAllPassed |= 0x01;
-            } else if (action == BleClientService.BLE_SERVICES_DISCOVERED) {
-                mTestAdapter.setTestPass(1);
-                mAllPassed |= 0x02;
-            } else if (action == BleClientService.BLE_CHARACTERISTIC_READ) {
-                mTestAdapter.setTestPass(2);
-                mAllPassed |= 0x04;
-            } else if (action == BleClientService.BLE_CHARACTERISTIC_WRITE) {
-                mTestAdapter.setTestPass(3);
-                mAllPassed |= 0x08;
-            } else if (action == BleClientService.BLE_RELIABLE_WRITE_COMPLETED) {
-                mTestAdapter.setTestPass(4);
-                mAllPassed |= 0x10;
-            } else if (action == BleClientService.BLE_CHARACTERISTIC_CHANGED) {
-                mTestAdapter.setTestPass(5);
-                mAllPassed |= 0x20;
-            } else if (action == BleClientService.BLE_DESCRIPTOR_READ) {
-                mTestAdapter.setTestPass(6);
-                mAllPassed |= 0x40;
-            } else if (action == BleClientService.BLE_DESCRIPTOR_WRITE) {
-                mTestAdapter.setTestPass(7);
-                mAllPassed |= 0x80;
-            } else if (action == BleClientService.BLE_READ_REMOTE_RSSI) {
-                mTestAdapter.setTestPass(8);
-                mAllPassed |= 0x100;
-            } else if (action == BleClientService.BLE_BLUETOOTH_DISCONNECTED) {
-                mTestAdapter.setTestPass(9);
-                mAllPassed |= 0x200;
-            }
-            mTestAdapter.notifyDataSetChanged();
-            if (mAllPassed == 0x3FF) getPassButton().setEnabled(true);
-        }
-    };
-
-}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientTestBaseActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientTestBaseActivity.java
new file mode 100644
index 0000000..f7adc3d
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientTestBaseActivity.java
@@ -0,0 +1,454 @@
+/*
+ * Copyright (C) 2014 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.AlertDialog;
+import android.app.Dialog;
+import android.app.ProgressDialog;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.os.Handler;
+import android.widget.ListView;
+
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class BleClientTestBaseActivity extends PassFailButtons.Activity {
+    public static final String TAG = "BleClientTestBase";
+
+    private static final boolean STEP_EXECUTION = false;
+
+    private static final int PASS_FLAG_CONNECT = 0x1;
+    private static final int PASS_FLAG_DISCOVER = 0x2;
+    private static final int PASS_FLAG_READ_CHARACTERISTIC = 0x4;
+    private static final int PASS_FLAG_WRITE_CHARACTERISTIC = 0x8;
+    private static final int PASS_FLAG_RELIABLE_WRITE = 0x10;
+    private static final int PASS_FLAG_NOTIFY_CHARACTERISTIC = 0x20;
+    private static final int PASS_FLAG_READ_DESCRIPTOR = 0x40;
+    private static final int PASS_FLAG_WRITE_DESCRIPTOR = 0x80;
+    private static final int PASS_FLAG_READ_RSSI = 0x100;
+    private static final int PASS_FLAG_DISCONNECT = 0x200;
+    private static final int PASS_FLAG_READ_CHARACTERISTIC_NO_PERMISSION = 0x400;
+    private static final int PASS_FLAG_WRITE_CHARACTERISTIC_NO_PERMISSION = 0x800;
+    private static final int PASS_FLAG_READ_DESCRIPTOR_NO_PERMISSION = 0x1000;
+    private static final int PASS_FLAG_WRITE_DESCRIPTOR_NO_PERMISSION = 0x2000;
+    private static final int PASS_FLAG_MTU_CHANGE_23BYTES = 0x4000;
+    private static final int PASS_FLAG_INDICATE_CHARACTERISTIC = 0x8000;
+    private static final int PASS_FLAG_MTU_CHANGE_512BYTES = 0x10000;
+    private static final int PASS_FLAG_RELIABLE_WRITE_BAD_RESP = 0x20000;
+    private static final int PASS_FLAG_ALL = 0x3FFFF;
+
+    private final int BLE_CLIENT_CONNECT = 0;
+    private final int BLE_BLE_DISVOCER_SERVICE = 1;
+    private final int BLE_READ_CHARACTERISTIC = 2;
+    private final int BLE_WRITE_CHARACTERISTIC = 3;
+    private final int BLE_REQUEST_MTU_23BYTES = 4;
+    private final int BLE_REQUEST_MTU_512BYTES = 5;
+    private final int BLE_READ_CHARACTERISTIC_NO_PERMISSION = 6;
+    private final int BLE_WRITE_CHARACTERISTIC_NO_PERMISSION = 7;
+    private final int BLE_RELIABLE_WRITE = 8;
+    private final int BLE_RELIABLE_WRITE_BAD_RESP = 9;
+    private final int BLE_NOTIFY_CHARACTERISTIC = 9;    //10;
+    private final int BLE_INDICATE_CHARACTERISTIC = 10;  //11;
+    private final int BLE_READ_DESCRIPTOR = 11; //12;
+    private final int BLE_WRITE_DESCRIPTOR = 12;    //13;
+    private final int BLE_READ_DESCRIPTOR_NO_PERMISSION = 13;   //14;
+    private final int BLE_WRITE_DESCRIPTOR_NO_PERMISSION = 14;  //15;
+    private final int BLE_READ_RSSI = 15;   //16;
+    private final int BLE_CLIENT_DISCONNECT = 16;   //17;
+
+    private TestAdapter mTestAdapter;
+    private long mPassed;
+    private Dialog mDialog;
+    private Handler mHandler;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.ble_server_start);
+        setPassFailButtonClickListeners();
+        setInfoResources(R.string.ble_client_test_name,
+                R.string.ble_client_test_info, -1);
+        getPassButton().setEnabled(false);
+
+        mTestAdapter = new TestAdapter(this, setupTestList());
+        ListView listView = (ListView) findViewById(R.id.ble_server_tests);
+        listView.setAdapter(mTestAdapter);
+
+        mPassed = 0;
+        mHandler = new Handler();
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(BleClientService.BLE_BLUETOOTH_CONNECTED);
+        filter.addAction(BleClientService.BLE_BLUETOOTH_DISCONNECTED);
+        filter.addAction(BleClientService.BLE_SERVICES_DISCOVERED);
+        filter.addAction(BleClientService.BLE_MTU_CHANGED_23BYTES);
+        filter.addAction(BleClientService.BLE_MTU_CHANGED_512BYTES);
+        filter.addAction(BleClientService.BLE_CHARACTERISTIC_READ);
+        filter.addAction(BleClientService.BLE_CHARACTERISTIC_WRITE);
+        filter.addAction(BleClientService.BLE_CHARACTERISTIC_CHANGED);
+        filter.addAction(BleClientService.BLE_DESCRIPTOR_READ);
+        filter.addAction(BleClientService.BLE_DESCRIPTOR_WRITE);
+        filter.addAction(BleClientService.BLE_RELIABLE_WRITE_COMPLETED);
+        filter.addAction(BleClientService.BLE_RELIABLE_WRITE_BAD_RESP_COMPLETED);
+        filter.addAction(BleClientService.BLE_READ_REMOTE_RSSI);
+        filter.addAction(BleClientService.BLE_CHARACTERISTIC_READ_NOPERMISSION);
+        filter.addAction(BleClientService.BLE_CHARACTERISTIC_WRITE_NOPERMISSION);
+        filter.addAction(BleClientService.BLE_DESCRIPTOR_READ_NOPERMISSION);
+        filter.addAction(BleClientService.BLE_DESCRIPTOR_WRITE_NOPERMISSION);
+        filter.addAction(BleClientService.BLE_CHARACTERISTIC_INDICATED);
+        filter.addAction(BleClientService.BLE_BLUETOOTH_DISABLED);
+        filter.addAction(BleClientService.BLE_BLUETOOTH_MISMATCH_SECURE);
+        filter.addAction(BleClientService.BLE_BLUETOOTH_MISMATCH_INSECURE);
+        filter.addAction(BleClientService.BLE_CLIENT_ERROR);
+
+        registerReceiver(mBroadcast, filter);
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        unregisterReceiver(mBroadcast);
+        closeDialog();
+    }
+
+    private synchronized void closeDialog() {
+        if (mDialog != null) {
+            mDialog.dismiss();
+            mDialog = null;
+        }
+    }
+
+    private synchronized void showProgressDialog() {
+        closeDialog();
+
+        ProgressDialog dialog = new ProgressDialog(this);
+        dialog.setTitle(R.string.ble_test_running);
+        dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
+        dialog.setMessage(getString(R.string.ble_test_running_message));
+        dialog.setCanceledOnTouchOutside(false);
+        mDialog = dialog;
+        mDialog.show();
+    }
+
+    private List<Integer> setupTestList() {
+        ArrayList<Integer> testList = new ArrayList<Integer>();
+        testList.add(R.string.ble_client_connect_name);
+        testList.add(R.string.ble_discover_service_name);
+        testList.add(R.string.ble_read_characteristic_name);
+        testList.add(R.string.ble_write_characteristic_name);
+        testList.add(R.string.ble_mtu_23_name);
+        testList.add(R.string.ble_mtu_512_name);
+        testList.add(R.string.ble_read_characteristic_nopermission_name);
+        testList.add(R.string.ble_write_characteristic_nopermission_name);
+        testList.add(R.string.ble_reliable_write_name);
+//        testList.add(R.string.ble_reliable_write_bad_resp_name);
+        testList.add(R.string.ble_notify_characteristic_name);
+        testList.add(R.string.ble_indicate_characteristic_name);
+        testList.add(R.string.ble_read_descriptor_name);
+        testList.add(R.string.ble_write_descriptor_name);
+        testList.add(R.string.ble_read_descriptor_nopermission_name);
+        testList.add(R.string.ble_write_descriptor_nopermission_name);
+        testList.add(R.string.ble_read_rssi_name);
+        testList.add(R.string.ble_client_disconnect_name);
+
+        return testList;
+    }
+
+    private void showErrorDialog(int titleId, int messageId, boolean finish) {
+        AlertDialog.Builder builder = new AlertDialog.Builder(this)
+                .setTitle(titleId)
+                .setMessage(messageId);
+        if (finish) {
+            builder.setOnCancelListener(new Dialog.OnCancelListener() {
+                @Override
+                public void onCancel(DialogInterface dialog) {
+                    finish();
+                }
+            });
+        }
+        builder.create().show();
+    }
+
+    public boolean shouldRebootBluetoothAfterTest() {
+        return false;
+    }
+
+    private BroadcastReceiver mBroadcast = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            boolean showProgressDialog = false;
+            closeDialog();
+
+            String action = intent.getAction();
+            String newAction = null;
+            String actionName = null;
+            final Intent startIntent = new Intent(BleClientTestBaseActivity.this, BleClientService.class);
+            switch (action) {
+            case BleClientService.BLE_BLUETOOTH_DISABLED:
+                showErrorDialog(R.string.ble_bluetooth_disable_title, R.string.ble_bluetooth_disable_message, true);
+                break;
+            case BleClientService.BLE_BLUETOOTH_CONNECTED:
+                actionName = getString(R.string.ble_client_connect_name);
+                mTestAdapter.setTestPass(BLE_CLIENT_CONNECT);
+                mPassed |= PASS_FLAG_CONNECT;
+                // execute service discovery test
+                newAction = BleClientService.BLE_CLIENT_ACTION_BLE_DISVOCER_SERVICE;
+                break;
+            case BleClientService.BLE_SERVICES_DISCOVERED:
+                actionName = getString(R.string.ble_discover_service_name);
+                mTestAdapter.setTestPass(BLE_BLE_DISVOCER_SERVICE);
+                mPassed |= PASS_FLAG_DISCOVER;
+                // execute MTU requesting test (23bytes)
+                newAction = BleClientService.BLE_CLIENT_ACTION_READ_CHARACTERISTIC;
+                break;
+            case BleClientService.BLE_MTU_CHANGED_23BYTES:
+                actionName = getString(R.string.ble_mtu_23_name);
+                mTestAdapter.setTestPass(BLE_REQUEST_MTU_23BYTES);
+                mPassed |= PASS_FLAG_MTU_CHANGE_23BYTES;
+                // execute MTU requesting test (512bytes)
+                newAction = BleClientService.BLE_CLIENT_ACTION_REQUEST_MTU_512;
+                showProgressDialog = true;
+                break;
+            case BleClientService.BLE_MTU_CHANGED_512BYTES:
+                actionName = getString(R.string.ble_mtu_512_name);
+                mTestAdapter.setTestPass(BLE_REQUEST_MTU_512BYTES);
+                mPassed |= PASS_FLAG_MTU_CHANGE_512BYTES;
+                // execute characteristic reading test
+                newAction = BleClientService.BLE_CLIENT_ACTION_READ_CHARACTERISTIC_NO_PERMISSION;
+                break;
+            case BleClientService.BLE_CHARACTERISTIC_READ:
+                actionName = getString(R.string.ble_read_characteristic_name);
+                mTestAdapter.setTestPass(BLE_READ_CHARACTERISTIC);
+                mPassed |= PASS_FLAG_READ_CHARACTERISTIC;
+                // execute characteristic writing test
+                newAction = BleClientService.BLE_CLIENT_ACTION_WRITE_CHARACTERISTIC;
+                break;
+            case BleClientService.BLE_CHARACTERISTIC_WRITE:
+                actionName = getString(R.string.ble_write_characteristic_name);
+                mTestAdapter.setTestPass(BLE_WRITE_CHARACTERISTIC);
+                mPassed |= PASS_FLAG_WRITE_CHARACTERISTIC;
+                newAction = BleClientService.BLE_CLIENT_ACTION_REQUEST_MTU_23;
+                showProgressDialog = true;
+                break;
+            case BleClientService.BLE_CHARACTERISTIC_READ_NOPERMISSION:
+                actionName = getString(R.string.ble_read_characteristic_nopermission_name);
+                mTestAdapter.setTestPass(BLE_READ_CHARACTERISTIC_NO_PERMISSION);
+                mPassed |= PASS_FLAG_READ_CHARACTERISTIC_NO_PERMISSION;
+                // execute unpermitted characteristic writing test
+                newAction = BleClientService.BLE_CLIENT_ACTION_WRITE_CHARACTERISTIC_NO_PERMISSION;
+                break;
+            case BleClientService.BLE_CHARACTERISTIC_WRITE_NOPERMISSION:
+                actionName = getString(R.string.ble_write_characteristic_nopermission_name);
+                mTestAdapter.setTestPass(BLE_WRITE_CHARACTERISTIC_NO_PERMISSION);
+                mPassed |= PASS_FLAG_WRITE_CHARACTERISTIC_NO_PERMISSION;
+                // execute reliable write test
+                newAction = BleClientService.BLE_CLIENT_ACTION_RELIABLE_WRITE;
+                showProgressDialog = true;
+                break;
+            case BleClientService.BLE_RELIABLE_WRITE_COMPLETED:
+                actionName = getString(R.string.ble_reliable_write_name);
+                mTestAdapter.setTestPass(BLE_RELIABLE_WRITE);
+                mPassed |= PASS_FLAG_RELIABLE_WRITE;
+//                newAction = BleClientService.BLE_CLIENT_ACTION_RELIABLE_WRITE_BAD_RESP;
+
+                // skip Reliable write (bad response) test
+                mPassed |= PASS_FLAG_RELIABLE_WRITE_BAD_RESP;
+                newAction = BleClientService.BLE_CLIENT_ACTION_NOTIFY_CHARACTERISTIC;
+                showProgressDialog = true;
+                break;
+            case BleClientService.BLE_RELIABLE_WRITE_BAD_RESP_COMPLETED: {
+                actionName = getString(R.string.ble_reliable_write_bad_resp_name);
+                if(!intent.hasExtra(BleClientService.EXTRA_ERROR_MESSAGE)) {
+                    mPassed |= PASS_FLAG_RELIABLE_WRITE_BAD_RESP;
+                    mTestAdapter.setTestPass(BLE_RELIABLE_WRITE_BAD_RESP);
+                }
+                // execute notification test
+                newAction = BleClientService.BLE_CLIENT_ACTION_NOTIFY_CHARACTERISTIC;
+                showProgressDialog = true;
+            }
+                break;
+            case BleClientService.BLE_CHARACTERISTIC_CHANGED:
+                actionName = getString(R.string.ble_notify_characteristic_name);
+                mTestAdapter.setTestPass(BLE_NOTIFY_CHARACTERISTIC);
+                mPassed |= PASS_FLAG_NOTIFY_CHARACTERISTIC;
+                // execute indication test
+                newAction = BleClientService.BLE_CLIENT_ACTION_INDICATE_CHARACTERISTIC;
+                showProgressDialog = true;
+                break;
+            case BleClientService.BLE_CHARACTERISTIC_INDICATED:
+                actionName = getString(R.string.ble_indicate_characteristic_name);
+                mTestAdapter.setTestPass(BLE_INDICATE_CHARACTERISTIC);
+                mPassed |= PASS_FLAG_INDICATE_CHARACTERISTIC;
+                // execute descriptor reading test
+                newAction = BleClientService.BLE_CLIENT_ACTION_READ_DESCRIPTOR;
+                break;
+            case BleClientService.BLE_DESCRIPTOR_READ:
+                actionName = getString(R.string.ble_read_descriptor_name);
+                mTestAdapter.setTestPass(BLE_READ_DESCRIPTOR);
+                mPassed |= PASS_FLAG_READ_DESCRIPTOR;
+                // execute descriptor writing test
+                newAction = BleClientService.BLE_CLIENT_ACTION_WRITE_DESCRIPTOR;
+                break;
+            case BleClientService.BLE_DESCRIPTOR_WRITE:
+                actionName = getString(R.string.ble_write_descriptor_name);
+                mTestAdapter.setTestPass(BLE_WRITE_DESCRIPTOR);
+                mPassed |= PASS_FLAG_WRITE_DESCRIPTOR;
+                // execute unpermitted descriptor reading test
+                newAction = BleClientService.BLE_CLIENT_ACTION_READ_DESCRIPTOR_NO_PERMISSION;
+                break;
+            case BleClientService.BLE_DESCRIPTOR_READ_NOPERMISSION:
+                actionName = getString(R.string.ble_read_descriptor_nopermission_name);
+                mTestAdapter.setTestPass(BLE_READ_DESCRIPTOR_NO_PERMISSION);
+                mPassed |= PASS_FLAG_READ_DESCRIPTOR_NO_PERMISSION;
+                // execute unpermitted descriptor writing test
+                newAction = BleClientService.BLE_CLIENT_ACTION_WRITE_DESCRIPTOR_NO_PERMISSION;
+                break;
+            case BleClientService.BLE_DESCRIPTOR_WRITE_NOPERMISSION:
+                actionName = getString(R.string.ble_write_descriptor_nopermission_name);
+                mTestAdapter.setTestPass(BLE_WRITE_DESCRIPTOR_NO_PERMISSION);
+                mPassed |= PASS_FLAG_WRITE_DESCRIPTOR_NO_PERMISSION;
+                // execute RSSI requesting test
+                newAction = BleClientService.BLE_CLIENT_ACTION_READ_RSSI;
+                break;
+            case BleClientService.BLE_READ_REMOTE_RSSI:
+                actionName = getString(R.string.ble_read_rssi_name);
+                mTestAdapter.setTestPass(BLE_READ_RSSI);
+                mPassed |= PASS_FLAG_READ_RSSI;
+                // execute disconnection test
+                newAction = BleClientService.BLE_CLIENT_ACTION_CLIENT_DISCONNECT;
+                break;
+            case BleClientService.BLE_BLUETOOTH_DISCONNECTED:
+                mTestAdapter.setTestPass(BLE_CLIENT_DISCONNECT);
+                mPassed |= PASS_FLAG_DISCONNECT;
+                // all test done
+                newAction = null;
+                break;
+            case BleClientService.BLE_BLUETOOTH_MISMATCH_SECURE:
+                showErrorDialog(R.string.ble_bluetooth_mismatch_title, R.string.ble_bluetooth_mismatch_secure_message, true);
+                break;
+            case BleClientService.BLE_BLUETOOTH_MISMATCH_INSECURE:
+                showErrorDialog(R.string.ble_bluetooth_mismatch_title, R.string.ble_bluetooth_mismatch_insecure_message, true);
+                break;
+            }
+
+            mTestAdapter.notifyDataSetChanged();
+
+            if (newAction != null) {
+                startIntent.setAction(newAction);
+                if (STEP_EXECUTION) {
+                    closeDialog();
+                    final boolean showProgressDialogValue = showProgressDialog;
+                    mDialog = new AlertDialog.Builder(BleClientTestBaseActivity.this)
+                            .setTitle(actionName)
+                            .setMessage(R.string.ble_test_finished)
+                            .setCancelable(false)
+                            .setPositiveButton(R.string.ble_test_next,
+                                    new DialogInterface.OnClickListener() {
+                                        @Override
+                                        public void onClick(DialogInterface dialog, int which) {
+                                            closeDialog();
+                                            if (showProgressDialogValue) {
+                                                showProgressDialog();
+                                            }
+                                            startService(startIntent);
+                                        }
+                                    })
+                            .show();
+                } else {
+                    if (showProgressDialog) {
+                        showProgressDialog();
+                    }
+                    startService(startIntent);
+                }
+            } else {
+                closeDialog();
+            }
+
+            if (mPassed == PASS_FLAG_ALL) {
+                if (shouldRebootBluetoothAfterTest()) {
+                    mBtPowerSwitcher.executeSwitching();
+                } else {
+                    getPassButton().setEnabled(true);
+                }
+            }
+        }
+    };
+
+    private static final long BT_ON_DELAY = 10000;
+    private final BluetoothPowerSwitcher mBtPowerSwitcher = new BluetoothPowerSwitcher();
+    private class BluetoothPowerSwitcher extends BroadcastReceiver {
+
+        private boolean mIsSwitching = false;
+        private BluetoothAdapter mAdapter;
+
+        public void executeSwitching() {
+            if (mAdapter == null) {
+                BluetoothManager btMgr = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
+                mAdapter = btMgr.getAdapter();
+            }
+
+            if (!mIsSwitching) {
+                IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
+                registerReceiver(this, filter);
+                mIsSwitching = true;
+                mHandler.postDelayed(new Runnable() {
+                    @Override
+                    public void run() {
+                        mAdapter.disable();
+                    }
+                }, 1000);
+                showProgressDialog();
+            }
+        }
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (intent.getAction().equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
+                int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);
+                if (state == BluetoothAdapter.STATE_OFF) {
+                    mHandler.postDelayed(new Runnable() {
+                        @Override
+                        public void run() {
+                            mAdapter.enable();
+                        }
+                    }, BT_ON_DELAY);
+                } else if (state == BluetoothAdapter.STATE_ON) {
+                    mIsSwitching = false;
+                    unregisterReceiver(this);
+                    getPassButton().setEnabled(true);
+                    closeDialog();
+                }
+            }
+        }
+    }
+
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleConnectionPriorityClientBaseActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleConnectionPriorityClientBaseActivity.java
new file mode 100644
index 0000000..0aa4841
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleConnectionPriorityClientBaseActivity.java
@@ -0,0 +1,312 @@
+/*

+ * Copyright (C) 2016 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.AlertDialog;

+import android.app.Dialog;

+import android.app.ProgressDialog;

+import android.bluetooth.BluetoothAdapter;

+import android.bluetooth.BluetoothManager;

+import android.content.BroadcastReceiver;

+import android.content.Context;

+import android.content.DialogInterface;

+import android.content.Intent;

+import android.content.IntentFilter;

+import android.os.Bundle;

+import android.os.Handler;

+import android.widget.ListView;

+import android.widget.Toast;

+

+import com.android.cts.verifier.PassFailButtons;

+import com.android.cts.verifier.R;

+

+import java.util.ArrayList;

+import java.util.List;

+

+public class BleConnectionPriorityClientBaseActivity extends PassFailButtons.Activity {

+

+    private TestAdapter mTestAdapter;

+    private int mPassed = 0;

+    private Dialog mDialog;

+

+    private static final int BLE_CONNECTION_HIGH = 0;

+    private static final int BLE_CONNECTION_BALANCED = 1;

+    private static final int BLE_CONNECTION_LOW = 2;

+

+    private static final int PASSED_HIGH = 0x1;

+    private static final int PASSED_BALANCED = 0x2;

+    private static final int PASSED_LOW = 0x4;

+    private static final int ALL_PASSED = 0x7;

+

+    private boolean mSecure;

+

+    private Handler mHandler;

+    private int mCurrentTest = -1;

+

+    @Override

+    protected void onCreate(Bundle savedInstanceState) {

+        super.onCreate(savedInstanceState);

+        setContentView(R.layout.ble_connection_priority_client_test);

+        setPassFailButtonClickListeners();

+        setInfoResources(R.string.ble_connection_priority_client_name,

+                R.string.ble_connection_priority_client_info, -1);

+        getPassButton().setEnabled(false);

+

+        mHandler = new Handler();

+

+        mTestAdapter = new TestAdapter(this, setupTestList());

+        ListView listView = (ListView) findViewById(R.id.ble_client_connection_tests);

+        listView.setAdapter(mTestAdapter);

+        listView.setEnabled(false);

+        listView.setClickable(false);

+    }

+

+    @Override

+    public void onResume() {

+        super.onResume();

+

+        IntentFilter filter = new IntentFilter();

+        filter.addAction(BleConnectionPriorityClientService.ACTION_BLUETOOTH_DISABLED);

+        filter.addAction(BleConnectionPriorityClientService.ACTION_CONNECTION_SERVICES_DISCOVERED);

+        filter.addAction(BleConnectionPriorityClientService.ACTION_FINISH_CONNECTION_PRIORITY_HIGH);

+        filter.addAction(BleConnectionPriorityClientService.ACTION_FINISH_CONNECTION_PRIORITY_BALANCED);

+        filter.addAction(BleConnectionPriorityClientService.ACTION_FINISH_CONNECTION_PRIORITY_LOW_POWER);

+        filter.addAction(BleConnectionPriorityClientService.ACTION_BLUETOOTH_MISMATCH_SECURE);

+        filter.addAction(BleConnectionPriorityClientService.ACTION_BLUETOOTH_MISMATCH_INSECURE);

+        filter.addAction(BleConnectionPriorityClientService.ACTION_FINISH_DISCONNECT);

+        registerReceiver(mBroadcast, filter);

+    }

+

+    @Override

+    public void onPause() {

+        super.onPause();

+        unregisterReceiver(mBroadcast);

+        closeDialog();

+    }

+

+    protected void setSecure(boolean secure) {

+        mSecure = secure;

+    }

+

+    public boolean isSecure() {

+        return mSecure;

+    }

+

+    private synchronized void closeDialog() {

+        if (mDialog != null) {

+            mDialog.dismiss();

+            mDialog = null;

+        }

+    }

+

+    private synchronized void showProgressDialog() {

+        closeDialog();

+

+        ProgressDialog dialog = new ProgressDialog(this);

+        dialog.setTitle(R.string.ble_test_running);

+        dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);

+        dialog.setMessage(getString(R.string.ble_test_running_message));

+        dialog.setCanceledOnTouchOutside(false);

+        mDialog = dialog;

+        mDialog.show();

+    }

+

+    private void showErrorDialog(int titleId, int messageId, boolean finish) {

+        AlertDialog.Builder builder = new AlertDialog.Builder(this)

+                .setTitle(titleId)

+                .setMessage(messageId);

+        if (finish) {

+            builder.setOnCancelListener(new Dialog.OnCancelListener() {

+                @Override

+                public void onCancel(DialogInterface dialog) {

+                    finish();

+                }

+            });

+        }

+        builder.create().show();

+    }

+

+    private List<Integer> setupTestList() {

+        ArrayList<Integer> testList = new ArrayList<Integer>();

+        testList.add(R.string.ble_connection_priority_client_high);

+        testList.add(R.string.ble_connection_priority_client_balanced);

+        testList.add(R.string.ble_connection_priority_client_low);

+        return testList;

+    }

+

+    private void executeNextTest(long delay) {

+        mHandler.postDelayed(new Runnable() {

+            @Override

+            public void run() {

+                executeNextTestImpl();

+            }

+        }, delay);

+    }

+    private void executeNextTestImpl() {

+        switch (mCurrentTest) {

+            case -1: {

+                mCurrentTest = BLE_CONNECTION_HIGH;

+                Intent intent = new Intent(this, BleConnectionPriorityClientService.class);

+                intent.setAction(BleConnectionPriorityClientService.ACTION_CONNECTION_PRIORITY_HIGH);

+                startService(intent);

+                String msg = getString(R.string.ble_client_connection_priority)

+                        + getString(R.string.ble_connection_priority_high);

+                Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_LONG).show();

+            }

+                break;

+            case BLE_CONNECTION_BALANCED: {

+                mCurrentTest = BLE_CONNECTION_LOW;

+                Intent intent = new Intent(this, BleConnectionPriorityClientService.class);

+                intent.setAction(BleConnectionPriorityClientService.ACTION_CONNECTION_PRIORITY_LOW_POWER);

+                startService(intent);

+                String msg = getString(R.string.ble_client_connection_priority)

+                        + getString(R.string.ble_connection_priority_low);

+                Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_LONG).show();

+            }

+                break;

+            case BLE_CONNECTION_HIGH: {

+                mCurrentTest = BLE_CONNECTION_BALANCED;

+                Intent intent = new Intent(this, BleConnectionPriorityClientService.class);

+                intent.setAction(BleConnectionPriorityClientService.ACTION_CONNECTION_PRIORITY_BALANCED);

+                startService(intent);

+                String msg = getString(R.string.ble_client_connection_priority)

+                        + getString(R.string.ble_connection_priority_balanced);

+                Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_LONG).show();

+            }

+                break;

+            case BLE_CONNECTION_LOW:

+                // all test done

+                closeDialog();

+                if (mPassed == ALL_PASSED) {

+                    Intent intent = new Intent(this, BleConnectionPriorityClientService.class);

+                    intent.setAction(BleConnectionPriorityClientService.ACTION_DISCONNECT);

+                    startService(intent);

+                }

+                break;

+            default:

+                // something went wrong

+                closeDialog();

+                break;

+        }

+    }

+

+    public boolean shouldRebootBluetoothAfterTest() {

+        return false;

+    }

+

+    private BroadcastReceiver mBroadcast = new BroadcastReceiver() {

+        @Override

+        public void onReceive(Context context, Intent intent) {

+            String action = intent.getAction();

+            switch (action) {

+            case BleConnectionPriorityClientService.ACTION_BLUETOOTH_DISABLED:

+                new AlertDialog.Builder(context)

+                        .setTitle(R.string.ble_bluetooth_disable_title)

+                        .setMessage(R.string.ble_bluetooth_disable_message)

+                        .setOnCancelListener(new Dialog.OnCancelListener() {

+                            @Override

+                            public void onCancel(DialogInterface dialog) {

+                                finish();

+                            }

+                        })

+                        .create().show();

+                break;

+            case BleConnectionPriorityClientService.ACTION_CONNECTION_SERVICES_DISCOVERED:

+                showProgressDialog();

+                executeNextTest(3000);

+                break;

+            case BleConnectionPriorityClientService.ACTION_FINISH_CONNECTION_PRIORITY_HIGH:

+                mTestAdapter.setTestPass(BLE_CONNECTION_HIGH);

+                mPassed |= PASSED_HIGH;

+                executeNextTest(1000);

+                break;

+            case BleConnectionPriorityClientService.ACTION_FINISH_CONNECTION_PRIORITY_BALANCED:

+                mTestAdapter.setTestPass(BLE_CONNECTION_BALANCED);

+                mPassed |= PASSED_BALANCED;

+                executeNextTest(1000);

+                break;

+            case BleConnectionPriorityClientService.ACTION_FINISH_CONNECTION_PRIORITY_LOW_POWER:

+                mTestAdapter.setTestPass(BLE_CONNECTION_LOW);

+                mPassed |= PASSED_LOW;

+                executeNextTest(100);

+                break;

+            case BleConnectionPriorityClientService.ACTION_BLUETOOTH_MISMATCH_SECURE:

+                showErrorDialog(R.string.ble_bluetooth_mismatch_title, R.string.ble_bluetooth_mismatch_secure_message, true);

+                break;

+            case BleConnectionPriorityClientService.ACTION_BLUETOOTH_MISMATCH_INSECURE:

+                showErrorDialog(R.string.ble_bluetooth_mismatch_title, R.string.ble_bluetooth_mismatch_insecure_message, true);

+                break;

+            case BleConnectionPriorityClientService.ACTION_FINISH_DISCONNECT:

+                if (shouldRebootBluetoothAfterTest()) {

+                    mBtPowerSwitcher.executeSwitching();

+                } else {

+                    getPassButton().setEnabled(true);

+                }

+                break;

+            }

+            mTestAdapter.notifyDataSetChanged();

+        }

+    };

+

+    private static final long BT_ON_DELAY = 10000;

+    private final BluetoothPowerSwitcher mBtPowerSwitcher = new BluetoothPowerSwitcher();

+    private class BluetoothPowerSwitcher extends BroadcastReceiver {

+

+        private boolean mIsSwitching = false;

+        private BluetoothAdapter mAdapter;

+

+        public void executeSwitching() {

+            if (mAdapter == null) {

+                BluetoothManager btMgr = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);

+                mAdapter = btMgr.getAdapter();

+            }

+

+            if (!mIsSwitching) {

+                IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);

+                registerReceiver(this, filter);

+                mIsSwitching = true;

+                mHandler.postDelayed(new Runnable() {

+                    @Override

+                    public void run() {

+                        mAdapter.disable();

+                    }

+                }, 1000);

+                showProgressDialog();

+            }

+        }

+

+        @Override

+        public void onReceive(Context context, Intent intent) {

+            if (intent.getAction().equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {

+                int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);

+                if (state == BluetoothAdapter.STATE_OFF) {

+                    mHandler.postDelayed(new Runnable() {

+                        @Override

+                        public void run() {

+                            mAdapter.enable();

+                        }

+                    }, BT_ON_DELAY);

+                } else if (state == BluetoothAdapter.STATE_ON) {

+                    mIsSwitching = false;

+                    unregisterReceiver(this);

+                    getPassButton().setEnabled(true);

+                    closeDialog();

+                }

+            }

+        }

+    }

+}

diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleConnectionPriorityClientService.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleConnectionPriorityClientService.java
new file mode 100644
index 0000000..28fd023
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleConnectionPriorityClientService.java
@@ -0,0 +1,435 @@
+/*

+ * Copyright (C) 2016 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.BluetoothGattCallback;

+import android.bluetooth.BluetoothGattCharacteristic;

+import android.bluetooth.BluetoothGattService;

+import android.bluetooth.BluetoothManager;

+import android.bluetooth.BluetoothProfile;

+import android.bluetooth.le.BluetoothLeScanner;

+import android.bluetooth.le.ScanCallback;

+import android.bluetooth.le.ScanFilter;

+import android.bluetooth.le.ScanResult;

+import android.bluetooth.le.ScanSettings;

+import android.content.Context;

+import android.content.Intent;

+import android.os.DeadObjectException;

+import android.os.Handler;

+import android.os.IBinder;

+import android.os.ParcelUuid;

+import android.util.Log;

+import android.widget.Toast;

+

+import java.util.Arrays;

+import java.util.Date;

+import java.util.List;

+import java.util.Set;

+import java.util.Timer;

+import java.util.TimerTask;

+import java.util.UUID;

+

+public class BleConnectionPriorityClientService extends Service {

+    public static final boolean DEBUG = true;

+    public static final String TAG = "BlePriorityClient";

+

+    public static final String ACTION_BLUETOOTH_DISABLED =

+            "com.android.cts.verifier.bluetooth.action.BLUETOOTH_DISABLED";

+

+    public static final String ACTION_CONNECTION_SERVICES_DISCOVERED =

+            "com.android.cts.verifier.bluetooth.action.CONNECTION_SERVICES_DISCOVERED";

+

+    public static final String ACTION_BLUETOOTH_MISMATCH_SECURE =

+            "com.android.cts.verifier.bluetooth.action.ACTION_BLUETOOTH_MISMATCH_SECURE";

+    public static final String ACTION_BLUETOOTH_MISMATCH_INSECURE =

+            "com.android.cts.verifier.bluetooth.action.ACTION_BLUETOOTH_MISMATCH_INSECURE";

+

+    public static final String ACTION_CONNECTION_PRIORITY_BALANCED =

+            "com.android.cts.verifier.bluetooth.action.CONNECTION_PRIORITY_BALANCED";

+    public static final String ACTION_CONNECTION_PRIORITY_HIGH =

+            "com.android.cts.verifier.bluetooth.action.CONNECTION_PRIORITY_HIGH";

+    public static final String ACTION_CONNECTION_PRIORITY_LOW_POWER =

+            "com.android.cts.verifier.bluetooth.action.CONNECTION_PRIORITY_LOW_POWER";

+

+    public static final String ACTION_FINISH_CONNECTION_PRIORITY_BALANCED =

+            "com.android.cts.verifier.bluetooth.action.FINISH_CONNECTION_PRIORITY_BALANCED";

+    public static final String ACTION_FINISH_CONNECTION_PRIORITY_HIGH =

+            "com.android.cts.verifier.bluetooth.action.FINISH_CONNECTION_PRIORITY_HIGH";

+    public static final String ACTION_FINISH_CONNECTION_PRIORITY_LOW_POWER =

+            "com.android.cts.verifier.bluetooth.action.FINISH_CONNECTION_PRIORITY_LOW_POWER";

+

+    public static final String ACTION_CLIENT_CONNECT_SECURE =

+            "com.android.cts.verifier.bluetooth.action.CLIENT_CONNECT_SECURE";

+

+    public static final String ACTION_DISCONNECT =

+            "com.android.cts.verifier.bluetooth.action.DISCONNECT";

+    public static final String ACTION_FINISH_DISCONNECT =

+            "com.android.cts.verifier.bluetooth.action.FINISH_DISCONNECT";

+

+    public static final long DEFAULT_INTERVAL = 100L;

+    public static final long DEFAULT_PERIOD = 10000L;

+

+    // this string will be used at writing test and connection priority test.

+    private static final String WRITE_VALUE = "TEST";

+

+    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 START_CHARACTERISTIC_UUID =

+            UUID.fromString("00009997-0000-1000-8000-00805f9b34fb");

+    private static final UUID STOP_CHARACTERISTIC_UUID =

+            UUID.fromString("00009995-0000-1000-8000-00805f9b34fb");

+

+    private BluetoothManager mBluetoothManager;

+    private BluetoothAdapter mBluetoothAdapter;

+    private BluetoothGatt mBluetoothGatt;

+    private BluetoothLeScanner mScanner;

+    private Handler mHandler;

+    private Timer mConnectionTimer;

+    private Context mContext;

+

+    private String mAction;

+    private long mInterval;

+    private long mPeriod;

+    private Date mStartDate;

+    private int mWriteCount;

+    private boolean mSecure;

+

+    private String mPriority;

+

+    private TestTaskQueue mTaskQueue;

+

+    @Override

+    public void onCreate() {

+        super.onCreate();

+

+        mTaskQueue = new TestTaskQueue(getClass().getName() + "__taskHandlerThread");

+

+        mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);

+        mBluetoothAdapter = mBluetoothManager.getAdapter();

+        mScanner = mBluetoothAdapter.getBluetoothLeScanner();

+        mHandler = new Handler();

+        mContext = this;

+        mInterval = DEFAULT_INTERVAL;

+        mPeriod = DEFAULT_PERIOD;

+

+        startScan();

+    }

+

+    @Override

+    public void onDestroy() {

+        super.onDestroy();

+        if (mBluetoothGatt != null) {

+            try {

+                mBluetoothGatt.disconnect();

+                mBluetoothGatt.close();

+            } catch (Exception e) {}

+            finally {

+                mBluetoothGatt = null;

+            }

+        }

+        stopScan();

+

+        mTaskQueue.quit();

+    }

+

+    @Override

+    public IBinder onBind(Intent intent) {

+        return null;

+    }

+

+    private void notifyBluetoothDisabled() {

+        Intent intent = new Intent(ACTION_BLUETOOTH_DISABLED);

+        sendBroadcast(intent);

+    }

+

+    @Override

+    public int onStartCommand(Intent intent, int flags, int startId) {

+        if (intent != null) {

+            mAction = intent.getAction();

+            if (mAction != null) {

+                switch (mAction) {

+                case ACTION_CLIENT_CONNECT_SECURE:

+                    mSecure = true;

+                    break;

+                case ACTION_CONNECTION_PRIORITY_BALANCED:

+                case ACTION_CONNECTION_PRIORITY_HIGH:

+                case ACTION_CONNECTION_PRIORITY_LOW_POWER:

+                    mTaskQueue.addTask(new Runnable() {

+                        @Override

+                        public void run() {

+                            startPeriodicTransmission();

+                        }

+                    });

+                    break;

+                case ACTION_DISCONNECT:

+                    if (mBluetoothGatt != null) {

+                        mBluetoothGatt.disconnect();

+                    } else {

+                        notifyDisconnect();

+                    }

+                    break;

+                }

+            }

+        }

+        return START_NOT_STICKY;

+    }

+

+    private void startPeriodicTransmission() {

+        mWriteCount = 0;

+

+        // Set connection priority

+        switch (mAction) {

+        case ACTION_CONNECTION_PRIORITY_BALANCED:

+            mPriority = BleConnectionPriorityServerService.CONNECTION_PRIORITY_BALANCED;

+            mBluetoothGatt.requestConnectionPriority(BluetoothGatt.CONNECTION_PRIORITY_BALANCED);

+            break;

+        case ACTION_CONNECTION_PRIORITY_HIGH:

+            mPriority = BleConnectionPriorityServerService.CONNECTION_PRIORITY_HIGH;

+            mBluetoothGatt.requestConnectionPriority(BluetoothGatt.CONNECTION_PRIORITY_HIGH);

+            break;

+        case ACTION_CONNECTION_PRIORITY_LOW_POWER:

+            mPriority = BleConnectionPriorityServerService.CONNECTION_PRIORITY_LOW_POWER;

+            mBluetoothGatt.requestConnectionPriority(BluetoothGatt.CONNECTION_PRIORITY_LOW_POWER);

+            break;

+        default:

+            mPriority = BleConnectionPriorityServerService.CONNECTION_PRIORITY_BALANCED;

+            mBluetoothGatt.requestConnectionPriority(BluetoothGatt.CONNECTION_PRIORITY_BALANCED);

+            break;

+        }

+

+        // Create Timer for Periodic transmission

+        mStartDate = new Date();

+        TimerTask task = new TimerTask() {

+            @Override

+            public void run() {

+                if (mBluetoothGatt == null) {

+                    if (DEBUG) {

+                        Log.d(TAG, "BluetoothGatt is null, return");

+                    }

+                    return;

+                }

+

+                Date currentData = new Date();

+                if ((currentData.getTime() - mStartDate.getTime()) >= mPeriod) {

+                    if (mConnectionTimer != null) {

+                        mConnectionTimer.cancel();

+                        mConnectionTimer = null;

+                    }

+                    // write termination data (contains current priority and number of messages wrote)

+                    String msg = "" + mPriority + "," + mWriteCount;

+                    writeCharacteristic(STOP_CHARACTERISTIC_UUID, msg);

+                    sleep(1000);

+                    Intent intent = new Intent();

+                    switch (mPriority) {

+                    case BleConnectionPriorityServerService.CONNECTION_PRIORITY_BALANCED:

+                        intent.setAction(ACTION_FINISH_CONNECTION_PRIORITY_BALANCED);

+                        break;

+                    case BleConnectionPriorityServerService.CONNECTION_PRIORITY_HIGH:

+                        intent.setAction(ACTION_FINISH_CONNECTION_PRIORITY_HIGH);

+                        break;

+                    case BleConnectionPriorityServerService.CONNECTION_PRIORITY_LOW_POWER:

+                        intent.setAction(ACTION_FINISH_CONNECTION_PRIORITY_LOW_POWER);

+                        break;

+                    }

+                    sendBroadcast(intent);

+                }

+

+                if (mConnectionTimer != null) {

+                    // write testing data

+                    ++mWriteCount;

+                    writeCharacteristic(CHARACTERISTIC_UUID, WRITE_VALUE);

+                }

+            }

+        };

+

+        // write starting data

+        writeCharacteristic(START_CHARACTERISTIC_UUID, mPriority);

+

+        // start sending

+        sleep(1000);

+        mConnectionTimer = new Timer();

+        mConnectionTimer.schedule(task, 0, mInterval);

+    }

+

+    private BluetoothGattService getService() {

+        BluetoothGattService service = null;

+

+        if (mBluetoothGatt != null) {

+            service = mBluetoothGatt.getService(SERVICE_UUID);

+            if (service == null) {

+                showMessage("Service not found");

+            }

+        }

+        return service;

+    }

+

+    private BluetoothGattCharacteristic getCharacteristic(UUID uuid) {

+        BluetoothGattCharacteristic characteristic = null;

+

+        BluetoothGattService service = getService();

+        if (service != null) {

+            characteristic = service.getCharacteristic(uuid);

+            if (characteristic == null) {

+                showMessage("Characteristic not found");

+            }

+        }

+        return characteristic;

+    }

+

+    private void writeCharacteristic(UUID uid, String writeValue) {

+        BluetoothGattCharacteristic characteristic = getCharacteristic(uid);

+        if (characteristic != null){

+            characteristic.setValue(writeValue);

+            mBluetoothGatt.writeCharacteristic(characteristic);

+        }

+    }

+

+    private void sleep(int millis) {

+        try {

+            Thread.sleep(millis);

+        } catch (InterruptedException e) {

+            Log.e(TAG, "Error in thread sleep", e);

+        }

+    }

+

+    private void showMessage(final String msg) {

+        mHandler.post(new Runnable() {

+            public void run() {

+                Toast.makeText(BleConnectionPriorityClientService.this, msg, Toast.LENGTH_SHORT).show();

+            }

+        });

+    }

+

+    private final BluetoothGattCallback mGattCallbacks = new BluetoothGattCallback() {

+        @Override

+        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {

+            if (DEBUG) Log.d(TAG, "onConnectionStateChange");

+            if (status == BluetoothGatt.GATT_SUCCESS) {

+                if (newState == BluetoothProfile.STATE_CONNECTED) {

+                    int bond = gatt.getDevice().getBondState();

+                    boolean bonded = false;

+                    BluetoothDevice target = gatt.getDevice();

+                    Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();

+                    if (pairedDevices.size() > 0) {

+                        for (BluetoothDevice device : pairedDevices) {

+                            if (device.getAddress().equals(target.getAddress())) {

+                                bonded = true;

+                                break;

+                            }

+                        }

+                    }

+                    if (mSecure && ((bond == BluetoothDevice.BOND_NONE) || !bonded)) {

+                        // not pairing and execute Secure Test

+                        mBluetoothGatt.disconnect();

+                        notifyMismatchSecure();

+                    } else if (!mSecure && ((bond != BluetoothDevice.BOND_NONE) || bonded)) {

+                        // already pairing nad execute Insecure Test

+                        mBluetoothGatt.disconnect();

+                        notifyMismatchInsecure();

+                    } else {

+                        showMessage("Bluetooth LE connected");

+                        mBluetoothGatt.discoverServices();

+                    }

+                } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {

+                    showMessage("Bluetooth LE disconnected");

+

+                    notifyDisconnect();

+                }

+            } else {

+                showMessage("Failed to connect");

+                mBluetoothGatt.close();

+                mBluetoothGatt = null;

+            }

+        }

+

+        @Override

+        public void onServicesDiscovered(BluetoothGatt gatt, int status) {

+            if (DEBUG){

+                Log.d(TAG, "onServiceDiscovered");

+            }

+            if ((status == BluetoothGatt.GATT_SUCCESS) && (mBluetoothGatt.getService(SERVICE_UUID) != null)) {

+                showMessage("Service discovered");

+                Intent intent = new Intent(ACTION_CONNECTION_SERVICES_DISCOVERED);

+                sendBroadcast(intent);

+            }

+        }

+

+        @Override

+        public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {

+            String value = characteristic.getStringValue(0);

+            UUID uid = characteristic.getUuid();

+            if (DEBUG) {

+                Log.d(TAG, "onCharacteristicWrite: characteristic.val=" + value + " status=" + status + " uid=" + uid);

+            }

+        }

+    };

+

+    private final ScanCallback mScanCallback = new ScanCallback() {

+        @Override

+        public void onScanResult(int callbackType, ScanResult result) {

+            if (mBluetoothGatt == null) {

+                stopScan();

+                mBluetoothGatt = BleClientService.connectGatt(result.getDevice(), mContext, false, mSecure, mGattCallbacks);

+            }

+        }

+    };

+

+    private void startScan() {

+        if (DEBUG) {

+            Log.d(TAG, "startScan");

+        }

+        if (!mBluetoothAdapter.isEnabled()) {

+            notifyBluetoothDisabled();

+        } else {

+            List<ScanFilter> filter = Arrays.asList(new ScanFilter.Builder().setServiceUuid(

+                    new ParcelUuid(BleConnectionPriorityServerService.ADV_SERVICE_UUID)).build());

+            ScanSettings setting = new ScanSettings.Builder()

+                    .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build();

+            mScanner.startScan(filter, setting, mScanCallback);

+        }

+    }

+

+    private void stopScan() {

+        if (DEBUG) {

+            Log.d(TAG, "stopScan");

+        }

+        if (mScanner != null) {

+            mScanner.stopScan(mScanCallback);

+        }

+    }

+

+    private void notifyMismatchSecure() {

+        Intent intent = new Intent(ACTION_BLUETOOTH_MISMATCH_SECURE);

+        sendBroadcast(intent);

+    }

+

+    private void notifyMismatchInsecure() {

+        Intent intent = new Intent(ACTION_BLUETOOTH_MISMATCH_INSECURE);

+        sendBroadcast(intent);

+    }

+

+    private void notifyDisconnect() {

+        Intent intent = new Intent(ACTION_FINISH_DISCONNECT);

+        sendBroadcast(intent);

+    }

+}

diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleConnectionPriorityServerBaseActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleConnectionPriorityServerBaseActivity.java
new file mode 100644
index 0000000..c0a2f09
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleConnectionPriorityServerBaseActivity.java
@@ -0,0 +1,243 @@
+/*

+ * Copyright (C) 2016 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.AlertDialog;

+import android.app.Dialog;

+import android.app.ProgressDialog;

+import android.content.BroadcastReceiver;

+import android.content.Context;

+import android.content.DialogInterface;

+import android.content.Intent;

+import android.content.IntentFilter;

+import android.os.Bundle;

+import android.widget.ListView;

+import android.widget.Toast;

+

+import com.android.cts.verifier.PassFailButtons;

+import com.android.cts.verifier.R;

+

+import java.util.ArrayList;

+import java.util.List;

+

+public class BleConnectionPriorityServerBaseActivity extends PassFailButtons.Activity {

+

+    public static final int CONNECTION_PRIORITY_HIGH = 0;

+    public static final int CONNECTION_PRIORITY_BALANCED = 1;

+    public static final int CONNECTION_PRIORITY_LOW_POWER = 2;

+

+    private long mAverageBalanced = -1;

+    private long mAverageHigh = -1;

+    private long mAverageLow = -1;

+

+    private TestAdapter mTestAdapter;

+

+    private Dialog mDialog;

+

+    @Override

+    protected void onCreate(Bundle savedInstanceState) {

+        super.onCreate(savedInstanceState);

+        setContentView(R.layout.ble_connection_priority_server_test);

+        setPassFailButtonClickListeners();

+        setInfoResources(R.string.ble_connection_priority_server_name,

+                R.string.ble_connection_priority_server_info, -1);

+

+        getPassButton().setEnabled(false);

+

+        mTestAdapter = new TestAdapter(this, setupTestList());

+        ListView listView = (ListView) findViewById(R.id.ble_server_connection_tests);

+        listView.setAdapter(mTestAdapter);

+

+        startService(new Intent(this, BleConnectionPriorityServerService.class));

+    }

+

+    @Override

+    public void onResume() {

+        super.onResume();

+

+        IntentFilter filter = new IntentFilter();

+        filter.addAction(BleConnectionPriorityServerService.ACTION_BLUETOOTH_DISABLED);

+        filter.addAction(BleConnectionPriorityServerService.ACTION_CONNECTION_WRITE_REQUEST);

+        filter.addAction(BleConnectionPriorityServerService.ACTION_FINICH_CONNECTION_PRIORITY_HIGHT);

+        filter.addAction(BleConnectionPriorityServerService.ACTION_FINICH_CONNECTION_PRIORITY_BALANCED);

+        filter.addAction(BleConnectionPriorityServerService.ACTION_FINICH_CONNECTION_PRIORITY_LOW);

+        filter.addAction(BleServerService.BLE_ADVERTISE_UNSUPPORTED);

+        filter.addAction(BleServerService.BLE_OPEN_FAIL);

+        filter.addAction(BleConnectionPriorityServerService.ACTION_START_CONNECTION_PRIORITY_TEST);

+        registerReceiver(mBroadcast, filter);

+    }

+

+    @Override

+    public void onPause() {

+        super.onPause();

+        unregisterReceiver(mBroadcast);

+        closeDialog();

+    }

+

+    private List<Integer> setupTestList() {

+        ArrayList<Integer> testList = new ArrayList<Integer>();

+        testList.add(R.string.ble_connection_priority_client_high);

+        testList.add(R.string.ble_connection_priority_client_balanced);

+        testList.add(R.string.ble_connection_priority_client_low);

+        return testList;

+    }

+

+    @Override

+    public void onDestroy() {

+        super.onDestroy();

+        stopService(new Intent(this, BleConnectionPriorityServerService.class));

+    }

+

+    private void closeDialog() {

+        if (mDialog != null) {

+            mDialog.dismiss();

+            mDialog = null;

+        }

+    }

+

+    private void showErrorDialog(int titleId, int messageId, boolean finish) {

+        closeDialog();

+

+        AlertDialog.Builder builder = new AlertDialog.Builder(this)

+                .setTitle(titleId)

+                .setMessage(messageId);

+        if (finish) {

+            builder.setOnCancelListener(new Dialog.OnCancelListener() {

+                @Override

+                public void onCancel(DialogInterface dialog) {

+                    finish();

+                }

+            });

+        }

+        mDialog = builder.create();

+        mDialog.show();

+    }

+

+    private BroadcastReceiver mBroadcast = new BroadcastReceiver() {

+        @Override

+        public void onReceive(Context context, Intent intent) {

+            String action = intent.getAction();

+            long average = intent.getLongExtra(BleConnectionPriorityServerService.EXTRA_AVERAGE, -1);

+            switch (action) {

+            case BleConnectionPriorityServerService.ACTION_BLUETOOTH_DISABLED:

+                new AlertDialog.Builder(context)

+                        .setTitle(R.string.ble_bluetooth_disable_title)

+                        .setMessage(R.string.ble_bluetooth_disable_message)

+                        .setOnCancelListener(new Dialog.OnCancelListener() {

+                            @Override

+                            public void onCancel(DialogInterface dialog) {

+                                finish();

+                            }

+                        })

+                        .create().show();

+                break;

+            case BleConnectionPriorityServerService.ACTION_START_CONNECTION_PRIORITY_TEST:

+                showProgressDialog();

+                break;

+            case BleConnectionPriorityServerService.ACTION_FINICH_CONNECTION_PRIORITY_HIGHT:

+                mAverageHigh = average;

+                mAverageBalanced = -1;

+                mAverageLow = -1;

+                break;

+            case BleConnectionPriorityServerService.ACTION_FINICH_CONNECTION_PRIORITY_BALANCED:

+                mAverageBalanced = average;

+                break;

+            case BleConnectionPriorityServerService.ACTION_FINICH_CONNECTION_PRIORITY_LOW:

+                mAverageLow = average;

+                break;

+            case BleServerService.BLE_OPEN_FAIL:

+                setTestResultAndFinish(false);

+                runOnUiThread(new Runnable() {

+                    @Override

+                    public void run() {

+                        Toast.makeText(BleConnectionPriorityServerBaseActivity.this, R.string.bt_open_failed_message, Toast.LENGTH_SHORT).show();

+                    }

+                });

+                break;

+            case BleServerService.BLE_ADVERTISE_UNSUPPORTED:

+                showErrorDialog(R.string.bt_advertise_unsupported_title, R.string.bt_advertise_unsupported_message, true);

+                break;

+            }

+

+            boolean passedHigh = (mAverageHigh >= 0);

+            boolean passedAll = false;

+

+            if (passedHigh) {

+                mTestAdapter.setTestPass(CONNECTION_PRIORITY_HIGH);

+            }

+

+            if (passedHigh && (mAverageLow >= 0) && (mAverageBalanced >= 0)) {

+                boolean passedBalanced = (mAverageHigh <= mAverageBalanced);

+                boolean passedLow = (mAverageBalanced <= mAverageLow);

+

+                if (passedBalanced) {

+                    mTestAdapter.setTestPass(CONNECTION_PRIORITY_BALANCED);

+                }

+                if (passedLow) {

+                    mTestAdapter.setTestPass(CONNECTION_PRIORITY_LOW_POWER);

+                }

+

+                String resultMsg;

+                if (passedBalanced && passedLow) {

+                    resultMsg = getString(R.string.ble_server_connection_priority_result_passed);

+                    passedAll = true;

+                } else {

+                    String detailsMsg = String.format(getString(R.string.ble_server_connection_priority_result_intervals),

+                            mAverageHigh,

+                            mAverageBalanced,

+                            mAverageLow);

+                    resultMsg = getString(R.string.ble_server_connection_priority_result_failed)

+                            + "\n\n"

+                            + detailsMsg;

+                }

+

+                closeDialog();

+                mDialog = new AlertDialog.Builder(BleConnectionPriorityServerBaseActivity.this)

+                        .setMessage(resultMsg)

+                        .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {

+                            @Override

+                            public void onClick(DialogInterface dialog, int which) {

+                                closeDialog();

+                            }

+                        })

+                        .setOnCancelListener(new DialogInterface.OnCancelListener() {

+                            @Override

+                            public void onCancel(DialogInterface dialog) {

+                                closeDialog();

+                            }

+                        })

+                        .create();

+                mDialog.show();

+            }

+

+            getPassButton().setEnabled(passedAll);

+            mTestAdapter.notifyDataSetChanged();

+        }

+    };

+

+    private synchronized void showProgressDialog() {

+        closeDialog();

+

+        ProgressDialog dialog = new ProgressDialog(this);

+        dialog.setTitle(R.string.ble_test_running);

+        dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);

+        dialog.setMessage(getString(R.string.ble_test_running_message));

+        dialog.setCanceledOnTouchOutside(false);

+        mDialog = dialog;

+        mDialog.show();

+    }

+}

diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleConnectionPriorityServerService.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleConnectionPriorityServerService.java
new file mode 100644
index 0000000..e1e4eed
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleConnectionPriorityServerService.java
@@ -0,0 +1,418 @@
+/*

+ * Copyright (C) 2016 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.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.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.Handler;

+import android.os.IBinder;

+import android.os.ParcelUuid;

+import android.util.Log;

+import android.widget.Toast;

+

+import java.util.Timer;

+import java.util.TimerTask;

+import java.util.UUID;

+

+public class BleConnectionPriorityServerService extends Service {

+    public static final boolean DEBUG = true;

+    public static final String TAG = "BlePriorityServer";

+    private static final String RESET_COUNT_VALUE = "RESET";

+    private static final String START_VALUE = "START";

+    private static final String STOP_VALUE = "STOP";

+    public static final String CONNECTION_PRIORITY_HIGH = "PR_H";

+    public static final String CONNECTION_PRIORITY_BALANCED = "PR_B";

+    public static final String CONNECTION_PRIORITY_LOW_POWER = "PR_L";

+

+    public static final String ACTION_BLUETOOTH_DISABLED =

+            "com.android.cts.verifier.bluetooth.action.BLUETOOTH_DISABLED";

+

+    public static final String ACTION_CONNECTION_WRITE_REQUEST =

+            "com.android.cts.verifier.bluetooth.action.CONNECTION_WRITE_REQUEST";

+    public static final String EXTRA_REQUEST_COUNT =

+            "com.android.cts.verifier.bluetooth.intent.EXTRA_REQUEST_COUNT";

+    public static final String ACTION_FINICH_CONNECTION_PRIORITY_HIGHT =

+            "com.android.cts.verifier.bluetooth.action.ACTION_FINICH_CONNECTION_PRIORITY_HIGHT";

+    public static final String ACTION_FINICH_CONNECTION_PRIORITY_BALANCED =

+            "com.android.cts.verifier.bluetooth.action.ACTION_FINICH_CONNECTION_PRIORITY_BALANCED";

+    public static final String ACTION_FINICH_CONNECTION_PRIORITY_LOW =

+            "com.android.cts.verifier.bluetooth.action.ACTION_FINICH_CONNECTION_PRIORITY_LOW";

+

+    public static final String ACTION_START_CONNECTION_PRIORITY_TEST =

+            "com.android.cts.verifier.bluetooth.action.ACTION_START_CONNECTION_PRIORITY_TEST";

+

+    public static final String EXTRA_AVERAGE =

+            "com.android.cts.verifier.bluetooth.intent.EXTRA_AVERAGE";

+

+    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 START_CHARACTERISTIC_UUID =

+            UUID.fromString("00009997-0000-1000-8000-00805f9b34fb");

+    private static final UUID STOP_CHARACTERISTIC_UUID =

+            UUID.fromString("00009995-0000-1000-8000-00805f9b34fb");

+    private static final UUID DESCRIPTOR_UUID =

+            UUID.fromString("00009996-0000-1000-8000-00805f9b34fb");

+    public static final UUID ADV_SERVICE_UUID=

+            UUID.fromString("00002222-0000-1000-8000-00805f9b34fb");

+

+    private BluetoothManager mBluetoothManager;

+    private BluetoothGattServer mGattServer;

+    private BluetoothGattService mService;

+    private BluetoothDevice mDevice;

+    private Handler mHandler;

+    private BluetoothLeAdvertiser mAdvertiser;

+    private long mReceiveWriteCount;

+    private Timer mTimeoutTimer;

+    private TimerTask mTimeoutTimerTask;

+

+    @Override

+    public void onCreate() {

+        super.onCreate();

+

+        mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);

+        mAdvertiser = mBluetoothManager.getAdapter().getBluetoothLeAdvertiser();

+        mGattServer = mBluetoothManager.openGattServer(this, mCallbacks);

+        mService = createService();

+        if ((mGattServer != null) && (mAdvertiser != null)) {

+            mGattServer.addService(mService);

+        }

+        mDevice = null;

+        mHandler = new Handler();

+

+        if (!mBluetoothManager.getAdapter().isEnabled()) {

+            notifyBluetoothDisabled();

+        } else if (mGattServer == null) {

+            notifyOpenFail();

+        } else if (mAdvertiser == null) {

+            notifyAdvertiseUnsupported();

+        } else {

+            startAdvertise();

+        }

+    }

+

+    @Override

+    public void onDestroy() {

+        super.onDestroy();

+

+        cancelTimeoutTimer(false);

+

+        if (mTimeoutTimer != null) {

+            mTimeoutTimer.cancel();

+            mTimeoutTimer = null;

+        }

+        mTimeoutTimerTask = null;

+

+        stopAdvertise();

+        if (mGattServer == null) {

+            return;

+        }

+        if (mDevice != null) {

+            mGattServer.cancelConnection(mDevice);

+        }

+        mGattServer.clearServices();

+        mGattServer.close();

+    }

+

+    @Override

+    public IBinder onBind(Intent intent) {

+        return null;

+    }

+

+    @Override

+    public int onStartCommand(Intent intent, int flags, int startId) {

+        return START_NOT_STICKY;

+    }

+

+    private void notifyBluetoothDisabled() {

+        if (DEBUG) {

+            Log.d(TAG, "notifyBluetoothDisabled");

+        }

+        Intent intent = new Intent(ACTION_BLUETOOTH_DISABLED);

+        sendBroadcast(intent);

+    }

+

+    private void notifyTestStart() {

+        Intent intent = new Intent(BleConnectionPriorityServerService.ACTION_START_CONNECTION_PRIORITY_TEST);

+        sendBroadcast(intent);

+    }

+

+    private void notifyOpenFail() {

+        if (DEBUG) {

+            Log.d(TAG, "notifyOpenFail");

+        }

+        Intent intent = new Intent(BleServerService.BLE_OPEN_FAIL);

+        sendBroadcast(intent);

+    }

+

+    private void notifyAdvertiseUnsupported() {

+        if (DEBUG) {

+            Log.d(TAG, "notifyAdvertiseUnsupported");

+        }

+        Intent intent = new Intent(BleServerService.BLE_ADVERTISE_UNSUPPORTED);

+        sendBroadcast(intent);

+    }

+

+    private void notifyConnected() {

+        if (DEBUG) {

+            Log.d(TAG, "notifyConnected");

+        }

+    }

+

+    private void notifyDisconnected() {

+        if (DEBUG) {

+            Log.d(TAG, "notifyDisconnected");

+        }

+    }

+

+    private void notifyServiceAdded() {

+        if (DEBUG) {

+            Log.d(TAG, "notifyServiceAdded");

+        }

+    }

+

+    private void notifyCharacteristicWriteRequest() {

+        if (DEBUG) {

+            Log.d(TAG, "notifyCharacteristicWriteRequest");

+        }

+        Intent intent = new Intent(ACTION_CONNECTION_WRITE_REQUEST);

+        intent.putExtra(EXTRA_REQUEST_COUNT, String.valueOf(mReceiveWriteCount));

+        sendBroadcast(intent);

+    }

+

+    private void showMessage(final String msg) {

+        mHandler.post(new Runnable() {

+            @Override

+            public void run() {

+                Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT).show();

+            }

+        });

+    }

+

+    private synchronized void cancelTimeoutTimer(boolean runTimeout) {

+        if (mTimeoutTimerTask != null) {

+            mTimeoutTimer.cancel();

+            if (runTimeout) {

+                mTimeoutTimerTask.run();

+            }

+            mTimeoutTimerTask = null;

+            mTimeoutTimer = null;

+        }

+    }

+

+    private BluetoothGattService createService() {

+        BluetoothGattService service =

+                new BluetoothGattService(SERVICE_UUID, BluetoothGattService.SERVICE_TYPE_PRIMARY);

+        // add characteristic to service

+        //   property: 0x0A (read, write)

+        //   permission: 0x11 (read, write)

+        BluetoothGattCharacteristic characteristic =

+                new BluetoothGattCharacteristic(CHARACTERISTIC_UUID, 0x0A, 0x11);

+        BluetoothGattDescriptor descriptor = new BluetoothGattDescriptor(DESCRIPTOR_UUID, 0x11);

+        characteristic.addDescriptor(descriptor);

+        service.addCharacteristic(characteristic);

+        characteristic = new BluetoothGattCharacteristic(START_CHARACTERISTIC_UUID, 0x0A, 0x11);

+        characteristic.addDescriptor(descriptor);

+        service.addCharacteristic(characteristic);

+        characteristic = new BluetoothGattCharacteristic(STOP_CHARACTERISTIC_UUID, 0x0A, 0x11);

+        characteristic.addDescriptor(descriptor);

+        service.addCharacteristic(characteristic);

+

+        return service;

+    }

+

+    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;

+                    notifyConnected();

+                } else if (status == BluetoothProfile.STATE_DISCONNECTED) {

+                    cancelTimeoutTimer(true);

+                    notifyDisconnected();

+                    mDevice = null;

+                }

+            }

+        }

+

+        @Override

+        public void onServiceAdded(int status, BluetoothGattService service) {

+            if (DEBUG) {

+                Log.d(TAG, "onServiceAdded()");

+            }

+            if (status == BluetoothGatt.GATT_SUCCESS) {

+                notifyServiceAdded();

+            }

+        }

+

+        String mPriority = null;

+

+        @Override

+        public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId,

+                                                 BluetoothGattCharacteristic characteristic,

+                                                 boolean preparedWrite, boolean responseNeeded,

+                                                 int offset, byte[] value) {

+            if (mGattServer == null) {

+                if (DEBUG) {

+                    Log.d(TAG, "GattServer is null, return");

+                }

+                return;

+            }

+            if (DEBUG) {

+                Log.d(TAG, "onCharacteristicWriteRequest: preparedWrite=" + preparedWrite);

+            }

+

+            if (characteristic.getUuid().equals(START_CHARACTERISTIC_UUID)) {

+                // time out if previous measurement is running

+                cancelTimeoutTimer(true);

+

+                mPriority = new String(value);

+                Log.d(TAG, "Start Count Up. Priority is " + mPriority);

+                if (BleConnectionPriorityServerService.CONNECTION_PRIORITY_HIGH.equals(mPriority)) {

+                    notifyTestStart();

+                }

+

+                // start timeout timer

+                mTimeoutTimer = new Timer(getClass().getName() + "_TimeoutTimer");

+                mTimeoutTimerTask = new TimerTask() {

+                    @Override

+                    public void run() {

+                        // measurement timed out

+                        mTimeoutTimerTask = null;

+                        mTimeoutTimer = null;

+                        mReceiveWriteCount = 0;

+                        notifyMeasurementFinished(mPriority, Long.MAX_VALUE);

+                    }

+                };

+                mTimeoutTimer.schedule(mTimeoutTimerTask, (BleConnectionPriorityClientService.DEFAULT_PERIOD * 2));

+

+                mReceiveWriteCount = 0;

+            } else if (characteristic.getUuid().equals(STOP_CHARACTERISTIC_UUID)) {

+                boolean isRunning = (mTimeoutTimerTask != null);

+                cancelTimeoutTimer(false);

+

+                String valeStr = new String(value);

+                String priority = null;

+                int writeCount = -1;

+                int sep = valeStr.indexOf(",");

+                if (sep > 0) {

+                    priority = valeStr.substring(0, sep);

+                    writeCount = Integer.valueOf(valeStr.substring(sep + 1));

+                }

+

+                if ((mPriority != null) && isRunning) {

+                    if (mPriority.equals(priority)) {

+                        long averageTime = BleConnectionPriorityClientService.DEFAULT_PERIOD / mReceiveWriteCount;

+                        notifyMeasurementFinished(mPriority, averageTime);

+                        Log.d(TAG, "Received " + mReceiveWriteCount + " of " + writeCount + " messages");

+                    } else {

+                        Log.d(TAG, "Connection priority does not match");

+                        showMessage("Connection priority does not match");

+                    }

+                } else {

+                    Log.d(TAG, "Not Start Count UP.");

+                }

+                mReceiveWriteCount = 0;

+            } else {

+                if (mTimeoutTimerTask != null) {

+                    ++mReceiveWriteCount;

+                }

+                if (!preparedWrite) {

+                    characteristic.setValue(value);

+                }

+            }

+

+            if (responseNeeded) {

+                mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, 0, null);

+            }

+        }

+    };

+

+    private void notifyMeasurementFinished(String priority, long averageTime) {

+        Intent intent = new Intent();

+        intent.putExtra(EXTRA_AVERAGE, averageTime);

+        switch (priority) {

+            case CONNECTION_PRIORITY_HIGH:

+                intent.setAction(ACTION_FINICH_CONNECTION_PRIORITY_HIGHT);

+                break;

+            case CONNECTION_PRIORITY_BALANCED:

+                intent.setAction(ACTION_FINICH_CONNECTION_PRIORITY_BALANCED);

+                break;

+            case CONNECTION_PRIORITY_LOW_POWER:

+                intent.setAction(ACTION_FINICH_CONNECTION_PRIORITY_LOW);

+                break;

+        }

+        sendBroadcast(intent);

+    }

+

+    private final AdvertiseCallback mAdvertiseCallback = new AdvertiseCallback() {

+        @Override

+        public void onStartFailure(int errorCode) {

+            super.onStartFailure(errorCode);

+            if (errorCode == ADVERTISE_FAILED_FEATURE_UNSUPPORTED) {

+                notifyAdvertiseUnsupported();

+            } else {

+                notifyOpenFail();

+            }

+        }

+    };

+

+    private void startAdvertise() {

+        if (DEBUG) {

+            Log.d(TAG, "startAdvertise");

+        }

+        AdvertiseData data = new AdvertiseData.Builder()

+                .addServiceData(new ParcelUuid(ADV_SERVICE_UUID), new byte[]{1, 2, 3})

+                .addServiceUuid(new ParcelUuid(ADV_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);

+        }

+    }

+

+}

diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleEncryptedClientBaseActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleEncryptedClientBaseActivity.java
new file mode 100644
index 0000000..3d2b840
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleEncryptedClientBaseActivity.java
@@ -0,0 +1,301 @@
+/*

+ * Copyright (C) 2016 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.AlertDialog;

+import android.app.Dialog;

+import android.app.ProgressDialog;

+import android.bluetooth.BluetoothAdapter;

+import android.bluetooth.BluetoothManager;

+import android.content.BroadcastReceiver;

+import android.content.Context;

+import android.content.DialogInterface;

+import android.content.Intent;

+import android.content.IntentFilter;

+import android.os.Bundle;

+import android.os.Handler;

+import android.util.Log;

+import android.view.View;

+import android.widget.AdapterView;

+import android.widget.ListView;

+

+import com.android.cts.verifier.PassFailButtons;

+import com.android.cts.verifier.R;

+

+import java.util.ArrayList;

+import java.util.List;

+

+public class BleEncryptedClientBaseActivity extends PassFailButtons.Activity {

+

+    private TestAdapter mTestAdapter;

+    private int mAllPassed;

+    private Dialog mDialog;

+    private Handler mHandler;

+

+    private final int BLE_READ_ENCRIPTED_CHARACTERISTIC = 0;

+    private final int BLE_WRITE_ENCRIPTED_CHARACTERISTIC = 1;

+    private final int BLE_READ_ENCRIPTED_DESCRIPTOR = 2;

+    private final int BLE_WRITE_ENCRIPTED_DESCRIPTOR = 3;

+

+    @Override

+    protected void onCreate(Bundle savedInstanceState) {

+        super.onCreate(savedInstanceState);

+        setContentView(R.layout.ble_encrypted_client_test);

+        setPassFailButtonClickListeners();

+        setInfoResources(R.string.ble_encrypted_client_name,

+                R.string.ble_encrypted_client_info, -1);

+        getPassButton().setEnabled(false);

+

+        mHandler = new Handler();

+

+        mTestAdapter = new TestAdapter(this, setupTestList());

+        ListView listView = (ListView) findViewById(R.id.ble_client_enctypted_tests);

+        listView.setAdapter(mTestAdapter);

+        listView.setOnItemClickListener(new ListView.OnItemClickListener() {

+            @Override

+            public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {

+                Intent intent = new Intent(BleEncryptedClientBaseActivity.this, BleEncryptedClientService.class);

+                Log.v(getLocalClassName(), "onItemClick()");

+                switch (position) {

+                case BLE_WRITE_ENCRIPTED_CHARACTERISTIC:

+                    intent.setAction(BleEncryptedClientService.ACTION_WRITE_ENCRYPTED_CHARACTERISTIC);

+                    break;

+                case BLE_READ_ENCRIPTED_CHARACTERISTIC:

+                    intent.setAction(BleEncryptedClientService.ACTION_READ_ENCRYPTED_CHARACTERISTIC);

+                    break;

+                case BLE_WRITE_ENCRIPTED_DESCRIPTOR:

+                    intent.setAction(BleEncryptedClientService.ACTION_WRITE_ENCRYPTED_DESCRIPTOR);

+                    break;

+                case BLE_READ_ENCRIPTED_DESCRIPTOR:

+                    intent.setAction(BleEncryptedClientService.ACTION_READ_ENCRYPTED_DESCRIPTOR);

+                    break;

+                default:

+                    return;

+                }

+                startService(intent);

+                showProgressDialog();

+            }

+        });

+

+        mAllPassed = 0;

+    }

+

+    @Override

+    public void onResume() {

+        super.onResume();

+

+        IntentFilter filter = new IntentFilter();

+        filter.addAction(BleEncryptedClientService.INTENT_BLE_BLUETOOTH_DISABLED);

+        filter.addAction(BleEncryptedClientService.INTENT_BLE_WRITE_ENCRYPTED_CHARACTERISTIC);

+        filter.addAction(BleEncryptedClientService.INTENT_BLE_READ_ENCRYPTED_CHARACTERISTIC);

+        filter.addAction(BleEncryptedClientService.INTENT_BLE_WRITE_ENCRYPTED_DESCRIPTOR);

+        filter.addAction(BleEncryptedClientService.INTENT_BLE_READ_ENCRYPTED_DESCRIPTOR);

+        filter.addAction(BleEncryptedClientService.INTENT_BLE_WRITE_NOT_ENCRYPTED_CHARACTERISTIC);

+        filter.addAction(BleEncryptedClientService.INTENT_BLE_READ_NOT_ENCRYPTED_CHARACTERISTIC);

+        filter.addAction(BleEncryptedClientService.INTENT_BLE_WRITE_NOT_ENCRYPTED_DESCRIPTOR);

+        filter.addAction(BleEncryptedClientService.INTENT_BLE_READ_NOT_ENCRYPTED_DESCRIPTOR);

+        filter.addAction(BleEncryptedClientService.INTENT_BLE_WRITE_FAIL_ENCRYPTED_CHARACTERISTIC);

+        filter.addAction(BleEncryptedClientService.INTENT_BLE_READ_FAIL_ENCRYPTED_CHARACTERISTIC);

+        filter.addAction(BleEncryptedClientService.INTENT_BLE_WRITE_FAIL_ENCRYPTED_DESCRIPTOR);

+        filter.addAction(BleEncryptedClientService.INTENT_BLE_READ_FAIL_ENCRYPTED_DESCRIPTOR);

+        filter.addAction(BleEncryptedClientService.ACTION_DISCONNECTED);

+        registerReceiver(mBroadcast, filter);

+    }

+

+    @Override

+    public void onPause() {

+        super.onPause();

+        unregisterReceiver(mBroadcast);

+        closeDialog();

+    }

+

+    private List<Integer> setupTestList() {

+        ArrayList<Integer> testList = new ArrayList<Integer>();

+        testList.add(R.string.ble_read_authenticated_characteristic_name);

+        testList.add(R.string.ble_write_authenticated_characteristic_name);

+        testList.add(R.string.ble_read_authenticated_descriptor_name);

+        testList.add(R.string.ble_write_authenticated_descriptor_name);

+        return testList;

+    }

+

+    private void showErrorDialog(String title, String message, boolean finish) {

+        closeDialog();

+

+        AlertDialog.Builder builder = new AlertDialog.Builder(this)

+                .setTitle(title)

+                .setMessage(message);

+        if (finish) {

+            builder.setOnCancelListener(new Dialog.OnCancelListener() {

+                @Override

+                public void onCancel(DialogInterface dialog) {

+                    finish();

+                }

+            });

+        }

+        builder.create().show();

+    }

+

+    private synchronized void closeDialog() {

+        if (mDialog != null) {

+            mDialog.dismiss();

+            mDialog = null;

+        }

+    }

+

+    private synchronized void showProgressDialog() {

+        closeDialog();

+

+        ProgressDialog dialog = new ProgressDialog(this);

+        dialog.setTitle(R.string.ble_test_running);

+        dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);

+        dialog.setMessage(getString(R.string.ble_test_running_message));

+        dialog.setCanceledOnTouchOutside(false);

+        mDialog = dialog;

+        mDialog.show();

+    }

+

+    public boolean shouldRebootBluetoothAfterTest() {

+        return false;

+    }

+

+    public boolean isSecure() { return false; }

+

+    private BroadcastReceiver mBroadcast = new BroadcastReceiver() {

+        @Override

+        public void onReceive(Context context, Intent intent) {

+            String action = intent.getAction();

+            switch (action) {

+            case BleEncryptedClientService.INTENT_BLE_BLUETOOTH_DISABLED:

+                showErrorDialog(getString(R.string.ble_bluetooth_disable_title), getString(R.string.ble_bluetooth_disable_message), true);

+                break;

+            case BleEncryptedClientService.INTENT_BLE_WRITE_ENCRYPTED_CHARACTERISTIC:

+                mTestAdapter.setTestPass(BLE_WRITE_ENCRIPTED_CHARACTERISTIC);

+                mAllPassed |= 0x01;

+                if (!isSecure()) {

+                    closeDialog();

+                }

+                break;

+            case BleEncryptedClientService.INTENT_BLE_READ_ENCRYPTED_CHARACTERISTIC:

+                mTestAdapter.setTestPass(BLE_READ_ENCRIPTED_CHARACTERISTIC);

+                mAllPassed |= 0x02;

+                if (!isSecure()) {

+                    closeDialog();

+                }

+                break;

+            case BleEncryptedClientService.INTENT_BLE_WRITE_ENCRYPTED_DESCRIPTOR:

+                mTestAdapter.setTestPass(BLE_WRITE_ENCRIPTED_DESCRIPTOR);

+                mAllPassed |= 0x04;

+                if (!isSecure()) {

+                    closeDialog();

+                }

+                break;

+            case BleEncryptedClientService.INTENT_BLE_READ_ENCRYPTED_DESCRIPTOR:

+                mTestAdapter.setTestPass(BLE_READ_ENCRIPTED_DESCRIPTOR);

+                mAllPassed |= 0x08;

+                if (!isSecure()) {

+                    closeDialog();

+                }

+                break;

+            case BleEncryptedClientService.INTENT_BLE_WRITE_NOT_ENCRYPTED_CHARACTERISTIC:

+                showErrorDialog(getString(R.string.ble_encrypted_client_name), getString(R.string.ble_encrypted_client_no_encrypted_characteristic), false);

+                break;

+            case BleEncryptedClientService.INTENT_BLE_READ_NOT_ENCRYPTED_CHARACTERISTIC:

+                showErrorDialog(getString(R.string.ble_encrypted_client_name), getString(R.string.ble_encrypted_client_no_encrypted_characteristic), false);

+                break;

+            case BleEncryptedClientService.INTENT_BLE_WRITE_NOT_ENCRYPTED_DESCRIPTOR:

+                showErrorDialog(getString(R.string.ble_encrypted_client_name), getString(R.string.ble_encrypted_client_no_encrypted_descriptor), false);

+                break;

+            case BleEncryptedClientService.INTENT_BLE_READ_NOT_ENCRYPTED_DESCRIPTOR:

+                showErrorDialog(getString(R.string.ble_encrypted_client_name), getString(R.string.ble_encrypted_client_no_encrypted_descriptor), false);

+                break;

+

+            case BleEncryptedClientService.INTENT_BLE_WRITE_FAIL_ENCRYPTED_CHARACTERISTIC:

+                showErrorDialog(getString(R.string.ble_encrypted_client_name), getString(R.string.ble_encrypted_client_fail_write_encrypted_characteristic), false);

+                break;

+            case BleEncryptedClientService.INTENT_BLE_READ_FAIL_ENCRYPTED_CHARACTERISTIC:

+                showErrorDialog(getString(R.string.ble_encrypted_client_name), getString(R.string.ble_encrypted_client_fail_read_encrypted_characteristic), false);

+                break;

+            case BleEncryptedClientService.INTENT_BLE_WRITE_FAIL_ENCRYPTED_DESCRIPTOR:

+                showErrorDialog(getString(R.string.ble_encrypted_client_name), getString(R.string.ble_encrypted_client_fail_write_encrypted_descriptor), false);

+                break;

+            case BleEncryptedClientService.INTENT_BLE_READ_FAIL_ENCRYPTED_DESCRIPTOR:

+                showErrorDialog(getString(R.string.ble_encrypted_client_name), getString(R.string.ble_encrypted_client_fail_read_encrypted_descriptor), false);

+                break;

+

+            case BleEncryptedClientService.ACTION_DISCONNECTED:

+                if (shouldRebootBluetoothAfterTest()) {

+                    mBtPowerSwitcher.executeSwitching();

+                } else {

+                    closeDialog();

+                }

+                break;

+            }

+

+            mTestAdapter.notifyDataSetChanged();

+            if (mAllPassed == 0x0F) {

+                getPassButton().setEnabled(true);

+            }

+        }

+    };

+

+    private static final long BT_ON_DELAY = 10000;

+    private final BluetoothPowerSwitcher mBtPowerSwitcher = new BluetoothPowerSwitcher();

+    private class BluetoothPowerSwitcher extends BroadcastReceiver {

+

+        private boolean mIsSwitching = false;

+        private BluetoothAdapter mAdapter;

+

+        public void executeSwitching() {

+            if (mAdapter == null) {

+                BluetoothManager btMgr = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);

+                mAdapter = btMgr.getAdapter();

+            }

+

+            if (!mIsSwitching) {

+                IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);

+                registerReceiver(this, filter);

+                mIsSwitching = true;

+                mHandler.postDelayed(new Runnable() {

+                    @Override

+                    public void run() {

+                        mAdapter.disable();

+                    }

+                }, 1000);

+            }

+        }

+

+        @Override

+        public void onReceive(Context context, Intent intent) {

+            if (intent.getAction().equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {

+                int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);

+                if (state == BluetoothAdapter.STATE_OFF) {

+                    mHandler.postDelayed(new Runnable() {

+                        @Override

+                        public void run() {

+                            mAdapter.enable();

+                        }

+                    }, BT_ON_DELAY);

+                } else if (state == BluetoothAdapter.STATE_ON) {

+                    mIsSwitching = false;

+                    unregisterReceiver(this);

+                    getPassButton().setEnabled(true);

+                    closeDialog();

+                }

+            }

+        }

+    }

+}

diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleEncryptedClientService.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleEncryptedClientService.java
new file mode 100644
index 0000000..68797f5
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleEncryptedClientService.java
@@ -0,0 +1,582 @@
+/*

+ * Copyright (C) 2016 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.BluetoothGattCallback;

+import android.bluetooth.BluetoothGattCharacteristic;

+import android.bluetooth.BluetoothGattDescriptor;

+import android.bluetooth.BluetoothGattService;

+import android.bluetooth.BluetoothManager;

+import android.bluetooth.BluetoothProfile;

+import android.bluetooth.le.BluetoothLeScanner;

+import android.bluetooth.le.ScanCallback;

+import android.bluetooth.le.ScanFilter;

+import android.bluetooth.le.ScanResult;

+import android.bluetooth.le.ScanSettings;

+import android.content.Context;

+import android.content.Intent;

+import android.os.Handler;

+import android.os.IBinder;

+import android.os.ParcelUuid;

+import android.util.Log;

+import android.widget.Toast;

+

+import java.util.Arrays;

+import java.util.List;

+import java.util.UUID;

+

+public class BleEncryptedClientService extends Service {

+    public static final boolean DEBUG = true;

+    public static final String TAG = "BleEncryptedClient";

+

+    public static final String ACTION_CONNECT_WITH_SECURE =

+            "com.android.cts.verifier.bluetooth.encripted.action.ACTION_CONNECT_WITH_SECURE";

+    public static final String ACTION_CONNECT_WITHOUT_SECURE =

+            "com.android.cts.verifier.bluetooth.encripted.action.ACTION_CONNECT_WITHOUT_SECURE";

+

+    public static final String INTENT_BLE_BLUETOOTH_DISABLED =

+            "com.android.cts.verifier.bluetooth.encripted.intent.BLE_BLUETOOTH_DISABLED";

+    public static final String INTENT_BLE_WRITE_ENCRYPTED_CHARACTERISTIC =

+            "com.android.cts.verifier.bluetooth.encripted.intent.BLE_WRITE_ENCRYPTED_CHARACTERISTIC";

+    public static final String INTENT_BLE_WRITE_NOT_ENCRYPTED_CHARACTERISTIC =

+            "com.android.cts.verifier.bluetooth.encripted.intent.BLE_WRITE_NOT_ENCRYPTED_CHARACTERISTIC";

+    public static final String INTENT_BLE_READ_ENCRYPTED_CHARACTERISTIC =

+            "com.android.cts.verifier.bluetooth.encripted.intent.BLE_READ_ENCRYPTED_CHARACTERISTIC";

+    public static final String INTENT_BLE_READ_NOT_ENCRYPTED_CHARACTERISTIC =

+            "com.android.cts.verifier.bluetooth.encripted.intent.BLE_READ_NOT_ENCRYPTED_CHARACTERISTIC";

+    public static final String INTENT_BLE_WRITE_ENCRYPTED_DESCRIPTOR =

+            "com.android.cts.verifier.bluetooth.encripted.intent.BLE_WRITE_ENCRYPTED_DESCRIPTOR";

+    public static final String INTENT_BLE_WRITE_NOT_ENCRYPTED_DESCRIPTOR =

+            "com.android.cts.verifier.bluetooth.encripted.intent.BLE_WRITE_NOT_ENCRYPTED_DESCRIPTOR";

+    public static final String INTENT_BLE_READ_ENCRYPTED_DESCRIPTOR =

+            "com.android.cts.verifier.bluetooth.encripted.intent.BLE_READ_ENCRYPTED_DESCRIPTOR";

+    public static final String INTENT_BLE_READ_NOT_ENCRYPTED_DESCRIPTOR =

+            "com.android.cts.verifier.bluetooth.encripted.intent.BLE_READ_NOT_ENCRYPTED_DESCRIPTOR";

+    public static final String INTENT_BLE_WRITE_FAIL_ENCRYPTED_CHARACTERISTIC =

+            "com.android.cts.verifier.bluetooth.encripted.intent.INTENT_BLE_WRITE_FAIL_ENCRYPTED_CHARACTERISTIC";

+    public static final String INTENT_BLE_READ_FAIL_ENCRYPTED_CHARACTERISTIC =

+            "com.android.cts.verifier.bluetooth.encripted.intent.INTENT_BLE_READ_FAIL_ENCRYPTED_CHARACTERISTIC";

+    public static final String INTENT_BLE_WRITE_FAIL_ENCRYPTED_DESCRIPTOR =

+            "com.android.cts.verifier.bluetooth.encripted.intent.INTENT_BLE_WRITE_FAIL_ENCRYPTED_DESCRIPTOR";

+    public static final String INTENT_BLE_READ_FAIL_ENCRYPTED_DESCRIPTOR =

+            "com.android.cts.verifier.bluetooth.encripted.intent.INTENT_BLE_READ_FAIL_ENCRYPTED_DESCRIPTOR";

+

+    public static final String ACTION_WRITE_ENCRYPTED_CHARACTERISTIC =

+            "com.android.cts.verifier.bluetooth.encripted.action.WRITE_ENCRYPTED_CHARACTERISTIC";

+    public static final String ACTION_READ_ENCRYPTED_CHARACTERISTIC =

+            "com.android.cts.verifier.bluetooth.encripted.action.READ_ENCRYPTED_CHARACTERISTIC";

+    public static final String ACTION_WRITE_ENCRYPTED_DESCRIPTOR =

+            "com.android.cts.verifier.bluetooth.encripted.action.WRITE_ENCRYPTED_DESCRIPTOR";

+    public static final String ACTION_READ_ENCRYPTED_DESCRIPTOR =

+            "com.android.cts.verifier.bluetooth.encripted.action.READ_ENCRYPTED_DESCRIPTOR";

+

+    public static final String ACTION_DISCONNECTED =

+            "com.android.cts.verifier.bluetooth.encripted.action.DISCONNECTED";

+

+    public static final String WRITE_VALUE = "ENC_CLIENT_TEST";

+

+    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 DESCRIPTOR_UUID =

+            UUID.fromString("00009997-0000-1000-8000-00805f9b34fb");

+    private static final UUID CHARACTERISTIC_ENCRYPTED_WRITE_UUID =

+            UUID.fromString("00009996-0000-1000-8000-00805f9b34fb");

+    private static final UUID CHARACTERISTIC_ENCRYPTED_READ_UUID =

+            UUID.fromString("00009995-0000-1000-8000-00805f9b34fb");

+    private static final UUID DESCRIPTOR_ENCRYPTED_WRITE_UUID =

+            UUID.fromString("00009994-0000-1000-8000-00805f9b34fb");

+    private static final UUID DESCRIPTOR_ENCRYPTED_READ_UUID =

+            UUID.fromString("00009993-0000-1000-8000-00805f9b34fb");

+

+    private BluetoothManager mBluetoothManager;

+    private BluetoothAdapter mBluetoothAdapter;

+    private BluetoothGatt mBluetoothGatt;

+    private BluetoothLeScanner mScanner;

+    private BluetoothDevice mDevice;

+    private Handler mHandler;

+    private Context mContext;

+    private String mAction;

+    private boolean mSecure;

+    private String mTarget;

+

+    private String mLastScanError;

+    private TestTaskQueue mTaskQueue;

+

+    public BleEncryptedClientService() {

+    }

+

+    @Override

+    public IBinder onBind(Intent intent) {

+        return null;

+    }

+

+    @Override

+    public void onCreate() {

+        super.onCreate();

+

+        mTaskQueue = new TestTaskQueue(getClass().getName() + "_enc_cli_taskHandlerThread");

+

+        mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);

+        mBluetoothAdapter = mBluetoothManager.getAdapter();

+

+        mScanner = mBluetoothAdapter.getBluetoothLeScanner();

+        mHandler = new Handler();

+        mContext = this;

+        mSecure = false;

+    }

+

+    @Override

+    public void onDestroy() {

+        super.onDestroy();

+

+        mTaskQueue.quit();

+

+        if (mBluetoothGatt != null) {

+            mBluetoothGatt.disconnect();

+            mBluetoothGatt.close();

+            mBluetoothGatt = null;

+            mDevice = null;

+        }

+        stopScan();

+    }

+

+    private void notifyBluetoothDisabled() {

+        Intent intent = new Intent(INTENT_BLE_BLUETOOTH_DISABLED);

+        sendBroadcast(intent);

+    }

+

+    private void notifyDisconnected() {

+        Intent intent = new Intent(ACTION_DISCONNECTED);

+        sendBroadcast(intent);

+    }

+

+    @Override

+    public int onStartCommand(Intent intent, int flags, int startId) {

+        if (!mBluetoothAdapter.isEnabled()) {

+            notifyBluetoothDisabled();

+        } else {

+            if (intent != null) {

+                mAction = intent.getAction();

+                if (mAction == null) {

+                    mSecure = intent.getBooleanExtra(BleEncryptedServerService.EXTRA_SECURE, false);

+                } else {

+                    switch (mAction) {

+                    case ACTION_CONNECT_WITH_SECURE:

+                        mSecure = true;

+                        break;

+                    case ACTION_CONNECT_WITHOUT_SECURE:

+                        mSecure = false;

+                        break;

+                    case ACTION_WRITE_ENCRYPTED_CHARACTERISTIC:

+                        mTarget = BleEncryptedServerService.WRITE_CHARACTERISTIC;

+                        startScan();

+                        break;

+                    case ACTION_READ_ENCRYPTED_CHARACTERISTIC:

+                        mTarget = BleEncryptedServerService.READ_CHARACTERISTIC;

+                        startScan();

+                        break;

+                    case ACTION_WRITE_ENCRYPTED_DESCRIPTOR:

+                        mTarget = BleEncryptedServerService.WRITE_DESCRIPTOR;

+                        startScan();

+                        break;

+                    case ACTION_READ_ENCRYPTED_DESCRIPTOR:

+                        mTarget = BleEncryptedServerService.READ_DESCRIPTOR;

+                        startScan();

+                        break;

+                    default:

+                        return START_NOT_STICKY;

+                    }

+                }

+            }

+        }

+        return START_NOT_STICKY;

+    }

+

+    private BluetoothGattService getService() {

+        BluetoothGattService service = null;

+

+        if (mBluetoothGatt != null) {

+            service = mBluetoothGatt.getService(SERVICE_UUID);

+            if (service == null) {

+                showMessage("Service not found");

+            }

+        }

+        return service;

+    }

+

+    private BluetoothGattCharacteristic getCharacteristic(UUID uuid) {

+        BluetoothGattCharacteristic characteristic = null;

+

+        BluetoothGattService service = getService();

+        if (service != null) {

+            characteristic = service.getCharacteristic(uuid);

+            if (characteristic == null) {

+                showMessage("Characteristic not found");

+            }

+        }

+        return characteristic;

+    }

+

+    private BluetoothGattDescriptor getDescriptor(UUID uid) {

+        BluetoothGattDescriptor descriptor = null;

+

+        BluetoothGattCharacteristic characteristic = getCharacteristic(CHARACTERISTIC_UUID);

+        if (characteristic != null) {

+            descriptor = characteristic.getDescriptor(uid);

+            if (descriptor == null) {

+                showMessage("Descriptor not found");

+            }

+        }

+        return descriptor;

+    }

+

+    private void sleep(int millis) {

+        try {

+            Thread.sleep(millis);

+        } catch (InterruptedException e) {

+            Log.e(TAG, "Error in thread sleep", e);

+        }

+    }

+

+    private void startEncryptedAction() {

+        BluetoothGattCharacteristic characteristic;

+        BluetoothGattCharacteristic caseCharacteristic;

+        BluetoothGattDescriptor descriptor;

+        switch (mTarget) {

+        case BleEncryptedServerService.WRITE_CHARACTERISTIC:

+            Log.v(TAG, "WRITE_CHARACTERISTIC");

+            characteristic = getCharacteristic(CHARACTERISTIC_ENCRYPTED_WRITE_UUID);

+            characteristic.setValue(WRITE_VALUE);

+            mBluetoothGatt.writeCharacteristic(characteristic);

+            break;

+        case BleEncryptedServerService.READ_CHARACTERISTIC:

+            Log.v(TAG, "READ_CHARACTERISTIC");

+            characteristic = getCharacteristic(CHARACTERISTIC_ENCRYPTED_READ_UUID);

+            mBluetoothGatt.readCharacteristic(characteristic);

+            break;

+        case BleEncryptedServerService.WRITE_DESCRIPTOR:

+            Log.v(TAG, "WRITE_DESCRIPTOR");

+            descriptor = getDescriptor(DESCRIPTOR_ENCRYPTED_WRITE_UUID);

+            descriptor.setValue(WRITE_VALUE.getBytes());

+            mBluetoothGatt.writeDescriptor(descriptor);

+            break;

+        case BleEncryptedServerService.READ_DESCRIPTOR:

+            Log.v(TAG, "READ_DESCRIPTOR");

+            descriptor = getDescriptor(DESCRIPTOR_ENCRYPTED_READ_UUID);

+            mBluetoothGatt.readDescriptor(descriptor);

+            break;

+        }

+    }

+

+    private void showMessage(final String msg) {

+        mHandler.post(new Runnable() {

+            public void run() {

+                Toast.makeText(BleEncryptedClientService.this, msg, Toast.LENGTH_SHORT).show();

+            }

+        });

+    }

+

+    private final BluetoothGattCallback mGattCallbacks = new BluetoothGattCallback() {

+        @Override

+        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {

+            if (DEBUG) Log.d(TAG, "onConnectionStateChange: status = " + status + ", newState = " + newState);

+            if (status == BluetoothGatt.GATT_SUCCESS) {

+                if (newState == BluetoothProfile.STATE_CONNECTED) {

+                    showMessage("Bluetooth LE connected");

+                    mTaskQueue.addTask(new Runnable() {

+                        @Override

+                        public void run() {

+                            mBluetoothGatt.discoverServices();

+                        }

+                    }, 1000);

+                } else if (status == BluetoothProfile.STATE_DISCONNECTED) {

+                    showMessage("Bluetooth LE disconnected");

+                    mTaskQueue.addTask(new Runnable() {

+                        @Override

+                        public void run() {

+                            if (mBluetoothGatt != null) {

+                                mBluetoothGatt.close();

+                                mBluetoothGatt = null;

+                                mTarget = null;

+                                mDevice = null;

+                                notifyDisconnected();

+                            }

+                        }

+                    }, 1000);

+                }

+            } else {

+                showMessage("Connection Not Success.");

+                if (mTarget != null) {

+                    Intent intent;

+                    switch (mTarget) {

+                    case BleEncryptedServerService.READ_CHARACTERISTIC:

+                        intent = new Intent(INTENT_BLE_READ_FAIL_ENCRYPTED_CHARACTERISTIC);

+                        break;

+                    case BleEncryptedServerService.WRITE_CHARACTERISTIC:

+                        if (mSecure) {

+                            intent = new Intent(INTENT_BLE_WRITE_FAIL_ENCRYPTED_CHARACTERISTIC);

+                        } else {

+                            intent = new Intent(INTENT_BLE_WRITE_ENCRYPTED_CHARACTERISTIC);

+                        }

+                        break;

+                    case BleEncryptedServerService.READ_DESCRIPTOR:

+                        intent = new Intent(INTENT_BLE_READ_FAIL_ENCRYPTED_DESCRIPTOR);

+                        break;

+                    case BleEncryptedServerService.WRITE_DESCRIPTOR:

+                        if (mSecure) {

+                            intent = new Intent(INTENT_BLE_WRITE_FAIL_ENCRYPTED_DESCRIPTOR);

+                        } else {

+                            intent = new Intent(INTENT_BLE_WRITE_ENCRYPTED_DESCRIPTOR);

+                        }

+                        break;

+                    default:

+                        return;

+                    }

+                    if (mBluetoothGatt != null) {

+                        mBluetoothGatt.close();

+                        mBluetoothGatt = null;

+                        mDevice = null;

+                        mTarget = null;

+                    }

+                    sendBroadcast(intent);

+                }

+            }

+        }

+

+        @Override

+        public void onServicesDiscovered(BluetoothGatt gatt, int status) {

+            if (DEBUG){

+                Log.d(TAG, "onServiceDiscovered");

+            }

+            if ((status == BluetoothGatt.GATT_SUCCESS) && (mBluetoothGatt.getService(SERVICE_UUID) != null)) {

+                showMessage("Service discovered");

+                startEncryptedAction();

+            }

+        }

+

+        @Override

+        public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, final int status) {

+            final String value = characteristic.getStringValue(0);

+            UUID uid = characteristic.getUuid();

+            if (DEBUG) {

+                Log.d(TAG, "onCharacteristicWrite: characteristic.val=" + value + " status=" + status + " uid=" + uid);

+            }

+

+            if (uid.equals(CHARACTERISTIC_ENCRYPTED_WRITE_UUID)) {

+                mTaskQueue.addTask(new Runnable() {

+                    @Override

+                    public void run() {

+                        if (status == BluetoothGatt.GATT_SUCCESS) {

+                            if (mSecure) {

+                                mBluetoothGatt.disconnect();

+                                if (WRITE_VALUE.equals(value)) {

+                                    Intent intent = new Intent(INTENT_BLE_WRITE_ENCRYPTED_CHARACTERISTIC);

+                                    sendBroadcast(intent);

+                                } else {

+                                    showMessage("Written data is not correct");

+                                }

+                            }

+                        } else {

+                            if (!mSecure) {

+                                mBluetoothGatt.disconnect();

+                                Intent intent = new Intent(INTENT_BLE_WRITE_NOT_ENCRYPTED_CHARACTERISTIC);

+                                sendBroadcast(intent);

+                            } else {

+                                mBluetoothGatt.disconnect();

+                                Intent intent = new Intent(INTENT_BLE_WRITE_FAIL_ENCRYPTED_CHARACTERISTIC);

+                                sendBroadcast(intent);

+                            }

+                        }

+                    }

+                }, 1000);

+            }

+        }

+

+        @Override

+        public void onCharacteristicRead(BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic, final int status) {

+            UUID uid = characteristic.getUuid();

+            if (DEBUG) {

+                Log.d(TAG, "onCharacteristicRead: status=" + status);

+            }

+            if (uid.equals(CHARACTERISTIC_ENCRYPTED_READ_UUID)) {

+                mTaskQueue.addTask(new Runnable() {

+                    @Override

+                    public void run() {

+                        if (status == BluetoothGatt.GATT_SUCCESS) {

+                            if (mSecure) {

+                                mBluetoothGatt.disconnect();

+                                if (Arrays.equals(BleEncryptedServerService.WRITE_VALUE.getBytes(), characteristic.getValue())) {

+                                    Intent intent = new Intent(INTENT_BLE_READ_ENCRYPTED_CHARACTERISTIC);

+                                    sendBroadcast(intent);

+                                } else {

+                                    showMessage("Read data is not correct");

+                                }

+                            } else {

+                                mBluetoothGatt.disconnect();

+                                Intent intent = new Intent(INTENT_BLE_READ_NOT_ENCRYPTED_CHARACTERISTIC);

+                                sendBroadcast(intent);

+                            }

+                        } else {

+                            if (!mSecure) {

+                                mBluetoothGatt.disconnect();

+                                Intent intent = new Intent(INTENT_BLE_READ_ENCRYPTED_CHARACTERISTIC);

+                                sendBroadcast(intent);

+                            } else {

+                                mBluetoothGatt.disconnect();

+                                Intent intent = new Intent(INTENT_BLE_READ_FAIL_ENCRYPTED_CHARACTERISTIC);

+                                sendBroadcast(intent);

+                            }

+                        }

+                    }

+                }, 1000);

+            }

+        }

+

+        @Override

+        public void onDescriptorRead(BluetoothGatt gatt, final BluetoothGattDescriptor descriptor, final int status) {

+            if (DEBUG) {

+                Log.d(TAG, "onDescriptorRead: status=" + status);

+            }

+

+            mTaskQueue.addTask(new Runnable() {

+                @Override

+                public void run() {

+                    UUID uid = descriptor.getUuid();

+                    if ((status == BluetoothGatt.GATT_SUCCESS)) {

+                        if (uid.equals(DESCRIPTOR_ENCRYPTED_READ_UUID)) {

+                            if (mSecure) {

+                                mBluetoothGatt.disconnect();

+                                if (Arrays.equals(BleEncryptedServerService.WRITE_VALUE.getBytes(), descriptor.getValue())) {

+                                    Intent intent = new Intent(INTENT_BLE_READ_ENCRYPTED_DESCRIPTOR);

+                                    sendBroadcast(intent);

+                                } else {

+                                    showMessage("Read data is not correct");

+                                }

+                            } else {

+                                mBluetoothGatt.disconnect();

+                                Intent intent = new Intent(INTENT_BLE_READ_NOT_ENCRYPTED_DESCRIPTOR);

+                                sendBroadcast(intent);

+                            }

+                        }

+                    } else {

+                        if (!mSecure) {

+                            mBluetoothGatt.disconnect();

+                            Intent intent = new Intent(INTENT_BLE_READ_ENCRYPTED_DESCRIPTOR);

+                            sendBroadcast(intent);

+                        } else {

+                            if (uid.equals(DESCRIPTOR_ENCRYPTED_READ_UUID)) {

+                                mBluetoothGatt.disconnect();

+                                Intent intent = new Intent(INTENT_BLE_READ_FAIL_ENCRYPTED_DESCRIPTOR);

+                                sendBroadcast(intent);

+                            }

+                        }

+                    }

+                }

+            }, 1000);

+        }

+

+        @Override

+        public void onDescriptorWrite(BluetoothGatt gatt, final BluetoothGattDescriptor descriptor, final int status) {

+            if (DEBUG) {

+                Log.d(TAG, "onDescriptorWrite: status=" + status);

+            }

+

+            mTaskQueue.addTask(new Runnable() {

+                @Override

+                public void run() {

+                    UUID uid = descriptor.getUuid();

+                    if (uid.equals(DESCRIPTOR_ENCRYPTED_WRITE_UUID)) {

+                        if ((status == BluetoothGatt.GATT_SUCCESS)) {

+                            if (mSecure) {

+                                mBluetoothGatt.disconnect();

+                                if (Arrays.equals(WRITE_VALUE.getBytes(), descriptor.getValue())) {

+                                    Intent intent = new Intent(INTENT_BLE_WRITE_ENCRYPTED_DESCRIPTOR);

+                                    sendBroadcast(intent);

+                                } else {

+                                    showMessage("Written data is not correct");

+                                }

+                            }

+                        } else {

+                            if (!mSecure) {

+                                mBluetoothGatt.disconnect();

+                                Intent intent = new Intent(INTENT_BLE_WRITE_NOT_ENCRYPTED_DESCRIPTOR);

+                                sendBroadcast(intent);

+                            } else {

+                                mBluetoothGatt.disconnect();

+                                Intent intent = new Intent(INTENT_BLE_WRITE_FAIL_ENCRYPTED_DESCRIPTOR);

+                                sendBroadcast(intent);

+                            }

+                        }

+                    }

+                }

+            }, 1000);

+        }

+    };

+

+    private final ScanCallback mScanCallback = new ScanCallback() {

+        @Override

+        public void onScanResult(int callbackType, final ScanResult result) {

+            if (mBluetoothGatt== null) {

+                mDevice = result.getDevice();

+                int bond_state = mDevice.getBondState();

+                if (mSecure && bond_state != BluetoothDevice.BOND_BONDED) {

+                    mLastScanError = "This test is a test of Secure.\n Before running the test, please do the pairing.";

+                    return;

+                } else if (!mSecure && bond_state != BluetoothDevice.BOND_NONE) {

+                    mLastScanError = "This test is a test of Insecure\n Before running the test, please release the pairing.";

+                    return;

+                }

+                mLastScanError = null;

+                stopScan();

+                mBluetoothGatt = BleClientService.connectGatt(mDevice, mContext, false, mSecure, mGattCallbacks);

+            }

+        }

+    };

+

+    private void startScan() {

+        if (DEBUG) Log.d(TAG, "startScan");

+        List<ScanFilter> filter = Arrays.asList(new ScanFilter.Builder().setServiceUuid(

+                new ParcelUuid(BleEncryptedServerService.ADV_SERVICE_UUID)).build());

+        ScanSettings setting = new ScanSettings.Builder()

+                .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build();

+        mScanner.startScan(filter, setting, mScanCallback);

+

+        mTaskQueue.addTask(new Runnable() {

+            @Override

+            public void run() {

+                if (mLastScanError != null) {

+                    stopScan();

+                    Toast.makeText(BleEncryptedClientService.this, mLastScanError, Toast.LENGTH_LONG).show();

+                    mLastScanError = null;

+                }

+            }

+        }, 10000);

+    }

+

+    private void stopScan() {

+        if (DEBUG) Log.d(TAG, "stopScan");

+        if (mScanner != null) {

+            mScanner.stopScan(mScanCallback);

+        }

+    }

+}

diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleEncryptedServerBaseActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleEncryptedServerBaseActivity.java
new file mode 100644
index 0000000..5639b50
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleEncryptedServerBaseActivity.java
@@ -0,0 +1,166 @@
+/*

+ * Copyright (C) 2016 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.AlertDialog;

+import android.app.Dialog;

+import android.content.BroadcastReceiver;

+import android.content.Context;

+import android.content.DialogInterface;

+import android.content.Intent;

+import android.content.IntentFilter;

+import android.os.Bundle;

+import android.widget.ListView;

+import android.widget.Toast;

+

+import com.android.cts.verifier.PassFailButtons;

+import com.android.cts.verifier.R;

+

+import java.util.ArrayList;

+import java.util.List;

+

+public class BleEncryptedServerBaseActivity extends PassFailButtons.Activity {

+

+    private TestAdapter mTestAdapter;

+    private int mAllPassed;

+

+    private final int WAIT_WRITE_ENCRIPTED_CHARACTERISTIC = 0;

+    private final int WAIT_READ_ENCRIPTED_CHARACTERISTIC = 1;

+    private final int WAIT_WRITE_ENCRIPTED_DESCRIPTOR = 2;

+    private final int WAIT_READ_ENCRIPTED_DESCRIPTOR = 3;

+

+    @Override

+    protected void onCreate(Bundle savedInstanceState) {

+        super.onCreate(savedInstanceState);

+        setContentView(R.layout.ble_encrypted_server_test);

+        setPassFailButtonClickListeners();

+        setInfoResources(R.string.ble_encrypted_server_name,

+                R.string.ble_encrypted_server_info, -1);

+

+        getPassButton().setEnabled(false);

+

+        mTestAdapter = new TestAdapter(this, setupTestList());

+        ListView listView = (ListView) findViewById(R.id.ble_server_enctypted_tests);

+        listView.setAdapter(mTestAdapter);

+

+        startService(new Intent(this, BleEncryptedServerService.class));

+    }

+

+    @Override

+    public void onResume() {

+        super.onResume();

+

+        IntentFilter filter = new IntentFilter();

+        filter.addAction(BleEncryptedServerService.INTENT_BLUETOOTH_DISABLED);

+        filter.addAction(BleEncryptedServerService.INTENT_WAIT_WRITE_ENCRYPTED_CHARACTERISTIC);

+        filter.addAction(BleEncryptedServerService.INTENT_WAIT_READ_ENCRYPTED_CHARACTERISTIC);

+        filter.addAction(BleEncryptedServerService.INTENT_WAIT_WRITE_ENCRYPTED_DESCRIPTOR);

+        filter.addAction(BleEncryptedServerService.INTENT_WAIT_READ_ENCRYPTED_DESCRIPTOR);

+        filter.addAction(BleServerService.BLE_ADVERTISE_UNSUPPORTED);

+        filter.addAction(BleServerService.BLE_OPEN_FAIL);

+        registerReceiver(mBroadcast, filter);

+    }

+

+    @Override

+    public void onPause() {

+        super.onPause();

+        unregisterReceiver(mBroadcast);

+    }

+

+    private List<Integer> setupTestList() {

+        ArrayList<Integer> testList = new ArrayList<Integer>();

+        testList.add(R.string.ble_server_write_characteristic_need_encrypted);

+        testList.add(R.string.ble_server_read_characteristic_need_encrypted);

+        testList.add(R.string.ble_server_write_descriptor_need_encrypted);

+        testList.add(R.string.ble_server_read_descriptor_need_encrypted);

+        return testList;

+    }

+

+    @Override

+    public void onDestroy() {

+        super.onDestroy();

+        stopService(new Intent(this, BleConnectionPriorityServerService.class));

+    }

+

+    private BroadcastReceiver mBroadcast = new BroadcastReceiver() {

+        @Override

+        public void onReceive(Context context, Intent intent) {

+            String action = intent.getAction();

+            switch (action) {

+            case BleEncryptedServerService.INTENT_BLUETOOTH_DISABLED:

+                new AlertDialog.Builder(context)

+                        .setTitle(R.string.ble_bluetooth_disable_title)

+                        .setMessage(R.string.ble_bluetooth_disable_message)

+                        .setOnCancelListener(new Dialog.OnCancelListener() {

+                            @Override

+                            public void onCancel(DialogInterface dialog) {

+                                finish();

+                            }

+                        })

+                        .create().show();

+                break;

+            case BleEncryptedServerService.INTENT_WAIT_WRITE_ENCRYPTED_CHARACTERISTIC:

+                mTestAdapter.setTestPass(WAIT_WRITE_ENCRIPTED_CHARACTERISTIC);

+                mAllPassed |= 0x01;

+                break;

+            case BleEncryptedServerService.INTENT_WAIT_READ_ENCRYPTED_CHARACTERISTIC:

+                mTestAdapter.setTestPass(WAIT_READ_ENCRIPTED_CHARACTERISTIC);

+                mAllPassed |= 0x02;

+                break;

+            case BleEncryptedServerService.INTENT_WAIT_WRITE_ENCRYPTED_DESCRIPTOR:

+                mTestAdapter.setTestPass(WAIT_WRITE_ENCRIPTED_DESCRIPTOR);

+                mAllPassed |= 0x04;

+                break;

+            case BleEncryptedServerService.INTENT_WAIT_READ_ENCRYPTED_DESCRIPTOR:

+                mTestAdapter.setTestPass(WAIT_READ_ENCRIPTED_DESCRIPTOR);

+                mAllPassed |= 0x08;

+                break;

+            case BleServerService.BLE_ADVERTISE_UNSUPPORTED:

+                showErrorDialog(R.string.bt_advertise_unsupported_title, R.string.bt_advertise_unsupported_message, true);

+                break;

+            case BleServerService.BLE_OPEN_FAIL:

+                setTestResultAndFinish(false);

+                runOnUiThread(new Runnable() {

+                    @Override

+                    public void run() {

+                        Toast.makeText(BleEncryptedServerBaseActivity.this, R.string.bt_open_failed_message, Toast.LENGTH_SHORT).show();

+                    }

+                });

+                break;

+            }

+            mTestAdapter.notifyDataSetChanged();

+            if (mAllPassed == 0x0F) {

+                getPassButton().setEnabled(true);

+            }

+        }

+    };

+

+    private void showErrorDialog(int titleId, int messageId, boolean finish) {

+        AlertDialog.Builder builder = new AlertDialog.Builder(this)

+                .setTitle(titleId)

+                .setMessage(messageId);

+        if (finish) {

+            builder.setOnCancelListener(new Dialog.OnCancelListener() {

+                @Override

+                public void onCancel(DialogInterface dialog) {

+                    finish();

+                }

+            });

+        }

+        builder.create().show();

+    }

+}

diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleEncryptedServerService.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleEncryptedServerService.java
new file mode 100644
index 0000000..6fb09a1
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleEncryptedServerService.java
@@ -0,0 +1,480 @@
+/*
+ * Copyright (C) 2016 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.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.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.Handler;
+import android.os.IBinder;
+import android.os.ParcelUuid;
+import android.util.Log;
+
+import java.util.Arrays;
+import java.util.UUID;
+
+public class BleEncryptedServerService extends Service {
+    public BleEncryptedServerService() {
+    }
+    public static final boolean DEBUG = true;
+    public static final String TAG = "BleEncryptedServer";
+
+    public static final String INTENT_BLUETOOTH_DISABLED =
+            "com.android.cts.verifier.bluetooth.encripted.intent.BLUETOOTH_DISABLED";
+
+    public static final String ACTION_CONNECT_WITH_SECURE =
+            "com.android.cts.verifier.bluetooth.encripted.action.ACTION_CONNECT_WITH_SECURE";
+    public static final String ACTION_CONNECT_WITHOUT_SECURE =
+            "com.android.cts.verifier.bluetooth.encripted.action.ACTION_CONNECT_WITHOUT_SECURE";
+
+    public static final String INTENT_WAIT_WRITE_ENCRYPTED_CHARACTERISTIC =
+            "com.android.cts.verifier.bluetooth.encripted.intent.WAIT_WRITE_ENCRYPTED_CHARACTERISTIC";
+    public static final String INTENT_WAIT_READ_ENCRYPTED_CHARACTERISTIC =
+            "com.android.cts.verifier.bluetooth.encripted.intent.WAIT_READ_ENCRYPTED_CHARACTERISTIC";
+    public static final String INTENT_WAIT_WRITE_ENCRYPTED_DESCRIPTOR =
+            "com.android.cts.verifier.bluetooth.encripted.intent.WAIT_WRITE_ENCRYPTED_DESCRIPTOR";
+    public static final String INTENT_WAIT_READ_ENCRYPTED_DESCRIPTOR =
+            "com.android.cts.verifier.bluetooth.encripted.intent.WAIT_READ_ENCRYPTED_DESCRIPTOR";
+
+    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 DESCRIPTOR_UUID =
+            UUID.fromString("00009997-0000-1000-8000-00805f9b34fb");
+
+    private static final UUID CHARACTERISTIC_ENCRYPTED_WRITE_UUID =
+            UUID.fromString("00009996-0000-1000-8000-00805f9b34fb");
+    private static final UUID CHARACTERISTIC_ENCRYPTED_READ_UUID =
+            UUID.fromString("00009995-0000-1000-8000-00805f9b34fb");
+    private static final UUID DESCRIPTOR_ENCRYPTED_WRITE_UUID =
+            UUID.fromString("00009994-0000-1000-8000-00805f9b34fb");
+    private static final UUID DESCRIPTOR_ENCRYPTED_READ_UUID =
+            UUID.fromString("00009993-0000-1000-8000-00805f9b34fb");
+
+    public static final UUID ADV_SERVICE_UUID=
+            UUID.fromString("00002222-0000-1000-8000-00805f9b34fb");
+
+    private static final int CONN_INTERVAL = 150;   // connection interval 150ms
+
+    public static final String EXTRA_SECURE = "SECURE";
+    public static final String WRITE_CHARACTERISTIC = "WRITE_CHAR";
+    public static final String READ_CHARACTERISTIC = "READ_CHAR";
+    public static final String WRITE_DESCRIPTOR = "WRITE_DESC";
+    public static final String READ_DESCRIPTOR = "READ_DESC";
+
+    public static final String WRITE_VALUE = "ENC_SERVER_TEST";
+
+    private BluetoothManager mBluetoothManager;
+    private BluetoothGattServer mGattServer;
+    private BluetoothGattService mService;
+    private BluetoothDevice mDevice;
+    private BluetoothLeAdvertiser mAdvertiser;
+    private boolean mSecure;
+    private String mTarget;
+    private Handler mHandler;
+    private Runnable mResetValuesTask;
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+
+        mHandler = new Handler();
+        mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
+        mAdvertiser = mBluetoothManager.getAdapter().getBluetoothLeAdvertiser();
+        mGattServer = mBluetoothManager.openGattServer(this, mCallbacks);
+        mService = createService();
+        if ((mGattServer != null) && (mAdvertiser != null)) {
+            mGattServer.addService(mService);
+        }
+        mDevice = null;
+        mSecure = false;
+        if (!mBluetoothManager.getAdapter().isEnabled()) {
+            notifyBluetoothDisabled();
+        } else if (mGattServer == null) {
+            notifyOpenFail();
+        } else if (mAdvertiser == null) {
+            notifyAdvertiseUnsupported();
+        } else {
+            startAdvertise();
+        }
+
+        resetValues();
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        stopAdvertise();
+        if (mGattServer == null) {
+            return;
+        }
+        if (mDevice != null) {
+            mGattServer.cancelConnection(mDevice);
+        }
+        mGattServer.clearServices();
+        mGattServer.close();
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return null;
+    }
+
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        String action = intent.getAction();
+        if (action != null) {
+            switch (action) {
+            case ACTION_CONNECT_WITH_SECURE:
+                mSecure = true;
+                break;
+            case ACTION_CONNECT_WITHOUT_SECURE:
+                mSecure = false;
+                break;
+            }
+        }
+        return START_NOT_STICKY;
+    }
+
+    /**
+     * Sets default value to characteristic and descriptor.
+     *
+     * Set operation will be done after connection interval.
+     * (If set values immediately, multiple read/write operations may fail.)
+     */
+    private synchronized void resetValues() {
+        // cancel pending task
+        if (mResetValuesTask != null) {
+            mHandler.removeCallbacks(mResetValuesTask);
+            mResetValuesTask = null;
+        }
+
+        // reserve task
+        mResetValuesTask = new Runnable() {
+            @Override
+            public void run() {
+                BluetoothGattCharacteristic characteristic = mService.getCharacteristic(CHARACTERISTIC_ENCRYPTED_READ_UUID);
+                characteristic.setValue(WRITE_VALUE.getBytes());
+                characteristic = mService.getCharacteristic(CHARACTERISTIC_UUID);
+                characteristic.getDescriptor(DESCRIPTOR_ENCRYPTED_READ_UUID).setValue(WRITE_VALUE.getBytes());
+            }
+        };
+        mHandler.postDelayed(mResetValuesTask, CONN_INTERVAL);
+    }
+
+    private void notifyBluetoothDisabled() {
+        Intent intent = new Intent(INTENT_BLUETOOTH_DISABLED);
+        sendBroadcast(intent);
+    }
+
+    private void notifyOpenFail() {
+        if (DEBUG) {
+            Log.d(TAG, "notifyOpenFail");
+        }
+        Intent intent = new Intent(BleServerService.BLE_OPEN_FAIL);
+        sendBroadcast(intent);
+    }
+
+    private void notifyAdvertiseUnsupported() {
+        if (DEBUG) {
+            Log.d(TAG, "notifyAdvertiseUnsupported");
+        }
+        Intent intent = new Intent(BleServerService.BLE_ADVERTISE_UNSUPPORTED);
+        sendBroadcast(intent);
+    }
+
+    private void notifyConnected() {
+        if (DEBUG) {
+            Log.d(TAG, "notifyConnected");
+        }
+        resetValues();
+    }
+
+    private void notifyDisconnected() {
+        if (DEBUG) {
+            Log.d(TAG, "notifyDisconnected");
+        }
+    }
+
+    private void notifyServiceAdded() {
+        if (DEBUG) {
+            Log.d(TAG, "notifyServiceAdded");
+        }
+    }
+
+    private void notifyCharacteristicWriteRequest() {
+        if (DEBUG) {
+            Log.d(TAG, "notifyCharacteristicWriteRequest");
+        }
+        Intent intent = new Intent(INTENT_WAIT_WRITE_ENCRYPTED_CHARACTERISTIC);
+        sendBroadcast(intent);
+        resetValues();
+    }
+
+    private void notifyCharacteristicReadRequest() {
+        if (DEBUG) {
+            Log.d(TAG, "notifyCharacteristicReadRequest");
+        }
+        Intent intent = new Intent(INTENT_WAIT_READ_ENCRYPTED_CHARACTERISTIC);
+        sendBroadcast(intent);
+        resetValues();
+    }
+
+    private void notifyDescriptorWriteRequest() {
+        if (DEBUG) {
+            Log.d(TAG, "notifyDescriptorWriteRequest");
+        }
+        Intent intent = new Intent(INTENT_WAIT_WRITE_ENCRYPTED_DESCRIPTOR);
+        sendBroadcast(intent);
+        resetValues();
+    }
+
+    private void notifyDescriptorReadRequest() {
+        if (DEBUG) {
+            Log.d(TAG, "notifyDescriptorReadRequest");
+        }
+        Intent intent = new Intent(INTENT_WAIT_READ_ENCRYPTED_DESCRIPTOR);
+        sendBroadcast(intent);
+        resetValues();
+    }
+
+    private BluetoothGattService createService() {
+        BluetoothGattService service =
+                new BluetoothGattService(SERVICE_UUID, BluetoothGattService.SERVICE_TYPE_PRIMARY);
+        // add characteristic to service
+        //   property: 0x0A (read, write)
+        //   permission: 0x11 (read, write)
+        BluetoothGattCharacteristic characteristic =
+                new BluetoothGattCharacteristic(CHARACTERISTIC_UUID, 0x0A, 0x11);
+
+        BluetoothGattDescriptor descriptor = new BluetoothGattDescriptor(DESCRIPTOR_UUID, 0x11);
+        characteristic.addDescriptor(descriptor);
+
+        // Encrypted Descriptor
+        descriptor = new BluetoothGattDescriptor(DESCRIPTOR_ENCRYPTED_READ_UUID, 0x02);
+        characteristic.addDescriptor(descriptor);
+        descriptor = new BluetoothGattDescriptor(DESCRIPTOR_ENCRYPTED_WRITE_UUID, 0x20);
+        characteristic.addDescriptor(descriptor);
+        service.addCharacteristic(characteristic);
+
+        // Encrypted Characteristic
+        characteristic = new BluetoothGattCharacteristic(CHARACTERISTIC_ENCRYPTED_READ_UUID, 0x0A, 0x02);
+        descriptor = new BluetoothGattDescriptor(DESCRIPTOR_UUID, 0x11);
+        characteristic.addDescriptor(descriptor);
+        service.addCharacteristic(characteristic);
+        characteristic = new BluetoothGattCharacteristic(CHARACTERISTIC_ENCRYPTED_WRITE_UUID, 0x0A, 0x20);
+        descriptor = new BluetoothGattDescriptor(DESCRIPTOR_UUID, 0x11);
+        characteristic.addDescriptor(descriptor);
+        service.addCharacteristic(characteristic);
+
+        return service;
+    }
+
+    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;
+                    notifyConnected();
+                } else if (status == BluetoothProfile.STATE_DISCONNECTED) {
+                    notifyDisconnected();
+                    mDevice = null;
+                    mTarget = null;
+                }
+            }
+        }
+
+        @Override
+        public void onServiceAdded(int status, BluetoothGattService service) {
+            if (DEBUG) {
+                Log.d(TAG, "onServiceAdded()");
+            }
+            if (status == BluetoothGatt.GATT_SUCCESS) {
+                notifyServiceAdded();
+            }
+        }
+
+        String mPriority = null;
+
+        @Override
+        public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId,
+                                                 BluetoothGattCharacteristic characteristic,
+                                                 boolean preparedWrite, boolean responseNeeded,
+                                                 int offset, byte[] value) {
+            int status = BluetoothGatt.GATT_SUCCESS;
+            if (mGattServer == null) {
+                if (DEBUG) {
+                    Log.d(TAG, "GattServer is null, return");
+                }
+                return;
+            }
+            if (DEBUG) {
+                Log.d(TAG, "onCharacteristicWriteRequest: preparedWrite=" + preparedWrite);
+            }
+            if (characteristic.getUuid().equals(CHARACTERISTIC_ENCRYPTED_WRITE_UUID)) {
+                if (mSecure) {
+                    characteristic.setValue(value);
+                    if (Arrays.equals(BleEncryptedClientService.WRITE_VALUE.getBytes(), characteristic.getValue())) {
+                        notifyCharacteristicWriteRequest();
+                    } else {
+                        status = BluetoothGatt.GATT_FAILURE;
+                    }
+                } else {
+                    // will not occur
+                    status = BluetoothGatt.GATT_FAILURE;
+                }
+            } else if (characteristic.getUuid().equals(CHARACTERISTIC_UUID)) {
+                mTarget = new String(value);
+                characteristic.setValue(value);
+            }
+
+            if (responseNeeded) {
+                mGattServer.sendResponse(device, requestId, status, offset, value);
+            }
+        }
+
+        @Override
+        public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattCharacteristic characteristic) {
+            int status = BluetoothGatt.GATT_SUCCESS;
+            if (mGattServer == null) {
+                if (DEBUG) {
+                    Log.d(TAG, "GattServer is null, return");
+                }
+                return;
+            }
+            if (DEBUG) {
+                Log.d(TAG, "onCharacteristicReadRequest()");
+            }
+            if (characteristic.getUuid().equals(CHARACTERISTIC_ENCRYPTED_READ_UUID)) {
+                if (mSecure) {
+                    notifyCharacteristicReadRequest();
+                }
+            }
+            mGattServer.sendResponse(device, requestId, status, offset, characteristic.getValue());
+        }
+
+        @Override
+        public void onDescriptorReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattDescriptor descriptor) {
+            int status = BluetoothGatt.GATT_SUCCESS;
+            if (mGattServer == null) {
+                if (DEBUG) {
+                    Log.d(TAG, "GattServer is null, return");
+                }
+                return;
+            }
+            if (DEBUG) {
+                Log.d(TAG, "onDescriptorReadRequest():");
+            }
+
+            if (descriptor.getUuid().equals(DESCRIPTOR_ENCRYPTED_READ_UUID)) {
+                if (mSecure) {
+                    notifyDescriptorReadRequest();
+                }
+            }
+            Log.d(TAG, "  status = " + status);
+            mGattServer.sendResponse(device, requestId, status, offset, descriptor.getValue());
+        }
+
+        @Override
+        public void onDescriptorWriteRequest(BluetoothDevice device, int requestId, BluetoothGattDescriptor descriptor, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {
+            int status = BluetoothGatt.GATT_SUCCESS;
+            if (mGattServer == null) {
+                if (DEBUG) {
+                    Log.d(TAG, "GattServer is null, return");
+                }
+                return;
+            }
+
+            if (DEBUG) {
+                Log.d(TAG, "onDescriptorWriteRequest: preparedWrite=" + preparedWrite + ", responseNeeded= " + responseNeeded);
+            }
+
+            if (descriptor.getUuid().equals(DESCRIPTOR_ENCRYPTED_WRITE_UUID)) {
+                if (mSecure) {
+                    descriptor.setValue(value);
+                    if (Arrays.equals(BleEncryptedClientService.WRITE_VALUE.getBytes(), descriptor.getValue())) {
+                        notifyDescriptorWriteRequest();
+                    } else {
+                        status = BluetoothGatt.GATT_FAILURE;
+                    }
+                } else {
+                    // will not occur
+                    status = BluetoothGatt.GATT_FAILURE;
+                }
+            }
+
+            if (responseNeeded) {
+                mGattServer.sendResponse(device, requestId, status, offset, value);
+            }
+        }
+    };
+
+    private final AdvertiseCallback mAdvertiseCallback = new AdvertiseCallback() {
+        @Override
+        public void onStartFailure(int errorCode) {
+            super.onStartFailure(errorCode);
+            if (errorCode == ADVERTISE_FAILED_FEATURE_UNSUPPORTED) {
+                notifyAdvertiseUnsupported();
+            } else {
+                notifyOpenFail();
+            }
+        }
+    };
+
+    private void startAdvertise() {
+        if (DEBUG) {
+            Log.d(TAG, "startAdvertise");
+        }
+        AdvertiseData data = new AdvertiseData.Builder()
+                .addServiceData(new ParcelUuid(ADV_SERVICE_UUID), new byte[]{1, 2, 3})
+                .addServiceUuid(new ParcelUuid(ADV_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);
+        }
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleInsecureClientStartActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleInsecureClientStartActivity.java
new file mode 100644
index 0000000..03256fb
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleInsecureClientStartActivity.java
@@ -0,0 +1,39 @@
+/*

+ * Copyright (C) 2016 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.content.Intent;

+import android.os.Bundle;

+

+public class BleInsecureClientStartActivity extends BleClientTestBaseActivity {

+    private Intent mIntent;

+

+    @Override

+    public void onCreate(Bundle savedInstanceState) {

+        super.onCreate(savedInstanceState);

+        mIntent = new Intent(this, BleClientService.class);

+        mIntent.setAction(BleClientService.BLE_CLIENT_ACTION_CLIENT_CONNECT);

+

+        startService(mIntent);

+    }

+

+    @Override

+    public void onDestroy() {

+        super.onDestroy();

+        stopService(mIntent);

+    }

+}

diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleInsecureClientTestListActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleInsecureClientTestListActivity.java
new file mode 100644
index 0000000..f058602
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleInsecureClientTestListActivity.java
@@ -0,0 +1,50 @@
+/*

+ * Copyright (C) 2016 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.bluetooth.BluetoothAdapter;

+import android.os.Bundle;

+

+import com.android.cts.verifier.ManifestTestListAdapter;

+import com.android.cts.verifier.PassFailButtons;

+import com.android.cts.verifier.R;

+

+import java.util.ArrayList;

+import java.util.List;

+

+public class BleInsecureClientTestListActivity extends PassFailButtons.TestListActivity {

+

+    @Override

+    protected void onCreate(Bundle savedInstanceState) {

+        super.onCreate(savedInstanceState);

+        setContentView(R.layout.pass_fail_list);

+        setPassFailButtonClickListeners();

+        setInfoResources(R.string.ble_insecure_client_test_list_name,

+                R.string.ble_insecure_client_test_list_info,

+                -1);

+

+        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();

+        List<String> disabledTest = new ArrayList<String>();

+        if (adapter == null || !adapter.isOffloadedFilteringSupported()) {

+            disabledTest.add(

+                    "com.android.cts.verifier.bluetooth.BleAdvertiserHardwareScanFilterActivity.");

+        }

+

+        setTestListAdapter(new ManifestTestListAdapter(this, getClass().getName(),

+                disabledTest.toArray(new String[disabledTest.size()])));

+    }

+}

diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleInsecureConnectionPriorityClientTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleInsecureConnectionPriorityClientTestActivity.java
new file mode 100644
index 0000000..cbb9af5
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleInsecureConnectionPriorityClientTestActivity.java
@@ -0,0 +1,37 @@
+/*

+ * Copyright (C) 2016 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.content.Intent;

+import android.os.Bundle;

+

+public class BleInsecureConnectionPriorityClientTestActivity extends BleConnectionPriorityClientBaseActivity {

+

+    @Override

+    protected void onCreate(Bundle savedInstanceState) {

+        super.onCreate(savedInstanceState);

+        Intent intent = new Intent(BleInsecureConnectionPriorityClientTestActivity.this,

+                BleConnectionPriorityClientService.class);

+        startService(intent);

+    }

+

+    @Override

+    public void onDestroy() {

+        super.onDestroy();

+        stopService(new Intent(this, BleConnectionPriorityClientService.class));

+    }

+}

diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleInsecureConnectionPriorityServerTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleInsecureConnectionPriorityServerTestActivity.java
new file mode 100644
index 0000000..e95fda5
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleInsecureConnectionPriorityServerTestActivity.java
@@ -0,0 +1,27 @@
+/*

+ * Copyright (C) 2016 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.os.Bundle;

+

+public class BleInsecureConnectionPriorityServerTestActivity extends BleConnectionPriorityServerBaseActivity {

+

+    @Override

+    protected void onCreate(Bundle savedInstanceState) {

+        super.onCreate(savedInstanceState);

+    }

+}

diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleInsecureEncryptedClientTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleInsecureEncryptedClientTestActivity.java
new file mode 100644
index 0000000..f6f467d
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleInsecureEncryptedClientTestActivity.java
@@ -0,0 +1,38 @@
+/*

+ * Copyright (C) 2016 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.content.Intent;

+import android.os.Bundle;

+

+public class BleInsecureEncryptedClientTestActivity extends BleEncryptedClientBaseActivity {

+    private Intent mIntent;

+

+    @Override

+    protected void onCreate(Bundle savedInstanceState) {

+        super.onCreate(savedInstanceState);

+        mIntent =  new Intent(this, BleEncryptedClientService.class);

+        mIntent.setAction(BleEncryptedClientService.ACTION_CONNECT_WITHOUT_SECURE);

+        startService(mIntent);

+    }

+

+    @Override

+    public void onDestroy() {

+        super.onDestroy();

+        stopService(mIntent);

+    }

+}

diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleInsecureEncryptedServerTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleInsecureEncryptedServerTestActivity.java
new file mode 100644
index 0000000..64bb71c
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleInsecureEncryptedServerTestActivity.java
@@ -0,0 +1,127 @@
+/*

+ * Copyright (C) 2016 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.AlertDialog;

+import android.app.Dialog;

+import android.content.BroadcastReceiver;

+import android.content.Context;

+import android.content.DialogInterface;

+import android.content.Intent;

+import android.content.IntentFilter;

+import android.os.Bundle;

+import android.widget.Toast;

+

+import com.android.cts.verifier.PassFailButtons;

+import com.android.cts.verifier.R;

+

+public class BleInsecureEncryptedServerTestActivity extends PassFailButtons.Activity {

+    private Intent mIntent;

+

+    @Override

+    protected void onCreate(Bundle savedInstanceState) {

+        super.onCreate(savedInstanceState);

+

+        setContentView(R.layout.ble_insecure_encrypted_server_test);

+        setPassFailButtonClickListeners();

+        setInfoResources(R.string.ble_encrypted_server_name,

+                R.string.ble_encrypted_server_info, -1);

+

+        getPassButton().setEnabled(true);

+

+        mIntent =  new Intent(this, BleEncryptedServerService.class);

+        mIntent.setAction(BleEncryptedServerService.ACTION_CONNECT_WITHOUT_SECURE);

+

+        startService(mIntent);

+    }

+

+    @Override

+    public void onResume() {

+        super.onResume();

+

+        IntentFilter filter = new IntentFilter();

+        filter.addAction(BleEncryptedServerService.INTENT_BLUETOOTH_DISABLED);

+        filter.addAction(BleServerService.BLE_OPEN_FAIL);

+        filter.addAction(BleServerService.BLE_ADVERTISE_UNSUPPORTED);

+        registerReceiver(mBroadcast, filter);

+    }

+

+    @Override

+    public void onPause() {

+        super.onPause();

+        unregisterReceiver(mBroadcast);

+    }

+

+    @Override

+    public void onDestroy() {

+        super.onDestroy();

+        stopService(mIntent);

+    }

+

+    private void showErrorDialog(int titleId, int messageId, boolean finish) {

+        AlertDialog.Builder builder = new AlertDialog.Builder(this)

+                .setTitle(titleId)

+                .setMessage(messageId);

+        if (finish) {

+            builder.setOnCancelListener(new Dialog.OnCancelListener() {

+                @Override

+                public void onCancel(DialogInterface dialog) {

+                    finish();

+                }

+            });

+        }

+        builder.create().show();

+    }

+

+    private BroadcastReceiver mBroadcast = new BroadcastReceiver() {

+        @Override

+        public void onReceive(Context context, Intent intent) {

+            String action = intent.getAction();

+            switch (action) {

+            case BleEncryptedServerService.INTENT_BLUETOOTH_DISABLED:

+                // show message to turn on Bluetooth

+                new AlertDialog.Builder(context)

+                        .setTitle(R.string.ble_bluetooth_disable_title)

+                        .setMessage(R.string.ble_bluetooth_disable_message)

+                        .setOnCancelListener(new Dialog.OnCancelListener() {

+                            @Override

+                            public void onCancel(DialogInterface dialog) {

+                                finish();

+                            }

+                        })

+                        .create().show();

+                break;

+            case BleServerService.BLE_ADVERTISE_UNSUPPORTED:

+                showErrorDialog(R.string.bt_advertise_unsupported_title,

+                        R.string.bt_advertise_unsupported_message,

+                        true);

+                break;

+            case BleServerService.BLE_OPEN_FAIL:

+                setTestResultAndFinish(false);

+                runOnUiThread(new Runnable() {

+                    @Override

+                    public void run() {

+                        Toast.makeText(BleInsecureEncryptedServerTestActivity.this,

+                                R.string.bt_open_failed_message,

+                                Toast.LENGTH_SHORT).show();

+                    }

+                });

+                break;

+            }

+        }

+    };

+}
\ No newline at end of file
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleInsecureServerAdvertiserPowerLevelActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleInsecureServerAdvertiserPowerLevelActivity.java
new file mode 100644
index 0000000..1191bba
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleInsecureServerAdvertiserPowerLevelActivity.java
@@ -0,0 +1,11 @@
+package com.android.cts.verifier.bluetooth;

+

+import android.os.Bundle;

+

+public class BleInsecureServerAdvertiserPowerLevelActivity extends BleAdvertiserPowerLevelActivity {

+

+    @Override

+    public void onCreate(Bundle savedInstanceState) {

+        super.onCreate(savedInstanceState);

+    }

+}

diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleInsecureServerAdvertiserTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleInsecureServerAdvertiserTestActivity.java
new file mode 100644
index 0000000..2005ef2
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleInsecureServerAdvertiserTestActivity.java
@@ -0,0 +1,11 @@
+package com.android.cts.verifier.bluetooth;

+

+import android.os.Bundle;

+

+public class BleInsecureServerAdvertiserTestActivity extends BleAdvertiserTestActivity {

+

+    @Override

+    public void onCreate(Bundle savedInstanceState) {

+        super.onCreate(savedInstanceState);

+    }

+}

diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleInsecureServerScannerPowerLevelActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleInsecureServerScannerPowerLevelActivity.java
new file mode 100644
index 0000000..e3f3f86
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleInsecureServerScannerPowerLevelActivity.java
@@ -0,0 +1,11 @@
+package com.android.cts.verifier.bluetooth;

+

+import android.os.Bundle;

+

+public class BleInsecureServerScannerPowerLevelActivity extends BleScannerPowerLevelActivity {

+

+    @Override

+    public void onCreate(Bundle savedInstanceState) {

+        super.onCreate(savedInstanceState);

+    }

+}

diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleInsecureServerScannerTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleInsecureServerScannerTestActivity.java
new file mode 100644
index 0000000..e1376f4
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleInsecureServerScannerTestActivity.java
@@ -0,0 +1,11 @@
+package com.android.cts.verifier.bluetooth;

+

+import android.os.Bundle;

+

+public class BleInsecureServerScannerTestActivity extends BleScannerTestActivity {

+

+    @Override

+    public void onCreate(Bundle savedInstanceState) {

+        super.onCreate(savedInstanceState);

+    }

+}

diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleInsecureServerStartActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleInsecureServerStartActivity.java
new file mode 100644
index 0000000..63d1bb5
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleInsecureServerStartActivity.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2016 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.content.Intent;
+import android.os.Bundle;
+
+public class BleInsecureServerStartActivity extends BleServerTestBaseActivity {
+    private Intent mIntent;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        mIntent = new Intent(this, BleServerService.class);
+        mIntent.setAction(BleServerService.BLE_ACTION_SERVER_NON_SECURE);
+        startService(mIntent);
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        stopService(mIntent);
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleInsecureServerTestListActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleInsecureServerTestListActivity.java
new file mode 100644
index 0000000..533e756
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleInsecureServerTestListActivity.java
@@ -0,0 +1,48 @@
+/*

+ * Copyright (C) 2016 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.bluetooth.BluetoothAdapter;

+import android.os.Bundle;

+

+import com.android.cts.verifier.ManifestTestListAdapter;

+import com.android.cts.verifier.PassFailButtons;

+import com.android.cts.verifier.R;

+

+import java.util.ArrayList;

+import java.util.List;

+

+public class BleInsecureServerTestListActivity extends PassFailButtons.TestListActivity {

+

+    @Override

+    protected void onCreate(Bundle savedInstanceState) {

+        super.onCreate(savedInstanceState);

+        setContentView(R.layout.pass_fail_list);

+        setPassFailButtonClickListeners();

+        setInfoResources(R.string.ble_insecure_server_test_list_name, R.string.ble_insecure_server_test_list_info, -1);

+

+        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();

+        List<String> disabledTest = new ArrayList<String>();

+        if (adapter == null || !adapter.isOffloadedFilteringSupported()) {

+            disabledTest.add(

+                    "com.android.cts.verifier.bluetooth.BleAdvertiserHardwareScanFilterActivity.");

+        }

+

+        setTestListAdapter(new ManifestTestListAdapter(this, getClass().getName(),

+                disabledTest.toArray(new String[disabledTest.size()])));

+    }

+}

diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleScannerPowerLevelActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleScannerPowerLevelActivity.java
index bf3484e..b2c6c60 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleScannerPowerLevelActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleScannerPowerLevelActivity.java
@@ -29,6 +29,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.graphics.Color;
 import android.os.Bundle;
 import android.os.CountDownTimer;
 import android.util.Log;
@@ -72,7 +73,7 @@
 
             @Override
             public void onFinish() {
-                mTimerText.setTextColor(getResources().getColor(R.color.red));
+                mTimerText.setTextColor(Color.RED);
                 mTimerText.setText("Time is up!");
             }
         };
@@ -188,7 +189,7 @@
                 case BleScannerService.BLE_PRIVACY_NEW_MAC_RECEIVE:
                      Toast.makeText(context, "New MAC address detected", Toast.LENGTH_SHORT)
                             .show();
-                     mTimerText.setTextColor(getResources().getColor(R.color.green));
+                     mTimerText.setTextColor(Color.GREEN);
                      mTimerText.append("   Get new MAC address.");
                      mTimer.cancel();
                      getPassButton().setEnabled(true);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleScannerService.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleScannerService.java
index eb71164..2bcd86a 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleScannerService.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleScannerService.java
@@ -23,9 +23,9 @@
 import android.bluetooth.le.BluetoothLeScanner;
 import android.bluetooth.le.ScanCallback;
 import android.bluetooth.le.ScanFilter;
-import android.bluetooth.le.ScanSettings;
 import android.bluetooth.le.ScanRecord;
 import android.bluetooth.le.ScanResult;
+import android.bluetooth.le.ScanSettings;
 import android.content.Context;
 import android.content.Intent;
 import android.os.Handler;
@@ -34,11 +34,9 @@
 import android.util.Log;
 import android.widget.Toast;
 
-import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
-import java.util.UUID;
 
 public class BleScannerService extends Service {
 
@@ -144,7 +142,9 @@
     @Override
     public void onDestroy() {
         super.onDestroy();
-        mScanner.stopScan(mCallback);
+        if (mScanner != null) {
+            mScanner.stopScan(mCallback);
+        }
     }
 
     private void showMessage(final String msg) {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleScannerTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleScannerTestActivity.java
index 52933e0..20cea88 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleScannerTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleScannerTestActivity.java
@@ -16,13 +16,16 @@
 
 package com.android.cts.verifier.bluetooth;
 
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.bluetooth.BluetoothAdapter;
+import android.content.DialogInterface;
+import android.os.Bundle;
+
 import com.android.cts.verifier.ManifestTestListAdapter;
 import com.android.cts.verifier.PassFailButtons;
 import com.android.cts.verifier.R;
 
-import android.bluetooth.BluetoothAdapter;
-import android.os.Bundle;
-
 import java.util.ArrayList;
 import java.util.List;
 
@@ -44,5 +47,18 @@
 
         setTestListAdapter(new ManifestTestListAdapter(this, getClass().getName(),
                 disabledTest.toArray(new String[disabledTest.size()])));
+
+        if (!adapter.isEnabled()) {
+            new AlertDialog.Builder(this)
+                    .setTitle(R.string.ble_bluetooth_disable_title)
+                    .setMessage(R.string.ble_bluetooth_disable_message)
+                    .setOnCancelListener(new Dialog.OnCancelListener() {
+                        @Override
+                        public void onCancel(DialogInterface dialog) {
+                            finish();
+                        }
+                    })
+                    .create().show();
+        }
     }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleSecureClientStartActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleSecureClientStartActivity.java
new file mode 100644
index 0000000..72d6e56
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleSecureClientStartActivity.java
@@ -0,0 +1,50 @@
+/*

+ * Copyright (C) 2016 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.content.Intent;

+import android.os.Build;

+import android.os.Bundle;

+

+import com.android.cts.verifier.R;

+

+public class BleSecureClientStartActivity extends BleClientTestBaseActivity {

+    private Intent mIntent;

+

+    @Override

+    public void onCreate(Bundle savedInstanceState) {

+        super.onCreate(savedInstanceState);

+        setInfoResources(R.string.ble_client_test_name,

+                R.string.ble_secure_client_test_info, -1);

+

+        mIntent = new Intent(this, BleClientService.class);

+        mIntent.setAction(BleClientService.BLE_CLIENT_ACTION_CLIENT_CONNECT_SECURE);

+

+        startService(mIntent);

+    }

+

+    @Override

+    public void onDestroy() {

+        super.onDestroy();

+        stopService(mIntent);

+    }

+

+    @Override

+    public boolean shouldRebootBluetoothAfterTest() {

+        return (Build.VERSION.SDK_INT > Build.VERSION_CODES.M);

+    }

+}

diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleSecureClientTestListActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleSecureClientTestListActivity.java
new file mode 100644
index 0000000..54f8ad1
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleSecureClientTestListActivity.java
@@ -0,0 +1,48 @@
+/*

+ * Copyright (C) 2016 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.bluetooth.BluetoothAdapter;

+import android.os.Bundle;

+

+import com.android.cts.verifier.ManifestTestListAdapter;

+import com.android.cts.verifier.PassFailButtons;

+import com.android.cts.verifier.R;

+

+import java.util.ArrayList;

+import java.util.List;

+

+public class BleSecureClientTestListActivity extends PassFailButtons.TestListActivity {

+

+    @Override

+    protected void onCreate(Bundle savedInstanceState) {

+        super.onCreate(savedInstanceState);

+        setContentView(R.layout.pass_fail_list);

+        setPassFailButtonClickListeners();

+        setInfoResources(R.string.ble_secure_client_test_list_name, R.string.ble_secure_client_test_list_info, -1);

+

+        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();

+        List<String> disabledTest = new ArrayList<String>();

+        if (adapter == null || !adapter.isOffloadedFilteringSupported()) {

+            disabledTest.add(

+                    "com.android.cts.verifier.bluetooth.BleAdvertiserHardwareScanFilterActivity.");

+        }

+

+        setTestListAdapter(new ManifestTestListAdapter(this, getClass().getName(),

+                disabledTest.toArray(new String[disabledTest.size()])));

+    }

+}

diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleSecureConnectionPriorityClientTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleSecureConnectionPriorityClientTestActivity.java
new file mode 100644
index 0000000..00eef49
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleSecureConnectionPriorityClientTestActivity.java
@@ -0,0 +1,44 @@
+/*

+ * Copyright (C) 2016 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.content.Intent;

+import android.os.Build;

+import android.os.Bundle;

+

+public class BleSecureConnectionPriorityClientTestActivity extends BleConnectionPriorityClientBaseActivity {

+    private Intent mIntent;

+

+    @Override

+    protected void onCreate(Bundle savedInstanceState) {

+        super.onCreate(savedInstanceState);

+        mIntent = new Intent(BleSecureConnectionPriorityClientTestActivity.this, BleConnectionPriorityClientService.class);

+        mIntent.setAction(BleConnectionPriorityClientService.ACTION_CLIENT_CONNECT_SECURE);

+        startService(mIntent);

+    }

+

+    @Override

+    public void onDestroy() {

+        super.onDestroy();

+        stopService(mIntent);

+    }

+

+    @Override

+    public boolean shouldRebootBluetoothAfterTest() {

+        return (Build.VERSION.SDK_INT > Build.VERSION_CODES.M);

+    }

+}

diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleSecureConnectionPriorityServerTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleSecureConnectionPriorityServerTestActivity.java
new file mode 100644
index 0000000..e64d6f6
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleSecureConnectionPriorityServerTestActivity.java
@@ -0,0 +1,27 @@
+/*

+ * Copyright (C) 2016 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.os.Bundle;

+

+public class BleSecureConnectionPriorityServerTestActivity extends BleConnectionPriorityServerBaseActivity {

+

+    @Override

+    protected void onCreate(Bundle savedInstanceState) {

+        super.onCreate(savedInstanceState);

+    }

+}

diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleSecureEncryptedClientTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleSecureEncryptedClientTestActivity.java
new file mode 100644
index 0000000..83a747c
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleSecureEncryptedClientTestActivity.java
@@ -0,0 +1,49 @@
+/*

+ * Copyright (C) 2016 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.content.Intent;

+import android.os.Build;

+import android.os.Bundle;

+

+public class BleSecureEncryptedClientTestActivity extends BleEncryptedClientBaseActivity {

+    private Intent mIntent;

+

+    @Override

+    protected void onCreate(Bundle savedInstanceState) {

+        super.onCreate(savedInstanceState);

+        mIntent =  new Intent(this, BleEncryptedClientService.class);

+        mIntent.setAction(BleEncryptedClientService.ACTION_CONNECT_WITH_SECURE);

+        startService(mIntent);

+    }

+

+    @Override

+    public void onDestroy() {

+        super.onDestroy();

+        stopService(mIntent);

+    }

+

+    @Override

+    public boolean shouldRebootBluetoothAfterTest() {

+        return (Build.VERSION.SDK_INT > Build.VERSION_CODES.M);

+    }

+

+    @Override

+    public boolean isSecure() {

+        return true;

+    }

+}

diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleSecureEncryptedServerTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleSecureEncryptedServerTestActivity.java
new file mode 100644
index 0000000..58fbc18
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleSecureEncryptedServerTestActivity.java
@@ -0,0 +1,38 @@
+/*

+ * Copyright (C) 2016 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.content.Intent;

+import android.os.Bundle;

+

+public class BleSecureEncryptedServerTestActivity extends BleEncryptedServerBaseActivity {

+    private Intent mIntent;

+

+    @Override

+    protected void onCreate(Bundle savedInstanceState) {

+        super.onCreate(savedInstanceState);

+        mIntent =  new Intent(this, BleEncryptedServerService.class);

+        mIntent.setAction(BleEncryptedServerService.ACTION_CONNECT_WITH_SECURE);

+        startService(mIntent);

+    }

+

+    @Override

+    public void onDestroy() {

+        super.onDestroy();

+        stopService(mIntent);

+    }

+}
\ No newline at end of file
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleSecureServerAdvertiserPowerLevelActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleSecureServerAdvertiserPowerLevelActivity.java
new file mode 100644
index 0000000..f131932
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleSecureServerAdvertiserPowerLevelActivity.java
@@ -0,0 +1,11 @@
+package com.android.cts.verifier.bluetooth;

+

+import android.os.Bundle;

+

+public class BleSecureServerAdvertiserPowerLevelActivity extends BleAdvertiserPowerLevelActivity {

+

+    @Override

+    public void onCreate(Bundle savedInstanceState) {

+        super.onCreate(savedInstanceState);

+    }

+}

diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleSecureServerAdvertiserTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleSecureServerAdvertiserTestActivity.java
new file mode 100644
index 0000000..5fff2e1
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleSecureServerAdvertiserTestActivity.java
@@ -0,0 +1,11 @@
+package com.android.cts.verifier.bluetooth;

+

+import android.os.Bundle;

+

+public class BleSecureServerAdvertiserTestActivity extends BleAdvertiserTestActivity {

+

+    @Override

+    public void onCreate(Bundle savedInstanceState) {

+        super.onCreate(savedInstanceState);

+    }

+}

diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleSecureServerScannerPowerLevelActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleSecureServerScannerPowerLevelActivity.java
new file mode 100644
index 0000000..a4f29fc
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleSecureServerScannerPowerLevelActivity.java
@@ -0,0 +1,11 @@
+package com.android.cts.verifier.bluetooth;

+

+import android.os.Bundle;

+

+public class BleSecureServerScannerPowerLevelActivity extends BleScannerPowerLevelActivity {

+

+    @Override

+    public void onCreate(Bundle savedInstanceState) {

+        super.onCreate(savedInstanceState);

+    }

+}

diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleSecureServerScannerTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleSecureServerScannerTestActivity.java
new file mode 100644
index 0000000..4f38a27
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleSecureServerScannerTestActivity.java
@@ -0,0 +1,11 @@
+package com.android.cts.verifier.bluetooth;

+

+import android.os.Bundle;

+

+public class BleSecureServerScannerTestActivity extends BleScannerTestActivity {

+

+    @Override

+    public void onCreate(Bundle savedInstanceState) {

+        super.onCreate(savedInstanceState);

+    }

+}

diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleSecureServerStartActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleSecureServerStartActivity.java
new file mode 100644
index 0000000..620ade3
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleSecureServerStartActivity.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2016 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.content.Intent;
+import android.os.Bundle;
+
+public class BleSecureServerStartActivity extends BleServerTestBaseActivity {
+    private Intent mIntent;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        mIntent = new Intent(this, BleServerService.class);
+        mIntent.setAction(BleServerService.BLE_ACTION_SERVER_SECURE);
+        startService(mIntent);
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        stopService(mIntent);
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleSecureServerTestListActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleSecureServerTestListActivity.java
new file mode 100644
index 0000000..06d6dab
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleSecureServerTestListActivity.java
@@ -0,0 +1,48 @@
+/*

+ * Copyright (C) 2016 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.bluetooth.BluetoothAdapter;

+import android.os.Bundle;

+

+import com.android.cts.verifier.ManifestTestListAdapter;

+import com.android.cts.verifier.PassFailButtons;

+import com.android.cts.verifier.R;

+

+import java.util.ArrayList;

+import java.util.List;

+

+public class BleSecureServerTestListActivity extends PassFailButtons.TestListActivity {

+

+    @Override

+    protected void onCreate(Bundle savedInstanceState) {

+        super.onCreate(savedInstanceState);

+        setContentView(R.layout.pass_fail_list);

+        setPassFailButtonClickListeners();

+        setInfoResources(R.string.ble_secure_server_test_list_name, R.string.ble_secure_server_test_list_info, -1);

+

+        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();

+        List<String> disabledTest = new ArrayList<String>();

+        if (adapter == null || !adapter.isOffloadedFilteringSupported()) {

+            disabledTest.add(

+                    "com.android.cts.verifier.bluetooth.BleAdvertiserHardwareScanFilterActivity.");

+        }

+

+        setTestListAdapter(new ManifestTestListAdapter(this, getClass().getName(),

+                disabledTest.toArray(new String[disabledTest.size()])));

+    }

+}

diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleServerService.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleServerService.java
index 8718f57..464761f 100755
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleServerService.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleServerService.java
@@ -16,14 +16,7 @@
 
 package com.android.cts.verifier.bluetooth;
 
-import java.util.Date;
-import java.util.List;
-import java.util.Timer;
-import java.util.TimerTask;
-import java.util.UUID;
-
 import android.app.Service;
-import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothGatt;
 import android.bluetooth.BluetoothGattCharacteristic;
@@ -39,12 +32,24 @@
 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.ParcelUuid;
 import android.util.Log;
 import android.widget.Toast;
 
+import com.android.cts.verifier.R;
+
+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 BleServerService extends Service {
 
     public static final boolean DEBUG = true;
@@ -54,29 +59,73 @@
     public static final int COMMAND_WRITE_CHARACTERISTIC = 1;
     public static final int COMMAND_WRITE_DESCRIPTOR = 2;
 
+    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_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_SERVER_CONNECTED =
             "com.android.cts.verifier.bluetooth.BLE_SERVER_CONNECTED";
     public static final String BLE_SERVER_DISCONNECTED =
             "com.android.cts.verifier.bluetooth.BLE_SERVER_DISCONNECTED";
     public static final String BLE_SERVICE_ADDED =
             "com.android.cts.verifier.bluetooth.BLE_SERVICE_ADDED";
+    public static final String BLE_MTU_REQUEST_23BYTES =
+            "com.android.cts.verifier.bluetooth.BLE_MTU_REQUEST_23BYTES";
+    public static final String BLE_MTU_REQUEST_512BYTES =
+            "com.android.cts.verifier.bluetooth.BLE_MTU_REQUEST_512BYTES";
     public static final String BLE_CHARACTERISTIC_READ_REQUEST =
             "com.android.cts.verifier.bluetooth.BLE_CHARACTERISTIC_READ_REQUEST";
     public static final String BLE_CHARACTERISTIC_WRITE_REQUEST =
             "com.android.cts.verifier.bluetooth.BLE_CHARACTERISTIC_WRITE_REQUEST";
+    public static final String BLE_CHARACTERISTIC_READ_REQUEST_WITHOUT_PERMISSION =
+            "com.android.cts.verifier.bluetooth.BLE_CHARACTERISTIC_READ_REQUEST_WITHOUT_PERMISSION";
+    public static final String BLE_CHARACTERISTIC_WRITE_REQUEST_WITHOUT_PERMISSION =
+            "com.android.cts.verifier.bluetooth.BLE_CHARACTERISTIC_WRITE_REQUEST_WITHOUT_PERMISSION";
+    public static final String BLE_CHARACTERISTIC_READ_REQUEST_NEED_ENCRYPTED =
+            "com.android.cts.verifier.bluetooth.BLE_CHARACTERISTIC_READ_REQUEST_NEED_ENCRYPTED";
+    public static final String BLE_CHARACTERISTIC_WRITE_REQUEST_NEED_ENCRYPTED =
+            "com.android.cts.verifier.bluetooth.BLE_CHARACTERISTIC_WRITE_REQUEST_NEED_ENCRYPTED";
+    public static final String BLE_CHARACTERISTIC_NOTIFICATION_REQUEST =
+            "com.android.cts.verifier.bluetooth.BLE_CHARACTERISTIC_NOTIFICATION_REQUEST";
+    public static final String BLE_CHARACTERISTIC_INDICATE_REQUEST =
+            "com.android.cts.verifier.bluetooth.BLE_CHARACTERISTIC_INDICATE_REQUEST";
     public static final String BLE_DESCRIPTOR_READ_REQUEST =
             "com.android.cts.verifier.bluetooth.BLE_DESCRIPTOR_READ_REQUEST";
     public static final String BLE_DESCRIPTOR_WRITE_REQUEST =
             "com.android.cts.verifier.bluetooth.BLE_DESCRIPTOR_WRITE_REQUEST";
+    public static final String BLE_DESCRIPTOR_READ_REQUEST_WITHOUT_PERMISSION =
+            "com.android.cts.verifier.bluetooth.BLE_DESCRIPTOR_READ_REQUEST_WITHOUT_PERMISSION";
+    public static final String BLE_DESCRIPTOR_WRITE_REQUEST_WITHOUT_PERMISSION =
+            "com.android.cts.verifier.bluetooth.BLE_DESCRIPTOR_WRITE_REQUEST_WITHOUT_PERMISSION";
+    public static final String BLE_DESCRIPTOR_READ_REQUEST_NEED_ENCRYPTED =
+            "com.android.cts.verifier.bluetooth.BLE_DESCRIPTOR_READ_REQUEST_NEED_ENCRYPTED";
+    public static final String BLE_DESCRIPTOR_WRITE_REQUEST_NEED_ENCRYPTED =
+            "com.android.cts.verifier.bluetooth.BLE_DESCRIPTOR_WRITE_REQUEST_NEED_ENCRYPTED";
     public static final String BLE_EXECUTE_WRITE =
             "com.android.cts.verifier.bluetooth.BLE_EXECUTE_WRITE";
     public static final String BLE_OPEN_FAIL =
             "com.android.cts.verifier.bluetooth.BLE_OPEN_FAIL";
+    public static final String BLE_RELIABLE_WRITE_BAD_RESP =
+            "com.android.cts.verifier.bluetooth.BLE_RELIABLE_WRITE_BAD_RESP";
+    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 =
@@ -84,6 +133,82 @@
     public static final UUID ADV_SERVICE_UUID=
             UUID.fromString("00003333-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 Characteristic
+    private static final UUID CHARACTERISTIC_NO_READ_UUID =
+            UUID.fromString("00009984-0000-1000-8000-00805f9b34fb");
+    private static final UUID CHARACTERISTIC_NO_WRITE_UUID =
+            UUID.fromString("00009983-0000-1000-8000-00805f9b34fb");
+    private static final UUID CHARACTERISTIC_NEED_ENCRYPTED_READ_UUID =
+            UUID.fromString("00009982-0000-1000-8000-00805f9b34fb");
+    private static final UUID CHARACTERISTIC_NEED_ENCRYPTED_WRITE_UUID =
+            UUID.fromString("00009981-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");
+
+    //  Variable for registration upper limit confirmation of Characteristic
+    private static final UUID UPDATE_CHARACTERISTIC_UUID_1 =
+            UUID.fromString("00009989-0000-1000-8000-00805f9b34fb");
+    private static final UUID UPDATE_CHARACTERISTIC_UUID_2 =
+            UUID.fromString("00009988-0000-1000-8000-00805f9b34fb");
+    private static final UUID UPDATE_CHARACTERISTIC_UUID_3 =
+            UUID.fromString("00009987-0000-1000-8000-00805f9b34fb");
+    private static final UUID UPDATE_CHARACTERISTIC_UUID_4 =
+            UUID.fromString("00009986-0000-1000-8000-00805f9b34fb");
+    private static final UUID UPDATE_CHARACTERISTIC_UUID_5 =
+            UUID.fromString("00009985-0000-1000-8000-00805f9b34fb");
+    private static final UUID UPDATE_CHARACTERISTIC_UUID_6 =
+            UUID.fromString("00009979-0000-1000-8000-00805f9b34fb");
+    private static final UUID UPDATE_CHARACTERISTIC_UUID_7 =
+            UUID.fromString("00009978-0000-1000-8000-00805f9b34fb");
+    private static final UUID UPDATE_CHARACTERISTIC_UUID_8 =
+            UUID.fromString("00009977-0000-1000-8000-00805f9b34fb");
+    private static final UUID UPDATE_CHARACTERISTIC_UUID_9 =
+            UUID.fromString("00009976-0000-1000-8000-00805f9b34fb");
+    private static final UUID UPDATE_CHARACTERISTIC_UUID_10 =
+            UUID.fromString("00009975-0000-1000-8000-00805f9b34fb");
+    private static final UUID UPDATE_CHARACTERISTIC_UUID_11 =
+            UUID.fromString("00009959-0000-1000-8000-00805f9b34fb");
+    private static final UUID UPDATE_CHARACTERISTIC_UUID_12 =
+            UUID.fromString("00009958-0000-1000-8000-00805f9b34fb");
+    private static final UUID UPDATE_CHARACTERISTIC_UUID_13 =
+            UUID.fromString("00009957-0000-1000-8000-00805f9b34fb");
+    private static final UUID UPDATE_CHARACTERISTIC_UUID_14 =
+            UUID.fromString("00009956-0000-1000-8000-00805f9b34fb");
+    private static final UUID UPDATE_CHARACTERISTIC_UUID_15 =
+            UUID.fromString("00009955-0000-1000-8000-00805f9b34fb");
+
+    private static final UUID UPDATE_DESCRIPTOR_UUID =
+            UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
+
+    private static final UUID INDICATE_CHARACTERISTIC_UUID =
+            UUID.fromString("00009971-0000-1000-8000-00805f9b34fb");
+
+    private static final int CONN_INTERVAL = 150;   // connection interval 150ms
+
+    // 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;
@@ -92,6 +217,25 @@
     private Handler mHandler;
     private String mReliableWriteValue;
     private BluetoothLeAdvertiser mAdvertiser;
+    private boolean mIndicated;
+    private int mNotifyCount;
+    private boolean mSecure;
+    private int mCountMtuChange;
+    private int mMtuSize = -1;
+    private String mMtuTestReceivedData;
+    private Runnable mResetValuesTask;
+    private BluetoothGattService mAdditionalNotificationService;
+
+    // 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() {
@@ -100,22 +244,73 @@
         mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
         mAdvertiser = mBluetoothManager.getAdapter().getBluetoothLeAdvertiser();
         mGattServer = mBluetoothManager.openGattServer(this, mCallbacks);
+
         mService = createService();
-        if (mGattServer != null) {
-            mGattServer.addService(mService);
-        }
+        mAdditionalNotificationService = createAdditionalNotificationService();
+
         mDevice = null;
-        mReliableWriteValue = null;
+        mReliableWriteValue = "";
 
         mHandler = new Handler();
-        if (mGattServer == null) {
+        if (!mBluetoothManager.getAdapter().isEnabled()) {
+            notifyBluetoothDisabled();
+        } else if (mGattServer == null) {
             notifyOpenFail();
+        } else if (mAdvertiser == null) {
+            notifyAdvertiseUnsupported();
+        } else {
+            // start adding services
+            mNotifyCount = 11;
+            mSecure = false;
+            mCountMtuChange = 0;
+            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);
+    }
+
+    private void notifyMismatchInsecure() {
+        /*
+        Intent intent = new Intent(BLE_BLUETOOTH_MISMATCH_INSECURE);
+        sendBroadcast(intent);
+        */
+    }
+
     @Override
     public int onStartCommand(Intent intent, int flags, int startId) {
-        startAdvertise();
+        String action = intent.getAction();
+        if (action != null) {
+            switch (action) {
+            case BLE_ACTION_SERVER_SECURE:
+                mSecure = true;
+                if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) {
+                    showMessage("Skip MTU test.");
+                    mCountMtuChange = 1;
+                    notifyMtuRequest();
+                    mCountMtuChange = 2;
+                    notifyMtuRequest();
+                    mCountMtuChange = 0;
+                }
+                break;
+            case BLE_ACTION_SERVER_NON_SECURE:
+                mSecure = false;
+                break;
+            }
+        }
+
+        if (mBluetoothManager.getAdapter().isEnabled() && (mAdvertiser != null)) {
+            startAdvertise();
+        }
         return START_NOT_STICKY;
     }
 
@@ -127,145 +322,498 @@
     @Override
     public void onDestroy() {
         super.onDestroy();
+        cancelNotificationTaskOfSecureTestStartFailure();
         stopAdvertise();
         if (mGattServer == null) {
            return;
         }
-        if (mDevice != null) mGattServer.cancelConnection(mDevice);
+        if (mDevice != null) {
+            mGattServer.cancelConnection(mDevice);
+        }
+        mGattServer.clearServices();
         mGattServer.close();
     }
 
-    private void writeCharacteristic(String writeValue) {
-        BluetoothGattCharacteristic characteristic = getCharacteristic(CHARACTERISTIC_UUID);
-        if (characteristic != null) return;
-        characteristic.setValue(writeValue);
-    }
+    /**
+     * Sets default value to characteristic and descriptor.
+     *
+     * Set operation will be done after connection interval.
+     * (If set values immediately, multiple read/write operations may fail.)
+     */
+    private synchronized void resetValues() {
+        // cancel pending task
+        if (mResetValuesTask != null) {
+            mHandler.removeCallbacks(mResetValuesTask);
+            mResetValuesTask = null;
+        }
 
-    private void writeDescriptor(String writeValue) {
-        BluetoothGattDescriptor descriptor = getDescriptor();
-        if (descriptor == null) return;
-        descriptor.setValue(writeValue.getBytes());
+        // reserve task
+        mResetValuesTask = new Runnable() {
+            @Override
+            public void run() {
+                getCharacteristic(CHARACTERISTIC_UUID).setValue(WRITE_VALUE.getBytes());
+                getDescriptor().setValue(WRITE_VALUE.getBytes());
+            }
+        };
+        mHandler.postDelayed(mResetValuesTask, CONN_INTERVAL);
     }
 
     private void notifyOpenFail() {
-        if (DEBUG) Log.d(TAG, "notifyOpenFail");
+        if (DEBUG) {
+            Log.d(TAG, "notifyOpenFail");
+        }
         Intent intent = new Intent(BLE_OPEN_FAIL);
         sendBroadcast(intent);
     }
 
-    private void notifyConnected() {
-        if (DEBUG) Log.d(TAG, "notifyConnected");
-        Intent intent = new Intent(BLE_SERVER_CONNECTED);
+    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_SERVER_CONNECTED);
+        sendBroadcast(intent);
+
+        resetValues();
+    }
+
     private void notifyDisconnected() {
-        if (DEBUG) Log.d(TAG, "notifyDisconnected");
+        if (DEBUG) {
+            Log.d(TAG, "notifyDisconnected");
+        }
         Intent intent = new Intent(BLE_SERVER_DISCONNECTED);
         sendBroadcast(intent);
     }
 
     private void notifyServiceAdded() {
-        if (DEBUG) Log.d(TAG, "notifyServiceAdded");
+        if (DEBUG) {
+            Log.d(TAG, "notifyServiceAdded");
+        }
         Intent intent = new Intent(BLE_SERVICE_ADDED);
         sendBroadcast(intent);
     }
 
-    private void notifyCharacteristicReadRequest() {
-        if (DEBUG) Log.d(TAG, "notifyCharacteristicReadRequest");
+    private void notifyMtuRequest() {
+        if (DEBUG) {
+            Log.d(TAG, "notifyMtuRequest");
+        }
+        Intent intent;
+        if (mCountMtuChange == 1) {
+            intent = new Intent(BLE_MTU_REQUEST_23BYTES);
+        } else if (mCountMtuChange == 2) {
+            intent = new Intent(BLE_MTU_REQUEST_512BYTES);
+        } else {
+            return; // never occurs
+        }
+        sendBroadcast(intent);
+    }
+
+    private void notifyCharacteristicReadRequest(boolean resetValues) {
+        if (DEBUG) {
+            Log.d(TAG, "notifyCharacteristicReadRequest");
+        }
         Intent intent = new Intent(BLE_CHARACTERISTIC_READ_REQUEST);
         sendBroadcast(intent);
+
+        if (resetValues) {
+            resetValues();
+        }
     }
 
     private void notifyCharacteristicWriteRequest() {
-        if (DEBUG) Log.d(TAG, "notifyCharacteristicWriteRequest");
+        if (DEBUG) {
+            Log.d(TAG, "notifyCharacteristicWriteRequest");
+        }
         Intent intent = new Intent(BLE_CHARACTERISTIC_WRITE_REQUEST);
         sendBroadcast(intent);
+
+        resetValues();
+    }
+
+    private void notifyCharacteristicReadRequestWithoutPermission() {
+        if (DEBUG) {
+            Log.d(TAG, "notifyCharacteristicReadRequestWithoutPermission");
+        }
+        Intent intent = new Intent(BLE_CHARACTERISTIC_READ_REQUEST_WITHOUT_PERMISSION);
+        sendBroadcast(intent);
+
+        resetValues();
+    }
+
+    private void notifyCharacteristicWriteRequestWithoutPermission() {
+        if (DEBUG) {
+            Log.d(TAG, "notifyCharacteristicWriteRequestWithoutPermission");
+        }
+        Intent intent = new Intent(BLE_CHARACTERISTIC_WRITE_REQUEST_WITHOUT_PERMISSION);
+        sendBroadcast(intent);
+
+        resetValues();
+    }
+
+    private void notifyCharacteristicReadRequestNeedEncrypted() {
+        if (DEBUG) {
+            Log.d(TAG, "notifyCharacteristicReadRequestNeedEncrypted");
+        }
+        Intent intent = new Intent(BLE_CHARACTERISTIC_READ_REQUEST_NEED_ENCRYPTED);
+        sendBroadcast(intent);
+
+        resetValues();
+    }
+
+    private void notifyCharacteristicWriteRequestNeedEncrypted() {
+        if (DEBUG) {
+            Log.d(TAG, "notifyCharacteristicWriteRequestNeedEncrypted");
+        }
+        Intent intent = new Intent(BLE_CHARACTERISTIC_WRITE_REQUEST_NEED_ENCRYPTED);
+        sendBroadcast(intent);
+
+        resetValues();
+    }
+
+    private void notifyCharacteristicNotificationRequest() {
+        if (DEBUG) {
+            Log.d(TAG, "notifyCharacteristicNotificationRequest");
+        }
+        mNotifyCount = 11;
+        Intent intent = new Intent(BLE_CHARACTERISTIC_NOTIFICATION_REQUEST);
+        sendBroadcast(intent);
+
+        resetValues();
+    }
+
+    private void notifyCharacteristicIndicationRequest() {
+        if (DEBUG) {
+            Log.d(TAG, "notifyCharacteristicIndicationRequest");
+        }
+        Intent intent = new Intent(BLE_CHARACTERISTIC_INDICATE_REQUEST);
+        sendBroadcast(intent);
+
+        resetValues();
     }
 
     private void notifyDescriptorReadRequest() {
-        if (DEBUG) Log.d(TAG, "notifyDescriptorReadRequest");
+        if (DEBUG) {
+            Log.d(TAG, "notifyDescriptorReadRequest");
+        }
         Intent intent = new Intent(BLE_DESCRIPTOR_READ_REQUEST);
         sendBroadcast(intent);
+
+        resetValues();
     }
 
     private void notifyDescriptorWriteRequest() {
-        if (DEBUG) Log.d(TAG, "notifyDescriptorWriteRequest");
+        if (DEBUG) {
+            Log.d(TAG, "notifyDescriptorWriteRequest");
+        }
         Intent intent = new Intent(BLE_DESCRIPTOR_WRITE_REQUEST);
         sendBroadcast(intent);
+
+        resetValues();
+    }
+
+    private void notifyDescriptorReadRequestWithoutPermission() {
+        if (DEBUG) {
+            Log.d(TAG, "notifyDescriptorReadRequestWithoutPermission");
+        }
+        Intent intent = new Intent(BLE_DESCRIPTOR_READ_REQUEST_WITHOUT_PERMISSION);
+        sendBroadcast(intent);
+
+        resetValues();
+    }
+
+    private void notifyDescriptorWriteRequestWithoutPermission() {
+        if (DEBUG) {
+            Log.d(TAG, "notifyDescriptorWriteRequestWithoutPermission");
+        }
+        Intent intent = new Intent(BLE_DESCRIPTOR_WRITE_REQUEST_WITHOUT_PERMISSION);
+        sendBroadcast(intent);
+
+        resetValues();
+    }
+
+    private void notifyDescriptorReadRequestNeedEncrypted() {
+        if (DEBUG) {
+            Log.d(TAG, "notifyDescriptorReadRequestNeedEncrypted");
+        }
+        Intent intent = new Intent(BLE_DESCRIPTOR_READ_REQUEST_NEED_ENCRYPTED);
+        sendBroadcast(intent);
+
+        resetValues();
+    }
+
+    private void notifyDescriptorWriteRequestNeedEncrypted() {
+        if (DEBUG) {
+            Log.d(TAG, "notifyDescriptorWriteRequestNeedEncrypted");
+        }
+        Intent intent = new Intent(BLE_DESCRIPTOR_WRITE_REQUEST_NEED_ENCRYPTED);
+        sendBroadcast(intent);
+
+        resetValues();
     }
 
     private void notifyExecuteWrite() {
-        if (DEBUG) Log.d(TAG, "notifyExecuteWrite");
+        if (DEBUG) {
+            Log.d(TAG, "notifyExecuteWrite");
+        }
         Intent intent = new Intent(BLE_EXECUTE_WRITE);
         sendBroadcast(intent);
+
+        resetValues();
+    }
+
+    private void notifyReliableWriteBadResp() {
+        if (DEBUG) {
+            Log.d(TAG, "notifyReliableWriteBadResp");
+        }
+        Intent intent = new Intent(BLE_RELIABLE_WRITE_BAD_RESP);
+        sendBroadcast(intent);
+
+        resetValues();
     }
 
     private BluetoothGattCharacteristic getCharacteristic(UUID uuid) {
-        BluetoothGattCharacteristic characteristic =
-                mService.getCharacteristic(uuid);
+        BluetoothGattCharacteristic characteristic = mService.getCharacteristic(uuid);
         if (characteristic == null) {
             showMessage("Characteristic not found");
-            return null;
         }
         return characteristic;
     }
 
     private BluetoothGattDescriptor getDescriptor() {
-        BluetoothGattCharacteristic characteristic = getCharacteristic(CHARACTERISTIC_UUID);
-        if (characteristic == null) return null;
+        BluetoothGattDescriptor descriptor = null;
 
-        BluetoothGattDescriptor descriptor = characteristic.getDescriptor(DESCRIPTOR_UUID);
-        if (descriptor == null) {
-            showMessage("Descriptor not found");
-            return null;
+        BluetoothGattCharacteristic characteristic = getCharacteristic(CHARACTERISTIC_UUID);
+        if (characteristic != null) {
+            descriptor = characteristic.getDescriptor(DESCRIPTOR_UUID);
+            if (descriptor == null) {
+                showMessage("Descriptor not found");
+            }
         }
         return descriptor;
     }
 
+    /**
+     * Create service for notification test
+     * @return
+     */
+    private BluetoothGattService createAdditionalNotificationService() {
+        BluetoothGattService service =
+                new BluetoothGattService(SERVICE_UUID_ADDITIONAL, BluetoothGattService.SERVICE_TYPE_PRIMARY);
+
+        BluetoothGattCharacteristic notiCharacteristic =
+                new BluetoothGattCharacteristic(UPDATE_CHARACTERISTIC_UUID_1, 0x12, 0x1);
+        BluetoothGattDescriptor descriptor = new BluetoothGattDescriptor(UPDATE_DESCRIPTOR_UUID, 0x11);
+        descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
+        notiCharacteristic.addDescriptor(descriptor);
+        notiCharacteristic.setValue(NOTIFY_VALUE);
+        service.addCharacteristic(notiCharacteristic);
+
+        notiCharacteristic =
+                new BluetoothGattCharacteristic(UPDATE_CHARACTERISTIC_UUID_2, 0x14, 0x11);
+        descriptor = new BluetoothGattDescriptor(UPDATE_DESCRIPTOR_UUID, 0x11);
+        descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
+        notiCharacteristic.addDescriptor(descriptor);
+        notiCharacteristic.setValue(NOTIFY_VALUE);
+        service.addCharacteristic(notiCharacteristic);
+
+        notiCharacteristic =
+                new BluetoothGattCharacteristic(UPDATE_CHARACTERISTIC_UUID_3, 0x16, 0x11);
+        descriptor = new BluetoothGattDescriptor(UPDATE_DESCRIPTOR_UUID, 0x11);
+        descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
+        notiCharacteristic.addDescriptor(descriptor);
+        notiCharacteristic.setValue(NOTIFY_VALUE);
+        service.addCharacteristic(notiCharacteristic);
+
+        notiCharacteristic =
+                new BluetoothGattCharacteristic(UPDATE_CHARACTERISTIC_UUID_4, 0x18, 0x10);
+        descriptor = new BluetoothGattDescriptor(UPDATE_DESCRIPTOR_UUID, 0x11);
+        descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
+        notiCharacteristic.addDescriptor(descriptor);
+        notiCharacteristic.setValue(NOTIFY_VALUE);
+        service.addCharacteristic(notiCharacteristic);
+
+        notiCharacteristic =
+                new BluetoothGattCharacteristic(UPDATE_CHARACTERISTIC_UUID_5, 0x1C, 0x11);
+        descriptor = new BluetoothGattDescriptor(UPDATE_DESCRIPTOR_UUID, 0x11);
+        descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
+        notiCharacteristic.addDescriptor(descriptor);
+        notiCharacteristic.setValue(NOTIFY_VALUE);
+        service.addCharacteristic(notiCharacteristic);
+
+        notiCharacteristic =
+                new BluetoothGattCharacteristic(UPDATE_CHARACTERISTIC_UUID_11, 0x3A, 0x11);
+        descriptor = new BluetoothGattDescriptor(UPDATE_DESCRIPTOR_UUID, 0x11);
+        descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
+        notiCharacteristic.addDescriptor(descriptor);
+        notiCharacteristic.setValue(NOTIFY_VALUE);
+        service.addCharacteristic(notiCharacteristic);
+
+        notiCharacteristic =
+                new BluetoothGattCharacteristic(UPDATE_CHARACTERISTIC_UUID_12, 0x3C, 0x11);
+        descriptor = new BluetoothGattDescriptor(UPDATE_DESCRIPTOR_UUID, 0x11);
+        descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
+        notiCharacteristic.addDescriptor(descriptor);
+        notiCharacteristic.setValue(NOTIFY_VALUE);
+        service.addCharacteristic(notiCharacteristic);
+
+        notiCharacteristic =
+                new BluetoothGattCharacteristic(UPDATE_CHARACTERISTIC_UUID_13, 0x3E, 0x11);
+        descriptor = new BluetoothGattDescriptor(UPDATE_DESCRIPTOR_UUID, 0x11);
+        descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
+        notiCharacteristic.addDescriptor(descriptor);
+        notiCharacteristic.setValue(NOTIFY_VALUE);
+        service.addCharacteristic(notiCharacteristic);
+
+        notiCharacteristic =
+                new BluetoothGattCharacteristic(UPDATE_CHARACTERISTIC_UUID_14, 0x10, 0x0);
+        descriptor = new BluetoothGattDescriptor(UPDATE_DESCRIPTOR_UUID, 0x11);
+        descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
+        notiCharacteristic.addDescriptor(descriptor);
+        notiCharacteristic.setValue(NOTIFY_VALUE);
+        service.addCharacteristic(notiCharacteristic);
+
+        notiCharacteristic =
+                new BluetoothGattCharacteristic(UPDATE_CHARACTERISTIC_UUID_15, 0x30, 0x0);
+        descriptor = new BluetoothGattDescriptor(UPDATE_DESCRIPTOR_UUID, 0x11);
+        descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
+        notiCharacteristic.addDescriptor(descriptor);
+        notiCharacteristic.setValue(NOTIFY_VALUE);
+        service.addCharacteristic(notiCharacteristic);
+
+        return service;
+    }
+
     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);
+
+        characteristic =
+                new BluetoothGattCharacteristic(CHARACTERISTIC_RESULT_UUID, 0x0A, 0x11);
+        characteristic.addDescriptor(descriptor);
+
+        BluetoothGattDescriptor descriptor_encrypted = new BluetoothGattDescriptor(DESCRIPTOR_NEED_ENCRYPTED_READ_UUID, 0x02);
+        characteristic.addDescriptor(descriptor_encrypted);
+
+        descriptor_encrypted = new BluetoothGattDescriptor(DESCRIPTOR_NEED_ENCRYPTED_WRITE_UUID, 0x20);
+        characteristic.addDescriptor(descriptor_encrypted);
+
+        service.addCharacteristic(characteristic);
+
+        // Add new Characteristics
+        // Registered the characteristic of read permission for operation confirmation.
+        characteristic =
+                new BluetoothGattCharacteristic(CHARACTERISTIC_NO_READ_UUID, 0x0A, 0x10);
         characteristic.addDescriptor(descriptor);
         service.addCharacteristic(characteristic);
 
+        // Registered the characteristic of write permission for operation confirmation.
+        characteristic =
+                new BluetoothGattCharacteristic(CHARACTERISTIC_NO_WRITE_UUID, 0x0A, 0x01);
+        characteristic.addDescriptor(descriptor);
+        service.addCharacteristic(characteristic);
+
+        // Registered the characteristic of authenticate (Encrypted) for operation confirmation.
+        characteristic =
+                new BluetoothGattCharacteristic(CHARACTERISTIC_NEED_ENCRYPTED_READ_UUID, 0x0A, 0x02);
+        characteristic.addDescriptor(descriptor);
+        service.addCharacteristic(characteristic);
+
+        characteristic =
+                new BluetoothGattCharacteristic(CHARACTERISTIC_NEED_ENCRYPTED_WRITE_UUID, 0x0A, 0x20);
+        characteristic.addDescriptor(descriptor);
+        service.addCharacteristic(characteristic);
+
+        // Add new Characteristics(Indicate)
+        BluetoothGattCharacteristic indicateCharacteristic =
+                new BluetoothGattCharacteristic(INDICATE_CHARACTERISTIC_UUID, 0x2A, 0x11);
+        descriptor = new BluetoothGattDescriptor(UPDATE_DESCRIPTOR_UUID, 0x11);
+        descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
+        indicateCharacteristic.addDescriptor(descriptor);
+        indicateCharacteristic.setValue(INDICATE_VALUE);
+        service.addCharacteristic(indicateCharacteristic);
+
+        // Add new Characteristics(Notify)
         BluetoothGattCharacteristic notiCharacteristic =
-                new BluetoothGattCharacteristic(UPDATE_CHARACTERISTIC_UUID, 0x10, 0x00);
+                new BluetoothGattCharacteristic(UPDATE_CHARACTERISTIC_UUID, 0x1A, 0x11);
+        descriptor = new BluetoothGattDescriptor(UPDATE_DESCRIPTOR_UUID, 0x11);
+        descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
+        notiCharacteristic.addDescriptor(descriptor);
+        notiCharacteristic.setValue(NOTIFY_VALUE);
+        service.addCharacteristic(notiCharacteristic);
+
+        notiCharacteristic =
+                new BluetoothGattCharacteristic(UPDATE_CHARACTERISTIC_UUID_6, 0x1E, 0x11);
+        descriptor = new BluetoothGattDescriptor(UPDATE_DESCRIPTOR_UUID, 0x11);
+        descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
+        notiCharacteristic.addDescriptor(descriptor);
+        notiCharacteristic.setValue(NOTIFY_VALUE);
+        service.addCharacteristic(notiCharacteristic);
+
+        notiCharacteristic =
+                new BluetoothGattCharacteristic(UPDATE_CHARACTERISTIC_UUID_7, 0x32, 0x1);
+        descriptor = new BluetoothGattDescriptor(UPDATE_DESCRIPTOR_UUID, 0x11);
+        descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
+        notiCharacteristic.addDescriptor(descriptor);
+        notiCharacteristic.setValue(NOTIFY_VALUE);
+        service.addCharacteristic(notiCharacteristic);
+
+        notiCharacteristic =
+                new BluetoothGattCharacteristic(UPDATE_CHARACTERISTIC_UUID_8, 0x34, 0x11);
+        descriptor = new BluetoothGattDescriptor(UPDATE_DESCRIPTOR_UUID, 0x11);
+        descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
+        notiCharacteristic.addDescriptor(descriptor);
+        notiCharacteristic.setValue(NOTIFY_VALUE);
+        service.addCharacteristic(notiCharacteristic);
+
+        notiCharacteristic =
+                new BluetoothGattCharacteristic(UPDATE_CHARACTERISTIC_UUID_9, 0x36, 0x11);
+        descriptor = new BluetoothGattDescriptor(UPDATE_DESCRIPTOR_UUID, 0x11);
+        descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
+        notiCharacteristic.addDescriptor(descriptor);
+        notiCharacteristic.setValue(NOTIFY_VALUE);
+        service.addCharacteristic(notiCharacteristic);
+
+        notiCharacteristic =
+                new BluetoothGattCharacteristic(UPDATE_CHARACTERISTIC_UUID_10, 0x38, 0x10);
+        descriptor = new BluetoothGattDescriptor(UPDATE_DESCRIPTOR_UUID, 0x11);
+        descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
+        notiCharacteristic.addDescriptor(descriptor);
+        notiCharacteristic.setValue(NOTIFY_VALUE);
         service.addCharacteristic(notiCharacteristic);
 
         return service;
     }
 
-    private void beginNotification() {
-        TimerTask task = new TimerTask() {
-            @Override
-            public void run() {
-                if (mGattServer == null) {
-                    if (DEBUG) Log.d(TAG, "GattServer is null, return");
-                    return;
-                }
-                BluetoothGattCharacteristic characteristic =
-                        mService.getCharacteristic(UPDATE_CHARACTERISTIC_UUID);
-                if (characteristic == null) return;
-
-                String date = (new Date()).toString();
-                characteristic.setValue(date);
-                mGattServer.notifyCharacteristicChanged(mDevice, characteristic, false);
-            }
-        };
-        mNotificationTimer = new Timer();
-        mNotificationTimer.schedule(task, 0, 1000);
-    }
-
-    private void stopNotification() {
-        if (mNotificationTimer == null) return;
-        mNotificationTimer.cancel();
-        mNotificationTimer = null;
-    }
-
     private void showMessage(final String msg) {
         mHandler.post(new Runnable() {
             public void run() {
@@ -274,17 +822,83 @@
         });
     }
 
+    private void onMtuTestDataReceive() {
+
+        Log.d(TAG, "onMtuTestDataReceive(" + mCountMtuChange + "):" + mMtuTestReceivedData);
+
+        // verify
+        if (mMtuTestReceivedData.equals(BleClientService.WRITE_VALUE_512BYTES_FOR_MTU)) {
+
+            // write back data
+            // MTU test verifies whether the write/read operations go well.
+            BluetoothGattCharacteristic characteristic = getCharacteristic(CHARACTERISTIC_UUID);
+            characteristic.setValue(mMtuTestReceivedData.getBytes());
+
+            notifyMtuRequest();
+        } else {
+            showMessage(getString(R.string.ble_mtu_fail_message));
+        }
+        mMtuTestReceivedData = "";
+        if (mCountMtuChange >= 2) {
+            // All MTU change tests completed
+            mCountMtuChange = 0;
+        }
+    }
+
+    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 (DEBUG) {
+                Log.d(TAG, "onConnectionStateChange: newState=" + newState);
+            }
+
             if (status == BluetoothGatt.GATT_SUCCESS) {
                 if (newState == BluetoothProfile.STATE_CONNECTED) {
                     mDevice = device;
-                    notifyConnected();
-                    beginNotification();
+                    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
+                        cancelNotificationTaskOfSecureTestStartFailure();
+                        /*
+                        mNotificationTaskOfSecureTestStartFailure = new Runnable() {
+                            @Override
+                            public void run() {
+                                mNotificationTaskOfSecureTestStartFailure = null;
+                                if (mSecure && (mDevice.getBondState() != BluetoothDevice.BOND_BONDED)) {
+                                    notifyMismatchSecure();
+                                }
+                            }
+                        };
+                        mHandler.postDelayed(mNotificationTaskOfSecureTestStartFailure,
+                                NOTIFICATION_DELAY_OF_SECURE_TEST_FAILURE);
+                        */
+                    } else if (!mSecure && ((device.getBondState() != BluetoothDevice.BOND_NONE) || bonded)) {
+                        // already pairing nad execute Insecure Test
+                        /*
+                        notifyMismatchInsecure();
+                        */
+                    } else {
+                        cancelNotificationTaskOfSecureTestStartFailure();
+                        notifyConnected();
+                    }
                 } else if (status == BluetoothProfile.STATE_DISCONNECTED) {
-                    stopNotification();
                     notifyDisconnected();
                     mDevice = null;
                 }
@@ -293,22 +907,78 @@
 
         @Override
         public void onServiceAdded(int status, BluetoothGattService service) {
-            if (DEBUG) Log.d(TAG, "onServiceAdded()");
-            if (status == BluetoothGatt.GATT_SUCCESS) notifyServiceAdded();
+            if (DEBUG) {
+                Log.d(TAG, "onServiceAdded(): " + service.getUuid());
+                dumpService(service, 0);
+            }
+            if (status == BluetoothGatt.GATT_SUCCESS) {
+                UUID uuid = service.getUuid();
+
+                if (uuid.equals(mService.getUuid())) {
+                    // create and add nested service
+                    BluetoothGattService includedService =
+                            new BluetoothGattService(SERVICE_UUID_INCLUDED, BluetoothGattService.SERVICE_TYPE_SECONDARY);
+                    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);
+                    includedService.addCharacteristic(characteristic);
+                    mGattServer.addService(includedService);
+                } else if (uuid.equals(SERVICE_UUID_INCLUDED)) {
+                    mService.addService(service);
+                    mGattServer.addService(mAdditionalNotificationService);
+                } else if (uuid.equals(mAdditionalNotificationService.getUuid())) {
+                    // all services added
+                    notifyServiceAdded();
+                } else {
+                    notifyAddServiceFail();
+                }
+            } else {
+                notifyAddServiceFail();
+            }
         }
 
         @Override
-        public void onCharacteristicReadRequest(BluetoothDevice device, int requestId,
-                int offset, BluetoothGattCharacteristic characteristic) {
+        public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattCharacteristic characteristic) {
             if (mGattServer == null) {
-                if (DEBUG) Log.d(TAG, "GattServer is null, return");
+                if (DEBUG) {
+                    Log.d(TAG, "GattServer is null, return");
+                }
                 return;
             }
-            if (DEBUG) Log.d(TAG, "onCharacteristicReadRequest()");
+            if (DEBUG) {
+                Log.d(TAG, "onCharacteristicReadRequest()");
+            }
 
-            notifyCharacteristicReadRequest();
-            mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, 0,
-                                     characteristic.getValue());
+            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(CHARACTERISTIC_NEED_ENCRYPTED_READ_UUID)) {
+                notifyCharacteristicReadRequestNeedEncrypted();
+            } else {
+                notifyCharacteristicReadRequest(finished);
+            }
         }
 
         @Override
@@ -317,32 +987,113 @@
                 boolean preparedWrite, boolean responseNeeded,
                 int offset, byte[] value) {
             if (mGattServer == null) {
-                if (DEBUG) Log.d(TAG, "GattServer is null, return");
+                if (DEBUG) {
+                    Log.d(TAG, "GattServer is null, return");
+                }
                 return;
             }
-            if (DEBUG) Log.d(TAG, "onCharacteristicWriteRequest: preparedWrite=" + preparedWrite);
+            if (DEBUG) {
+                Log.d(TAG, "onCharacteristicWriteRequest: preparedWrite=" + preparedWrite + ", responseNeeded= " + responseNeeded);
+            }
 
-            notifyCharacteristicWriteRequest();
-            if (preparedWrite) mReliableWriteValue = new String(value);
-            else characteristic.setValue(value);
+            if (characteristic.getUuid().equals(CHARACTERISTIC_RESULT_UUID)) {
+                String resValue = new String(value);
+                Log.d(TAG, "CHARACTERISTIC_RESULT_UUID: resValue=" + resValue);
+                switch (resValue) {
+                    case WRITE_NO_PERMISSION:
+                        notifyCharacteristicWriteRequestWithoutPermission();
+                        break;
+                    case READ_NO_PERMISSION:
+                        notifyCharacteristicReadRequestWithoutPermission();
+                        break;
+                    case DESCRIPTOR_WRITE_NO_PERMISSION:
+                        notifyDescriptorWriteRequestWithoutPermission();
+                        break;
+                    case DESCRIPTOR_READ_NO_PERMISSION:
+                        notifyDescriptorReadRequestWithoutPermission();
+                        break;
+                }
+                if (responseNeeded) {
+                    mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value);
+                }
+                return;
+            }
 
-            if (responseNeeded)
+            // MTU test flow
+            if (mCountMtuChange > 0) {
+                if (preparedWrite) {
+                    mMtuTestReceivedData += new String(value);
+                } else {
+                    String strValue = new String(value);
+                    if (mCountMtuChange > 0) {
+                        mMtuTestReceivedData = strValue;
+                        onMtuTestDataReceive();
+                    }
+                }
+                if (responseNeeded) {
+                    mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value);
+                }
+
+                return;
+            }
+
+            // Reliable write with bad response test flow
+            String valueStr = new String(value);
+            if (BleClientService.WRITE_VALUE_BAD_RESP.equals(valueStr)) {
                 mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, 0, null);
+                notifyReliableWriteBadResp();
+                return;
+            }
+
+            if (preparedWrite) {
+                mReliableWriteValue += (new String(value));
+            } else {
+                characteristic.setValue(value);
+                // verify
+                if (Arrays.equals(BleClientService.WRITE_VALUE.getBytes(), characteristic.getValue())) {
+                    UUID uid = characteristic.getUuid();
+                    if (uid.equals(CHARACTERISTIC_NEED_ENCRYPTED_WRITE_UUID)) {
+                        notifyCharacteristicWriteRequestNeedEncrypted();
+                    } else {
+                        notifyCharacteristicWriteRequest();
+                    }
+                } else {
+                    showMessage("Written data is not correct");
+                }
+            }
+
+            if (responseNeeded) {
+                mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value);
+            }
         }
 
         @Override
         public void onDescriptorReadRequest(BluetoothDevice device, int requestId,
                 int offset, BluetoothGattDescriptor descriptor) {
             if (mGattServer == null) {
-                if (DEBUG) Log.d(TAG, "GattServer is null, return");
+                if (DEBUG) {
+                    Log.d(TAG, "GattServer is null, return");
+                }
                 return;
             }
-            if (DEBUG) Log.d(TAG, "onDescriptorReadRequest(): (descriptor == getDescriptor())="
-                                  + (descriptor == getDescriptor()));
+                if (DEBUG) {
+                Log.d(TAG, "onDescriptorReadRequest(): (descriptor == getDescriptor())="
+                        + (descriptor == getDescriptor()));
+            }
 
-            notifyDescriptorReadRequest();
-            mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, 0,
-                                     descriptor.getValue());
+            UUID uid = descriptor.getUuid();
+            if (uid.equals(DESCRIPTOR_NEED_ENCRYPTED_READ_UUID)){
+                notifyDescriptorReadRequestNeedEncrypted();
+            } else {
+                notifyDescriptorReadRequest();
+            }
+
+            byte[] value = descriptor.getValue();
+            if (value == null) {
+                throw new RuntimeException("descriptor data read is null");
+            }
+
+            mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value);
         }
 
         @Override
@@ -351,35 +1102,139 @@
                 boolean preparedWrite, boolean responseNeeded,
                 int offset,  byte[] value) {
             if (mGattServer == null) {
-                if (DEBUG) Log.d(TAG, "GattServer is null, return");
+                if (DEBUG) {
+                    Log.d(TAG, "GattServer is null, return");
+                }
                 return;
             }
-            if (DEBUG) Log.d(TAG, "onDescriptorWriteRequest(): (descriptor == getDescriptor())="
-                                  + (descriptor == getDescriptor()));
+            BluetoothGattCharacteristic characteristic = descriptor.getCharacteristic();
+            UUID uid = characteristic.getUuid();
+            if (DEBUG) {
+                Log.d(TAG, "onDescriptorWriteRequest: preparedWrite=" + preparedWrite + ", responseNeeded= " + responseNeeded);
+                Log.d(TAG, "   characteristic uuid = " + uid);
+            }
 
-            notifyDescriptorWriteRequest();
             descriptor.setValue(value);
-            if (responseNeeded)
-                mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, 0, null);
+            UUID duid = descriptor.getUuid();
+            // If there is a written request to the CCCD for Notify.
+            if (duid.equals(UPDATE_DESCRIPTOR_UUID)) {
+                if (Arrays.equals(value, BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE)) {
+                    mGattServer.notifyCharacteristicChanged(mDevice, descriptor.getCharacteristic(), false);
+                    mIndicated = false;
+                } else if (Arrays.equals(value, BluetoothGattDescriptor.ENABLE_INDICATION_VALUE)) {
+                    mGattServer.notifyCharacteristicChanged(mDevice, descriptor.getCharacteristic(), true);
+                    mIndicated = true;
+                }
+            } else if (duid.equals(DESCRIPTOR_NEED_ENCRYPTED_WRITE_UUID)) {
+                // verify
+                if (Arrays.equals(BleClientService.WRITE_VALUE.getBytes(), descriptor.getValue())) {
+                    notifyDescriptorWriteRequestNeedEncrypted();
+                } else {
+                    showMessage("Written data is not correct");
+                }
+            } else {
+                // verify
+                if (Arrays.equals(BleClientService.WRITE_VALUE.getBytes(), descriptor.getValue())) {
+                    notifyDescriptorWriteRequest();
+                } else {
+                    showMessage("Written data is not correct");
+                }
+            }
+            if (responseNeeded) {
+                mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value);
+            }
         }
 
         @Override
         public void onExecuteWrite(BluetoothDevice device, int requestId, boolean execute) {
             if (mGattServer == null) {
-                if (DEBUG) Log.d(TAG, "GattServer is null, return");
+                if (DEBUG) {
+                    Log.d(TAG, "GattServer is null, return");
+                }
                 return;
             }
-            if (DEBUG) Log.d(TAG, "onExecuteWrite");
-            if (execute) {
-                notifyExecuteWrite();
-                getCharacteristic(CHARACTERISTIC_UUID).setValue(mReliableWriteValue);
-                mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, 0, null);
+            if (DEBUG) {
+                Log.d(TAG, "onExecuteWrite");
             }
+
+            if (execute) {
+                if (mCountMtuChange > 0) {
+                    onMtuTestDataReceive();
+                } else {
+                    // verify
+                    String str = BleClientService.WRITE_VALUE_507BYTES_FOR_RELIABLE_WRITE
+                            + BleClientService.WRITE_VALUE_507BYTES_FOR_RELIABLE_WRITE;
+                    if (str.equals(mReliableWriteValue)) {
+                        notifyExecuteWrite();
+                    } else {
+                        showMessage("Failed to receive data");
+                        Log.d(TAG, "Failed to receive data:" + mReliableWriteValue);
+                    }
+                }
+                mReliableWriteValue = "";
+            }
+            mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, 0, null);
+        }
+
+        @Override
+        public void onNotificationSent(BluetoothDevice device, int status) {
+            if (mGattServer == null) {
+                if (DEBUG) {
+                    Log.d(TAG, "GattServer is null, return");
+                }
+                return;
+            }
+            if (DEBUG) {
+                Log.d(TAG, "onNotificationSent");
+            }
+
+            if (status == BluetoothGatt.GATT_SUCCESS) {
+                if (mIndicated) {
+                    notifyCharacteristicIndicationRequest();
+                } else {
+                    mNotifyCount--;
+                    if (mNotifyCount == 0) {
+                        notifyCharacteristicNotificationRequest();
+                    }
+                }
+            }
+        }
+
+        @Override
+        public void onMtuChanged(BluetoothDevice device, int mtu) {
+            if (mGattServer == null) {
+                if (DEBUG) {
+                    Log.d(TAG, "GattServer is null, return");
+                }
+                return;
+            }
+            if (DEBUG) {
+                Log.d(TAG, "onMtuChanged");
+            }
+
+            mMtuSize = mtu;
+            if (mCountMtuChange == 0) {
+                if (mtu != 23) {
+                    String msg = String.format(getString(R.string.ble_mtu_mismatch_message),
+                            23, mtu);
+                    showMessage(msg);
+                }
+            } else if (mCountMtuChange == 1) {
+                if (mtu != 512) {
+                    String msg = String.format(getString(R.string.ble_mtu_mismatch_message),
+                            512, mtu);
+                    showMessage(msg);
+                }
+            }
+            mMtuTestReceivedData = "";
+            ++mCountMtuChange;
         }
     };
 
     private void startAdvertise() {
-        if (DEBUG) Log.d(TAG, "startAdvertise");
+        if (DEBUG) {
+            Log.d(TAG, "startAdvertise");
+        }
         AdvertiseData data = new AdvertiseData.Builder()
             .addServiceData(new ParcelUuid(ADV_SERVICE_UUID), new byte[]{1,2,3})
             .addServiceUuid(new ParcelUuid(ADV_SERVICE_UUID))
@@ -393,10 +1248,67 @@
     }
 
     private void stopAdvertise() {
-        if (DEBUG) Log.d(TAG, "stopAdvertise");
-        mAdvertiser.stopAdvertising(mAdvertiseCallback);
+        if (DEBUG) {
+            Log.d(TAG, "stopAdvertise");
+        }
+        if (mAdvertiser != null) {
+            mAdvertiser.stopAdvertising(mAdvertiseCallback);
+        }
     }
 
-    private final AdvertiseCallback mAdvertiseCallback = new AdvertiseCallback(){};
+    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);
+            }
+        }
+    }
+
 }
 
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleServerStartActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleServerStartActivity.java
deleted file mode 100644
index e8e35d5..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleServerStartActivity.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright (C) 2013 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 com.android.cts.verifier.PassFailButtons;
-import com.android.cts.verifier.R;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.BaseAdapter;
-import android.widget.ImageView;
-import android.widget.ListView;
-import android.widget.TextView;
-import android.widget.Toast;
-
-public class BleServerStartActivity extends PassFailButtons.Activity {
-
-    private TestAdapter mTestAdapter;
-    private int mAllPassed;
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.ble_server_start);
-        setPassFailButtonClickListeners();
-        setInfoResources(R.string.ble_server_start_name,
-                         R.string.ble_server_start_info, -1);
-        getPassButton().setEnabled(false);
-
-        mTestAdapter = new TestAdapter(this, setupTestList());
-        ListView listView = (ListView) findViewById(R.id.ble_server_tests);
-        listView.setAdapter(mTestAdapter);
-
-        mAllPassed = 0;
-        startService(new Intent(this, BleServerService.class));
-    }
-
-    @Override
-    public void onResume() {
-        super.onResume();
-
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(BleServerService.BLE_SERVICE_ADDED);
-        filter.addAction(BleServerService.BLE_SERVER_CONNECTED);
-        filter.addAction(BleServerService.BLE_CHARACTERISTIC_READ_REQUEST);
-        filter.addAction(BleServerService.BLE_CHARACTERISTIC_WRITE_REQUEST);
-        filter.addAction(BleServerService.BLE_DESCRIPTOR_READ_REQUEST);
-        filter.addAction(BleServerService.BLE_DESCRIPTOR_WRITE_REQUEST);
-        filter.addAction(BleServerService.BLE_EXECUTE_WRITE);
-        filter.addAction(BleServerService.BLE_SERVER_DISCONNECTED);
-        filter.addAction(BleServerService.BLE_OPEN_FAIL);
-        registerReceiver(onBroadcast, filter);
-    }
-
-    @Override
-    public void onPause() {
-        super.onPause();
-        unregisterReceiver(onBroadcast);
-    }
-
-    @Override
-    public void onDestroy() {
-        super.onDestroy();
-        stopService(new Intent(this, BleServerService.class));
-    }
-
-    private List<Integer> setupTestList() {
-        ArrayList<Integer> testList = new ArrayList<Integer>();
-        testList.add(R.string.ble_server_add_service);
-        testList.add(R.string.ble_server_receiving_connect);
-        testList.add(R.string.ble_server_read_characteristic);
-        testList.add(R.string.ble_server_write_characteristic);
-        testList.add(R.string.ble_server_read_descriptor);
-        testList.add(R.string.ble_server_write_descriptor);
-        testList.add(R.string.ble_server_reliable_write);
-        testList.add(R.string.ble_server_receiving_disconnect);
-        return testList;
-    }
-
-    private BroadcastReceiver onBroadcast = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            if (action == BleServerService.BLE_SERVICE_ADDED) {
-                mTestAdapter.setTestPass(0);
-                mAllPassed |= 0x01;
-            } else if (action == BleServerService.BLE_SERVER_CONNECTED) {
-                mTestAdapter.setTestPass(1);
-                mAllPassed |= 0x02;
-            } else if (action == BleServerService.BLE_CHARACTERISTIC_READ_REQUEST) {
-                mTestAdapter.setTestPass(2);
-                mAllPassed |= 0x04;
-            } else if (action == BleServerService.BLE_CHARACTERISTIC_WRITE_REQUEST) {
-                mTestAdapter.setTestPass(3);
-                mAllPassed |= 0x08;
-            } else if (action == BleServerService.BLE_DESCRIPTOR_READ_REQUEST) {
-                mTestAdapter.setTestPass(4);
-                mAllPassed |= 0x10;
-            } else if (action == BleServerService.BLE_DESCRIPTOR_WRITE_REQUEST) {
-                mTestAdapter.setTestPass(5);
-                mAllPassed |= 0x20;
-            } else if (action == BleServerService.BLE_EXECUTE_WRITE) {
-                mTestAdapter.setTestPass(6);
-                mAllPassed |= 0x40;
-            } else if (action == BleServerService.BLE_SERVER_DISCONNECTED) {
-                mTestAdapter.setTestPass(7);
-                mAllPassed |= 0x80;
-            } else if (action == BleServerService.BLE_OPEN_FAIL) {
-                setTestResultAndFinish(false);
-                runOnUiThread(new Runnable() {
-                    @Override
-                    public void run() {
-                        Toast.makeText(BleServerStartActivity.this, "Cannot open GattService",
-                                Toast.LENGTH_SHORT).show();
-                    }
-                });
-            }
-            mTestAdapter.notifyDataSetChanged();
-            if (mAllPassed == 0xFF) getPassButton().setEnabled(true);
-        }
-    };
-}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleServerTestBaseActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleServerTestBaseActivity.java
new file mode 100644
index 0000000..c58ee46
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleServerTestBaseActivity.java
@@ -0,0 +1,286 @@
+/*
+ * Copyright (C) 2013 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.AlertDialog;
+import android.app.Dialog;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.widget.ListView;
+import android.widget.Toast;
+
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class BleServerTestBaseActivity extends PassFailButtons.Activity {
+
+    private static final int PASS_FLAG_ADD_SERVICE = 0x1;
+    private static final int PASS_FLAG_CONNECT = 0x2;
+    private static final int PASS_FLAG_READ_CHARACTERISTIC = 0x4;
+    private static final int PASS_FLAG_WRITE_CHARACTERISTIC = 0x8;
+    private static final int PASS_FLAG_READ_DESCRIPTOR = 0x10;
+    private static final int PASS_FLAG_WRITE_DESCRIPTOR = 0x20;
+    private static final int PASS_FLAG_WRITE = 0x40;
+    private static final int PASS_FLAG_DISCONNECT = 0x80;
+    private static final int PASS_FLAG_NOTIFY_CHARACTERISTIC = 0x100;
+    private static final int PASS_FLAG_READ_CHARACTERISTIC_NO_PERMISSION = 0x200;
+    private static final int PASS_FLAG_WRITE_CHARACTERISTIC_NO_PERMISSION = 0x400;
+    private static final int PASS_FLAG_READ_DESCRIPTOR_NO_PERMISSION = 0x800;
+    private static final int PASS_FLAG_WRITE_DESCRIPTOR_NO_PERMISSION = 0x1000;
+    private static final int PASS_FLAG_INDICATE_CHARACTERISTIC = 0x2000;
+    private static final int PASS_FLAG_MTU_CHANGE_23BYTES = 0x4000;
+    private static final int PASS_FLAG_MTU_CHANGE_512BYTES = 0x8000;
+    private static final int PASS_FLAG_RELIABLE_WRITE_BAD_RESP = 0x10000;
+    private static final int PASS_FLAG_ALL = 0x1FFFF;
+
+    private final int BLE_SERVICE_ADDED = 0;
+    private final int BLE_SERVER_CONNECTED = 1;
+    private final int BLE_CHARACTERISTIC_READ_REQUEST = 2;
+    private final int BLE_CHARACTERISTIC_WRITE_REQUEST = 3;
+    private final int BLE_SERVER_MTU_23BYTES = 4;
+    private final int BLE_SERVER_MTU_512BYTES = 5;
+    private final int BLE_CHARACTERISTIC_READ_REQUEST_WITHOUT_PERMISSION = 6;
+    private final int BLE_CHARACTERISTIC_WRITE_REQUEST_WITHOUT_PERMISSION = 7;
+    private final int BLE_EXECUTE_WRITE = 8;
+    private final int BLE_EXECUTE_WRITE_BAD_RESP = 9;
+    private final int BLE_CHARACTERISTIC_NOTIFICATION_REQUEST = 9;  //10;
+    private final int BLE_CHARACTERISTIC_INDICATE_REQUEST = 10; //11;
+    private final int BLE_DESCRIPTOR_READ_REQUEST = 11; //12;
+    private final int BLE_DESCRIPTOR_WRITE_REQUEST = 12;    //13;
+    private final int BLE_DESCRIPTOR_READ_REQUEST_WITHOUT_PERMISSION = 13;  //14;
+    private final int BLE_DESCRIPTOR_WRITE_REQUEST_WITHOUT_PERMISSION = 14; //15;
+    private final int BLE_SERVER_DISCONNECTED = 15; //16;
+    private final int BLE_OPEN_FAIL = 16;   //17;
+
+    private TestAdapter mTestAdapter;
+    private long mAllPassed;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.ble_server_start);
+        setPassFailButtonClickListeners();
+        setInfoResources(R.string.ble_server_start_name,
+                         R.string.ble_server_start_info, -1);
+        getPassButton().setEnabled(false);
+
+        mTestAdapter = new TestAdapter(this, setupTestList());
+        ListView listView = (ListView) findViewById(R.id.ble_server_tests);
+        listView.setAdapter(mTestAdapter);
+
+//        mAllPassed = 0;
+        // skip Reliable write (bad response) test
+        mAllPassed = PASS_FLAG_RELIABLE_WRITE_BAD_RESP;
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(BleServerService.BLE_BLUETOOTH_DISABLED);
+        filter.addAction(BleServerService.BLE_SERVICE_ADDED);
+        filter.addAction(BleServerService.BLE_SERVER_CONNECTED);
+        filter.addAction(BleServerService.BLE_MTU_REQUEST_23BYTES);
+        filter.addAction(BleServerService.BLE_MTU_REQUEST_512BYTES);
+        filter.addAction(BleServerService.BLE_CHARACTERISTIC_READ_REQUEST);
+        filter.addAction(BleServerService.BLE_CHARACTERISTIC_WRITE_REQUEST);
+        filter.addAction(BleServerService.BLE_CHARACTERISTIC_READ_REQUEST_WITHOUT_PERMISSION);
+        filter.addAction(BleServerService.BLE_CHARACTERISTIC_WRITE_REQUEST_WITHOUT_PERMISSION);
+        filter.addAction(BleServerService.BLE_CHARACTERISTIC_NOTIFICATION_REQUEST);
+        filter.addAction(BleServerService.BLE_CHARACTERISTIC_INDICATE_REQUEST);
+        filter.addAction(BleServerService.BLE_DESCRIPTOR_READ_REQUEST);
+        filter.addAction(BleServerService.BLE_DESCRIPTOR_WRITE_REQUEST);
+        filter.addAction(BleServerService.BLE_DESCRIPTOR_READ_REQUEST_WITHOUT_PERMISSION);
+        filter.addAction(BleServerService.BLE_DESCRIPTOR_WRITE_REQUEST_WITHOUT_PERMISSION);
+        filter.addAction(BleServerService.BLE_EXECUTE_WRITE);
+        filter.addAction(BleServerService.BLE_RELIABLE_WRITE_BAD_RESP);
+        filter.addAction(BleServerService.BLE_SERVER_DISCONNECTED);
+        filter.addAction(BleServerService.BLE_OPEN_FAIL);
+        filter.addAction(BleServerService.BLE_BLUETOOTH_MISMATCH_SECURE);
+        filter.addAction(BleServerService.BLE_BLUETOOTH_MISMATCH_INSECURE);
+        filter.addAction(BleServerService.BLE_ADVERTISE_UNSUPPORTED);
+        filter.addAction(BleServerService.BLE_ADD_SERVICE_FAIL);
+
+        registerReceiver(mBroadcast, filter);
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        unregisterReceiver(mBroadcast);
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+    }
+
+    private List<Integer> setupTestList() {
+        ArrayList<Integer> testList = new ArrayList<Integer>();
+        testList.add(R.string.ble_server_add_service);
+        testList.add(R.string.ble_server_receiving_connect);
+        testList.add(R.string.ble_server_read_characteristic);
+        testList.add(R.string.ble_server_write_characteristic);
+        testList.add(R.string.ble_server_mtu_23bytes);
+        testList.add(R.string.ble_server_mtu_512bytes);
+        testList.add(R.string.ble_server_read_characteristic_without_permission);
+        testList.add(R.string.ble_server_write_characteristic_without_permission);
+        testList.add(R.string.ble_server_reliable_write);
+//        testList.add(R.string.ble_server_reliable_write_bad_resp);
+        testList.add(R.string.ble_server_notify_characteristic);
+        testList.add(R.string.ble_server_indicate_characteristic);
+        testList.add(R.string.ble_server_read_descriptor);
+        testList.add(R.string.ble_server_write_descriptor);
+        testList.add(R.string.ble_server_read_descriptor_without_permission);
+        testList.add(R.string.ble_server_write_descriptor_without_permission);
+        testList.add(R.string.ble_server_receiving_disconnect);
+        return testList;
+    }
+
+    private void showErrorDialog(int titleId, int messageId, boolean finish) {
+        AlertDialog.Builder builder = new AlertDialog.Builder(this)
+                .setTitle(titleId)
+                .setMessage(messageId);
+        if (finish) {
+            builder.setOnCancelListener(new Dialog.OnCancelListener() {
+                @Override
+                public void onCancel(DialogInterface dialog) {
+                    finish();
+                }
+            });
+        }
+        builder.create().show();
+    }
+
+    private BroadcastReceiver mBroadcast = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            switch (action) {
+            case BleServerService.BLE_BLUETOOTH_DISABLED:
+                showErrorDialog(R.string.ble_bluetooth_disable_title, R.string.ble_bluetooth_disable_message, true);
+                break;
+            case BleServerService.BLE_SERVICE_ADDED:
+                mTestAdapter.setTestPass(BLE_SERVICE_ADDED);
+                mAllPassed |= PASS_FLAG_ADD_SERVICE;
+                break;
+            case BleServerService.BLE_SERVER_CONNECTED:
+                mTestAdapter.setTestPass(BLE_SERVER_CONNECTED);
+                mAllPassed |= PASS_FLAG_CONNECT;
+                break;
+            case BleServerService.BLE_CHARACTERISTIC_READ_REQUEST:
+                // Sometimes server returns incorrect pairing status.
+                // And it causes the mismatch of pairing status and connection status.
+                // So consider the connection went well if reading characteristic went well.
+                mTestAdapter.setTestPass(BLE_SERVER_CONNECTED);
+                mAllPassed |= PASS_FLAG_CONNECT;
+
+                mTestAdapter.setTestPass(BLE_CHARACTERISTIC_READ_REQUEST);
+                mAllPassed |= PASS_FLAG_READ_CHARACTERISTIC;
+                break;
+            case BleServerService.BLE_CHARACTERISTIC_WRITE_REQUEST:
+                mTestAdapter.setTestPass(BLE_CHARACTERISTIC_WRITE_REQUEST);
+                mAllPassed |= PASS_FLAG_WRITE_CHARACTERISTIC;
+                break;
+            case BleServerService.BLE_DESCRIPTOR_READ_REQUEST:
+                mTestAdapter.setTestPass(BLE_DESCRIPTOR_READ_REQUEST);
+                mAllPassed |= PASS_FLAG_READ_DESCRIPTOR;
+                break;
+            case BleServerService.BLE_DESCRIPTOR_WRITE_REQUEST:
+                mTestAdapter.setTestPass(BLE_DESCRIPTOR_WRITE_REQUEST);
+                mAllPassed |= PASS_FLAG_WRITE_DESCRIPTOR;
+                break;
+            case BleServerService.BLE_EXECUTE_WRITE:
+                mTestAdapter.setTestPass(BLE_EXECUTE_WRITE);
+                mAllPassed |= PASS_FLAG_WRITE;
+                break;
+            case BleServerService.BLE_RELIABLE_WRITE_BAD_RESP:
+                mTestAdapter.setTestPass(BLE_EXECUTE_WRITE_BAD_RESP);
+                mAllPassed |= PASS_FLAG_RELIABLE_WRITE_BAD_RESP;
+                break;
+            case BleServerService.BLE_SERVER_DISCONNECTED:
+                mTestAdapter.setTestPass(BLE_SERVER_DISCONNECTED);
+                mAllPassed |= PASS_FLAG_DISCONNECT;
+                break;
+            case BleServerService.BLE_CHARACTERISTIC_NOTIFICATION_REQUEST:
+                mTestAdapter.setTestPass(BLE_CHARACTERISTIC_NOTIFICATION_REQUEST);
+                mAllPassed |= PASS_FLAG_NOTIFY_CHARACTERISTIC;
+                break;
+            case BleServerService.BLE_CHARACTERISTIC_READ_REQUEST_WITHOUT_PERMISSION:
+                mTestAdapter.setTestPass(BLE_CHARACTERISTIC_READ_REQUEST_WITHOUT_PERMISSION);
+                mAllPassed |= PASS_FLAG_READ_CHARACTERISTIC_NO_PERMISSION;
+                break;
+            case BleServerService.BLE_CHARACTERISTIC_WRITE_REQUEST_WITHOUT_PERMISSION:
+                mTestAdapter.setTestPass(BLE_CHARACTERISTIC_WRITE_REQUEST_WITHOUT_PERMISSION);
+                mAllPassed |= PASS_FLAG_WRITE_CHARACTERISTIC_NO_PERMISSION;
+                break;
+            case BleServerService.BLE_DESCRIPTOR_READ_REQUEST_WITHOUT_PERMISSION:
+                mTestAdapter.setTestPass(BLE_DESCRIPTOR_READ_REQUEST_WITHOUT_PERMISSION);
+                mAllPassed |= PASS_FLAG_READ_DESCRIPTOR_NO_PERMISSION;
+                break;
+            case BleServerService.BLE_DESCRIPTOR_WRITE_REQUEST_WITHOUT_PERMISSION:
+                mTestAdapter.setTestPass(BLE_DESCRIPTOR_WRITE_REQUEST_WITHOUT_PERMISSION);
+                mAllPassed |= PASS_FLAG_WRITE_DESCRIPTOR_NO_PERMISSION;
+                break;
+            case BleServerService.BLE_CHARACTERISTIC_INDICATE_REQUEST:
+                mTestAdapter.setTestPass(BLE_CHARACTERISTIC_INDICATE_REQUEST);
+                mAllPassed |= PASS_FLAG_INDICATE_CHARACTERISTIC;
+                break;
+            case BleServerService.BLE_MTU_REQUEST_23BYTES:
+                mTestAdapter.setTestPass(BLE_SERVER_MTU_23BYTES);
+                mAllPassed |= PASS_FLAG_MTU_CHANGE_23BYTES;
+                break;
+            case BleServerService.BLE_MTU_REQUEST_512BYTES:
+                mTestAdapter.setTestPass(BLE_SERVER_MTU_512BYTES);
+                mAllPassed |= PASS_FLAG_MTU_CHANGE_512BYTES;
+                break;
+            case BleServerService.BLE_BLUETOOTH_MISMATCH_SECURE:
+                showErrorDialog(R.string.ble_bluetooth_mismatch_title, R.string.ble_bluetooth_mismatch_secure_message, true);
+                break;
+            case BleServerService.BLE_BLUETOOTH_MISMATCH_INSECURE:
+                showErrorDialog(R.string.ble_bluetooth_mismatch_title, R.string.ble_bluetooth_mismatch_insecure_message, true);
+                break;
+            case BleServerService.BLE_ADVERTISE_UNSUPPORTED:
+                showErrorDialog(R.string.bt_advertise_unsupported_title, R.string.bt_advertise_unsupported_message, true);
+                break;
+            case BleServerService.BLE_OPEN_FAIL:
+                setTestResultAndFinish(false);
+                runOnUiThread(new Runnable() {
+                    @Override
+                    public void run() {
+                        Toast.makeText(BleServerTestBaseActivity.this, R.string.bt_open_failed_message, Toast.LENGTH_SHORT).show();
+                    }
+                });
+                break;
+            case BleServerService.BLE_ADD_SERVICE_FAIL:
+                showErrorDialog(R.string.bt_add_service_failed_title, R.string.bt_add_service_failed_message, true);
+                break;
+            }
+
+            mTestAdapter.notifyDataSetChanged();
+            if (mAllPassed == PASS_FLAG_ALL) getPassButton().setEnabled(true);
+        }
+    };
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BluetoothTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BluetoothTestActivity.java
index df70984..3477870 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BluetoothTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BluetoothTestActivity.java
@@ -16,14 +16,14 @@
 
 package com.android.cts.verifier.bluetooth;
 
-import com.android.cts.verifier.ManifestTestListAdapter;
-import com.android.cts.verifier.PassFailButtons;
-import com.android.cts.verifier.R;
-
 import android.bluetooth.BluetoothAdapter;
 import android.os.Bundle;
 import android.widget.Toast;
 
+import com.android.cts.verifier.ManifestTestListAdapter;
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
+
 import java.util.ArrayList;
 import java.util.List;
 
@@ -54,14 +54,20 @@
             disabledTestArray.add(
                   "com.android.cts.verifier.bluetooth.BleClientTestActivity");
             disabledTestArray.add(
-                  "com.android.cts.verifier.bluetooth.BleServerStartActivity");
+                  "com.android.cts.verifier.bluetooth.BleServerTestBaseActivity");
+            disabledTestArray.add(
+                  "com.android.cts.verifier.bluetooth.BleConnectionPriorityServerBaseActivity");
+            disabledTestArray.add(
+                  "com.android.cts.verifier.bluetooth.BleConnectionPriorityClientBaseActivity");
         } else if (!bluetoothAdapter.isMultipleAdvertisementSupported()) {
             disabledTestArray.add(
                   "com.android.cts.verifier.bluetooth.BleAdvertiserTestActivity");
             disabledTestArray.add(
-                  "com.android.cts.verifier.bluetooth.BleServerStartActivity");
+                  "com.android.cts.verifier.bluetooth.BleServerTestBaseActivity");
             disabledTestArray.add(
                   "com.android.cts.verifier.bluetooth.BleScannerTestActivity");
+            disabledTestArray.add(
+                  "com.android.cts.verifier.bluetooth.BleConnectionPriorityServerBaseActivity");
         }
         setTestListAdapter(new ManifestTestListAdapter(this, getClass().getName(),
                 disabledTestArray.toArray(new String[disabledTestArray.size()])));
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/TestTaskQueue.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/TestTaskQueue.java
new file mode 100644
index 0000000..5ceee0c
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/TestTaskQueue.java
@@ -0,0 +1,86 @@
+/*

+ * Copyright (C) 2016 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.os.Handler;

+import android.os.HandlerThread;

+

+import java.util.ArrayList;

+

+/**

+ * TestTaskQueue runs asynchronous operations on background thread.

+ *

+ * TestTaskQueue holds Handler which runs on background thread.

+ * Asynchronous operations will be run by adding operation by addTask().

+ * Each operations will be managed by Handler.

+ */

+public class TestTaskQueue {

+

+    private Handler mHandler;

+    private ArrayList<Runnable> mTasks = new ArrayList<>();

+

+    public TestTaskQueue(String threadName) {

+        HandlerThread th = new HandlerThread(threadName);

+        th.start();

+        mHandler = new Handler(th.getLooper());

+    }

+

+    /**

+     * Cancels all pending operations.

+     */

+    public synchronized void quit() {

+        // cancel all pending operations.

+        for (Runnable task : mTasks) {

+            mHandler.removeCallbacks(task);

+        }

+        mTasks.clear();

+

+        // terminate Handler

+        mHandler.getLooper().quit();

+        mHandler = null;

+    }

+

+    /**

+     * Reserves new asynchronous operation.

+     * Operations will be run sequentially.

+     *

+     * @param r new operation

+     */

+    public synchronized void addTask(Runnable r) {

+        addTask(r, 0);

+    }

+

+    /**

+     * Reserves new asynchronous operation.

+     * Operations will be run sequentially.

+     *

+     * @param r new operation

+     * @param delay delay for execution

+     */

+    public synchronized void addTask(final Runnable r, long delay) {

+        if ((mHandler != null) && (r != null)) {

+            Runnable task = new Runnable() {

+                @Override

+                public void run() {

+                    mTasks.remove(this);

+                    r.run();

+                }

+            };

+            mTasks.add(task);

+            mHandler.postDelayed(task, delay);

+        }

+    }

+}