Merge "Revert "Fix AudioManager.testRouting()."" into jb-dev
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index bacf4bd..ef3c073 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -348,6 +348,30 @@
             <meta-data android:name="test_required_features" android:value="android.hardware.wifi.direct" />
         </activity>
 
+        <activity android:name=".p2p.GoNegRequesterTestListActivity"
+                android:label="@string/p2p_go_neg_requester"
+                android:configChanges="keyboardHidden|orientation" />
+
+        <activity android:name=".p2p.GoNegRequesterTestActivity"
+                android:label="@string/p2p_go_neg_requester"
+                android:configChanges="keyboardHidden|orientation" />
+
+        <activity android:name=".p2p.GoNegResponderTestActivity"
+                android:label="@string/p2p_go_neg_responder"
+                android:configChanges="keyboardHidden|orientation" />
+
+        <activity android:name=".p2p.P2pClientTestListActivity"
+                android:label="@string/p2p_join_go"
+                android:configChanges="keyboardHidden|orientation" />
+
+        <activity android:name=".p2p.P2pClientTestActivity"
+                android:label="@string/p2p_join_go"
+                android:configChanges="keyboardHidden|orientation" />
+
+        <activity android:name=".p2p.GoTestActivity"
+                android:label="@string/p2p_accept_client"
+                android:configChanges="keyboardHidden|orientation" />
+
         <activity android:name=".p2p.ServiceRequesterTestListActivity"
                 android:label="@string/p2p_service_discovery_requester"
                 android:configChanges="keyboardHidden|orientation" />
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 6cf8d7d..d09efb1 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -357,19 +357,42 @@
         start the responder test. Your device must pass both requester and responder
         tests.
         </string>
+    <string name="p2p_group_formation">Group Formation</string>
+    <string name="p2p_join">Group Join</string>
     <string name="p2p_service_discovery">Service Discovery</string>
+
+    <string name="p2p_go_neg_responder_test">GO Negotiation Responder Test</string>
+    <string name="p2p_go_neg_requester_test">GO Negotiation Requester Test</string>
+    <string name="p2p_group_owner_test">Group Owner Test</string>
+    <string name="p2p_group_client_test">Group Client Test</string>
     <string name="p2p_service_discovery_responder_test">
         Service Discovery Responder Test</string>
     <string name="p2p_service_discovery_requester_test">
         Service Discovery Requester Test</string>
 
+    <string name="p2p_go_neg_responder">GO Negotiation Responder</string>
+    <string name="p2p_go_neg_requester">GO Negotiation Requester</string>
+    <string name="p2p_accept_client">Group Owner</string>
+    <string name="p2p_join_go">Group Client</string>
     <string name="p2p_service_discovery_responder">Service Discovery Responder</string>
     <string name="p2p_service_discovery_requester">Service Discovery Requester</string>
 
+    <string name="p2p_go_neg_responder_info">
+        Start the \"GO Negotiation Requester Test\" on the other device and follow
+        the instructions.</string>
+    <string name="p2p_accept_client_info">
+        Start the \"Group Client Test\" on the other device and follow
+        the instructions.</string>
     <string name="p2p_service_discovery_responder_info">
         Start the \"Service Discovery Requester Test\" on the other device and follow
         the instructions.</string>
 
+    <string name="p2p_go_neg_requester_info">
+        Start the \"GO Negotiation Responder Test\" on the other device.
+        Then run each test individually by clicking on it\'s name.</string>
+    <string name="p2p_join_go_info">
+        Start the \"Group Owner Test\" on the other device.
+        Then run each test individually by clicking on it\'s name.</string>
     <string name="p2p_service_discovery_requester_info">
         Start the \"Service Discovery Responder Test\" on the other device.
         Then run each test individually by clicking on it\'s name.</string>
@@ -380,9 +403,22 @@
     <string name="p2p_settings">Wi-Fi Direct Settings</string>
 
     <string name="p2p_result_success">Test passed successfully.</string>
-    <string name="p2p_responder_ready">
-        The Responder is now ready to start. Start the \"Service Discovery
-        Requester Test\" test on the other device.</string>
+
+    <string name="p2p_go_neg_responder_ready">
+        The go negotiation responder is now ready to start. Start
+        the \"GO Negotiation Requester Test\" on the other device.
+        Keep the screen here until all tests on the other device are
+        finished.</string>
+    <string name="p2p_go_ready">
+        The group owner is now ready to start. Start the \"Join
+        Group Test\" on the other device.
+        Keep the screen here until all tests on the other device are
+        finished.</string>
+    <string name="p2p_service_responder_ready">
+        The service responder is now ready to start. Start the
+        \"Service Discovery Requester Test\" on the other device.
+        Keep the screen here until all tests on the other device are
+        finished.</string>
 
     <string name="p2p_setup_error">
         Test failed.\n\nSet up error. Check whether Wi-Fi can be enabled.</string>
@@ -396,20 +432,48 @@
         Test failed.\n\nFailed to remove service request.</string>
     <string name="p2p_clear_service_requests_error">
         Test failed.\n\nFailed to clear service requests.</string>
+    <string name="p2p_connect_error">
+        Test failed.\n\nFailed to start a p2p connection to the target device.</string>
+    <string name="p2p_remove_group_error">
+        Test failed.\n\nFailed to remove a p2p group.</string>
     <string name="p2p_discover_peers_error">
         Test failed.\n\nFailed to discover peers.</string>
     <string name="p2p_discover_services_error">
         Test failed.\n\nFailed to discover services.</string>
+    <string name="p2p_ceate_group_error">
+        Test failed.\n\nFailed to start up group owner.</string>
     <string name="p2p_no_service_requests_error">
-        Test failed.\n\n\"NO_SERVICE_REQUESTS\" error did not occurred.</string>
+        Test failed.\n\n\"NO_SERVICE_REQUESTS\" error did not occur.</string>
     <string name="p2p_receive_invalid_response_error">
         Test failed.\n\nReceived an invalid message or could not receive
          the expected message.\n\n</string>
     <string name="p2p_target_not_found_error">Test failed.\n\n
         The target responder device was NOT found. Start up the responder
         test on the other device, then run the test again.</string>
+    <string name="p2p_target_invalid_role_error">Test failed.\n\n
+        The target responder must be p2p device. However, the target responder
+        device was group owner. Check the test case on the other device.</string>
+    <string name="p2p_target_invalid_role_error2">Test failed.\n\n
+        The target responder must be group owner. However, the target responder
+        device was p2p device. Check the test case on the other device.</string>
+    <string name="p2p_connection_error">
+        Test failed.\n\nFailed to establish a p2p connection.</string>
+    <string name="p2p_detect_disconnection_error">
+        Test failed.\n\nFailed to detect client disconnection.</string>
+    <string name="p2p_disconnect_error">
+        Test failed.\n\nFailed to disconnect a p2p connection.</string>
 
     <string name="p2p_search_target">Search Target</string>
     <string name="p2p_searching_target">Searching for target device ...</string>
-    <string name="p2p_executing_test">Checking the service discovery capability ...</string>
+    <string name="p2p_checking_serv_capab">Checking the service discovery
+        capability ...</string>
+    <string name="p2p_connecting_with_pbc">Trying to connect the target device ...\n\n
+        Click the \"OK\" button on the other device to accept the connection
+        request from this device.</string>
+    <string name="p2p_connecting_with_pin">Trying to connect the target device ...\n\n
+        Enter the pin number on the other device.</string>
+    <string name="p2p_waiting_for_peer_to_connect">Waiting for peer to
+        connect ...</string>
+    <string name="p2p_waiting_for_peer_to_disconnect">Waiting for peer
+        to disconnect ...</string>
 </resources>
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/GoNegRequesterTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/GoNegRequesterTestActivity.java
new file mode 100644
index 0000000..a828b23
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/GoNegRequesterTestActivity.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2012 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.p2p;
+
+import android.content.Context;
+
+import com.android.cts.verifier.p2p.testcase.GoNegReqTestSuite;
+import com.android.cts.verifier.p2p.testcase.ReqTestCase;
+
+/**
+ * Test activity that tries to connect to the p2p device with group owner negotiation.
+ * This activity is invoked from GoNegRequesterTestListActivity.
+ */
+public class GoNegRequesterTestActivity  extends RequesterTestActivity {
+
+    @Override
+    protected ReqTestCase getTestCase(Context context, String testId) {
+        return GoNegReqTestSuite.getTestCase(context, testId);
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/GoNegRequesterTestListActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/GoNegRequesterTestListActivity.java
new file mode 100644
index 0000000..059615a
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/GoNegRequesterTestListActivity.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2012 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.p2p;
+
+import java.util.ArrayList;
+
+import android.content.Context;
+import android.os.Bundle;
+
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.p2p.testcase.GoNegReqTestSuite;
+import com.android.cts.verifier.p2p.testcase.ReqTestCase;
+
+/**
+ * Activity that lists all the go negotiation requester tests.
+ */
+public class GoNegRequesterTestListActivity extends RequesterTestListActivity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setInfoResources(R.string.p2p_go_neg_requester,
+                R.string.p2p_go_neg_requester_info, -1);
+    }
+
+    @Override
+    protected ArrayList<ReqTestCase> getTestSuite(Context context) {
+        return GoNegReqTestSuite.getTestSuite(context);
+    }
+
+    @Override
+    protected Class<?> getRequesterActivityClass() {
+        return GoNegRequesterTestActivity.class;
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/GoNegResponderTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/GoNegResponderTestActivity.java
new file mode 100644
index 0000000..d4b4227
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/GoNegResponderTestActivity.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2012 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.p2p;
+
+import android.content.Context;
+import android.os.Bundle;
+
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.p2p.testcase.GoNegRespTestCase;
+import com.android.cts.verifier.p2p.testcase.TestCase;
+
+/**
+ * Test activity that responds go negotiation request.
+ */
+public class GoNegResponderTestActivity extends ResponderTestActivity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setInfoResources(R.string.p2p_go_neg_responder,
+                R.string.p2p_go_neg_responder_info, -1);
+    }
+
+    @Override
+    protected TestCase getTestCase(Context context) {
+        return new GoNegRespTestCase(context);
+    }
+
+    @Override
+    protected int getReadyMsgId() {
+        return R.string.p2p_go_neg_responder_ready;
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/GoTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/GoTestActivity.java
new file mode 100644
index 0000000..7f855b4
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/GoTestActivity.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2012 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.p2p;
+
+import android.content.Context;
+import android.os.Bundle;
+
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.p2p.testcase.GoTestCase;
+import com.android.cts.verifier.p2p.testcase.TestCase;
+
+/**
+ * Test activity that accepts a connection from p2p client.
+ */
+public class GoTestActivity extends ResponderTestActivity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setInfoResources(R.string.p2p_accept_client,
+                R.string.p2p_accept_client_info, -1);
+    }
+
+    @Override
+    protected TestCase getTestCase(Context context) {
+        return new GoTestCase(context);
+    }
+
+    @Override
+    protected int getReadyMsgId() {
+        return R.string.p2p_go_ready;
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/P2pClientTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/P2pClientTestActivity.java
new file mode 100644
index 0000000..399a52e
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/P2pClientTestActivity.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2012 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.p2p;
+
+import android.content.Context;
+
+import com.android.cts.verifier.p2p.testcase.P2pClientTestSuite;
+import com.android.cts.verifier.p2p.testcase.ReqTestCase;
+
+/**
+ * Test activity that tries to join an existing p2p group.
+ * This activity is invoked from JoinTestListActivity.
+ */
+public class P2pClientTestActivity  extends RequesterTestActivity {
+
+    @Override
+    protected ReqTestCase getTestCase(Context context, String testId) {
+        return P2pClientTestSuite.getTestCase(context, testId);
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/P2pClientTestListActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/P2pClientTestListActivity.java
new file mode 100644
index 0000000..efd75b7
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/P2pClientTestListActivity.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2012 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.p2p;
+
+import java.util.ArrayList;
+
+import android.content.Context;
+import android.os.Bundle;
+
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.p2p.testcase.P2pClientTestSuite;
+import com.android.cts.verifier.p2p.testcase.ReqTestCase;
+
+/**
+ * Activity that lists all the joining group owner tests.
+ */
+public class P2pClientTestListActivity extends RequesterTestListActivity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setInfoResources(R.string.p2p_join_go,
+                R.string.p2p_join_go_info, -1);
+    }
+
+    @Override
+    protected ArrayList<ReqTestCase> getTestSuite(Context context) {
+        return P2pClientTestSuite.getTestSuite(context);
+    }
+
+    @Override
+    protected Class<?> getRequesterActivityClass() {
+        return P2pClientTestActivity.class;
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/P2pTestListActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/P2pTestListActivity.java
index e32edab..d133eda 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/P2pTestListActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/P2pTestListActivity.java
@@ -66,6 +66,27 @@
          * Added WiFiDirect test activity to the list.
          */
         ArrayTestListAdapter adapter = new ArrayTestListAdapter(this);
+
+        adapter.add(TestListItem.newCategory(this, R.string.p2p_group_formation));
+        adapter.add(TestListItem.newTest(this,
+                R.string.p2p_go_neg_responder_test,
+                GoNegResponderTestActivity.class.getName(),
+                new Intent(this, GoNegResponderTestActivity.class), null));
+        adapter.add(TestListItem.newTest(this,
+                R.string.p2p_go_neg_requester_test,
+                GoNegRequesterTestListActivity.class.getName(),
+                new Intent(this, GoNegRequesterTestListActivity.class), null));
+
+        adapter.add(TestListItem.newCategory(this, R.string.p2p_join));
+        adapter.add(TestListItem.newTest(this,
+                R.string.p2p_group_owner_test,
+                GoTestActivity.class.getName(),
+                new Intent(this, GoTestActivity.class), null));
+        adapter.add(TestListItem.newTest(this,
+                R.string.p2p_group_client_test,
+                P2pClientTestListActivity.class.getName(),
+                new Intent(this, P2pClientTestListActivity.class), null));
+
         adapter.add(TestListItem.newCategory(this, R.string.p2p_service_discovery));
         adapter.add(TestListItem.newTest(this,
                 R.string.p2p_service_discovery_responder_test,
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/RequesterTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/RequesterTestActivity.java
new file mode 100644
index 0000000..9540463
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/RequesterTestActivity.java
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 2012 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.p2p;
+
+import java.util.Collection;
+import java.util.Timer;
+import java.util.TimerTask;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.net.wifi.p2p.WifiP2pDevice;
+import android.net.wifi.p2p.WifiP2pDeviceList;
+import android.net.wifi.p2p.WifiP2pManager;
+import android.net.wifi.p2p.WifiP2pManager.Channel;
+import android.net.wifi.p2p.WifiP2pManager.PeerListListener;
+import android.os.Bundle;
+import android.os.Handler;
+import android.view.WindowManager;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.R.id;
+import com.android.cts.verifier.p2p.testcase.ReqTestCase;
+import com.android.cts.verifier.p2p.testcase.TestCase;
+import com.android.cts.verifier.p2p.testcase.TestCase.TestCaseListener;
+
+/**
+ * A base class for requester test activity.
+ *
+ * This class provides the feature to search target device and show test results.
+ * A requester test activity just have to extend this class and implement getTestCase().
+ */
+public abstract class RequesterTestActivity  extends PassFailButtons.Activity
+    implements TestCaseListener {
+
+    /*
+     * Timeout for searching devices. The unit is millisecond
+     */
+    private final static int SEARCH_TARGET_TIMEOUT = 8000;
+
+    /*
+     * The target device address.
+     * The service discovery request test needs the responder address.
+     * The target device address is reused until test failed.
+     */
+    private static String sTargetAddr;
+
+    /*
+     * The test case to be executed.
+     */
+    private ReqTestCase mTestCase;
+
+    /*
+     * The text view to print the test result
+     */
+    private TextView mTextView;
+
+    /*
+     * The progress bar.
+     */
+    private ProgressBar mProgress;
+
+    /*
+     * GUI thread handler.
+     */
+    private Handler mHandler = new Handler();
+
+    /*
+     * Timer object. It's used for searching devices.
+     */
+    private Timer mTimer;
+
+    /*
+     * p2p manager
+     */
+    private WifiP2pManager mP2pMgr;
+    private Channel mChannel;
+
+    /**
+     * Return the specified requester test case.
+     *
+     * @param context
+     * @param testId test id.
+     * @return requester test case
+     */
+    protected abstract ReqTestCase getTestCase(Context context, String testId);
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.p2p_requester_main);
+        setPassFailButtonClickListeners();
+        getPassButton().setEnabled(false);
+
+        mProgress = (ProgressBar) findViewById(R.id.p2p_progress);
+        mProgress.setVisibility(ProgressBar.VISIBLE);
+        mTextView = (TextView) findViewById(id.p2p_req_text);
+
+        String testId = (String) getIntent().getSerializableExtra(
+                TestCase.EXTRA_TEST_NAME);
+        mTestCase = getTestCase(this, testId);
+        setTitle(mTestCase.getTestName());
+
+        // Initialize p2p manager.
+        mP2pMgr = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
+        mChannel = mP2pMgr.initialize(this, getMainLooper(), null);
+
+        // keep screen on while this activity is front view.
+        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        /*
+         * If the target device is NOT set, search targets and show
+         * the target device list on the dialog.
+         * After the user selection, the specified test will be executed.
+         */
+        if (sTargetAddr == null) {
+            searchTarget();
+            return;
+        }
+
+        mTestCase.setTargetAddress(sTargetAddr);
+        mTestCase.start(this);
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+        if (mTimer != null) {
+            mTimer.cancel();
+            mTimer = null;
+        }
+        mTestCase.stop();
+    }
+
+    @Override
+    public String getTestId() {
+        return mTestCase.getTestId();
+    }
+
+    @Override
+    public void onTestStarted() {
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                mProgress.setVisibility(ProgressBar.VISIBLE);
+            }
+        });
+    }
+
+    public void onTestMsgReceived(final String msg) {
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                mTextView.setText(msg);
+            }
+        });
+    }
+
+    @Override
+    public void onTestFailed(final String reason) {
+        // if test failed, forget target device address.
+        sTargetAddr = null;
+
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                mProgress.setVisibility(ProgressBar.INVISIBLE);
+                mTextView.setText(reason);
+            }
+        });
+    }
+
+    @Override
+    public void onTestSuccess() {
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                mProgress.setVisibility(ProgressBar.INVISIBLE);
+                mTextView.setText(R.string.p2p_result_success);
+                getPassButton().setEnabled(true);
+            }
+        });
+    }
+
+    /**
+     * Search devices and show the found devices on the dialog.
+     * After user selection, the specified test will be executed.
+     */
+    private void searchTarget() {
+        // Discover peers.
+        mP2pMgr.discoverPeers(mChannel, null);
+        mTextView.setText(R.string.p2p_searching_target);
+        mProgress.setVisibility(ProgressBar.VISIBLE);
+
+        /*
+         * Show the peer list dialog after searching devices for 8 seconds.
+         */
+        if (mTimer == null) {
+            mTimer = new Timer(true);
+        }
+        mTimer.schedule(new TimerTask() {
+            @Override
+            public void run() {
+                mP2pMgr.requestPeers(mChannel, new PeerListListener() {
+                    @Override
+                    public void onPeersAvailable(WifiP2pDeviceList _peers) {
+                        final WifiP2pDeviceList peers = _peers;
+                        /*
+                         * Need to show dialog in GUI thread.
+                         */
+                        mHandler.post(new Runnable() {
+                            @Override
+                            public void run() {
+                                mProgress.setVisibility(ProgressBar.INVISIBLE);
+                                if (peers.getDeviceList().size() == 0) {
+                                    mTextView.setText(
+                                            R.string.p2p_target_not_found_error);
+                                } else {
+                                    showSelectTargetDialog(peers);
+                                }
+                            }
+                        });
+                    }
+                });
+            }
+        }, SEARCH_TARGET_TIMEOUT);
+    }
+
+    /**
+     * Show the found device list on the dialog.
+     * The target device address selected by user is stored in {@link #mTargetAddr}.
+     * After user selection, the specified test will be executed.
+     * @param peers
+     * @param testIndex
+     */
+    private void showSelectTargetDialog(WifiP2pDeviceList peers) {
+        final Collection<WifiP2pDevice> peerList = peers.getDeviceList();
+        final CharSequence[] items = new CharSequence[peerList.size()];
+        int i=0;
+        for (WifiP2pDevice dev: peerList) {
+            items[i++] = dev.deviceName;
+        }
+
+        new AlertDialog.Builder(this)
+                .setIcon(android.R.drawable.ic_dialog_info)
+                .setTitle(R.string.p2p_search_target)
+                .setItems(items, new android.content.DialogInterface.OnClickListener() {
+            @Override
+            public void onClick(DialogInterface dialog, int which) {
+                int i=0;
+                for (WifiP2pDevice dev: peerList) {
+                    if (i == which) {
+                        sTargetAddr = dev.deviceAddress;
+                        mTestCase.setTargetAddress(sTargetAddr);
+                        mTestCase.start(getTestCaseListener());
+                        break;
+                    }
+                    i++;
+                }
+            }
+        }).show();
+    }
+
+    private TestCaseListener getTestCaseListener() {
+        return this;
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/RequesterTestListActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/RequesterTestListActivity.java
new file mode 100644
index 0000000..e6f94af
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/RequesterTestListActivity.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2012 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.p2p;
+
+import java.util.ArrayList;
+
+import android.content.Context;
+import android.content.Intent;
+import android.database.DataSetObserver;
+import android.os.Bundle;
+
+import com.android.cts.verifier.ArrayTestListAdapter;
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.TestListAdapter;
+import com.android.cts.verifier.TestListAdapter.TestListItem;
+import com.android.cts.verifier.p2p.testcase.ReqTestCase;
+import com.android.cts.verifier.p2p.testcase.TestCase;
+
+/**
+ * A base class for requester test list activity.
+ *
+ * This class provides the feature to list all the requester test cases.
+ * A requester test list activity just have to extend this class and implement
+ * getTestSuite() and getRequesterActivityClass().
+ */
+public abstract class RequesterTestListActivity extends
+     PassFailButtons.TestListActivity {
+
+    /**
+     * Test list view adapter
+     */
+    protected TestListAdapter mAdapter;
+
+    /**
+     * Return test suite to be listed.
+     * @param context
+     * @return test suite
+     */
+    protected abstract ArrayList<ReqTestCase> getTestSuite(Context context);
+
+    /**
+     * Return requester activity class.
+     * @return
+     */
+    protected abstract Class<?> getRequesterActivityClass();
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.pass_fail_list);
+        setPassFailButtonClickListeners();
+        getPassButton().setEnabled(false);
+
+        mAdapter = getTestListAdapter();
+        setTestListAdapter(mAdapter);
+    }
+
+    /**
+     * Get test list view adapter
+     * @return
+     */
+    private TestListAdapter getTestListAdapter() {
+        ArrayTestListAdapter adapter = new ArrayTestListAdapter(this);
+
+        for (ReqTestCase testcase: getTestSuite(this)) {
+            addTestCase(adapter, testcase);
+        }
+
+        adapter.registerDataSetObserver(new DataSetObserver() {
+            @Override
+            public void onChanged() {
+                updatePassButton();
+            }
+        });
+
+        return adapter;
+    }
+
+    /**
+     * Add test case to test list view adapter.
+     * @param adapter
+     * @param testcase
+     */
+    private void addTestCase(ArrayTestListAdapter adapter, TestCase testcase) {
+        Intent intent = new Intent(this, getRequesterActivityClass());
+        intent.putExtra(TestCase.EXTRA_TEST_NAME,
+                testcase.getTestId());
+        adapter.add(TestListItem.newTest(testcase.getTestName(), testcase.getTestId(),
+                intent, null));
+    }
+
+    /**
+     * Enable Pass Button when the all tests passed.
+     */
+    private void updatePassButton() {
+        getPassButton().setEnabled(mAdapter.allTestsPassed());
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/ResponderTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/ResponderTestActivity.java
new file mode 100644
index 0000000..4285a1a
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/ResponderTestActivity.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2012 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.p2p;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.wifi.p2p.WifiP2pDevice;
+import android.net.wifi.p2p.WifiP2pManager;
+import android.os.Bundle;
+import android.os.Handler;
+import android.view.WindowManager;
+import android.widget.TextView;
+
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.R.id;
+import com.android.cts.verifier.p2p.testcase.TestCase;
+import com.android.cts.verifier.p2p.testcase.TestCase.TestCaseListener;
+
+/**
+ * A base class for responder test activity.
+ *
+ * This class provides the feature to show own device name and test results.
+ * A responder test activity just have to extend this class and implement getTestCase()
+ * and getReadyMsgId().
+ */
+public abstract class ResponderTestActivity extends PassFailButtons.Activity
+    implements TestCaseListener {
+
+    /*
+     * Test case to be executed
+     */
+    private TestCase mTestCase;
+
+    /*
+     * Text view to show the result of the test.
+     */
+    private TextView mTextView;
+
+    /*
+     * Text view to show own device name.
+     * It would be helpful to select this device on the other device.
+     */
+    private TextView mMyDeviceView;
+
+    /*
+     * BroadcastReceiver to obtain own device information.
+     */
+    private final P2pBroadcastReceiver mReceiver = new P2pBroadcastReceiver();
+    private final IntentFilter mIntentFilter = new IntentFilter();
+    private Handler mHandler = new Handler();
+
+    /**
+     * Constructor
+     */
+    public ResponderTestActivity() {
+        mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
+    }
+
+    abstract protected TestCase getTestCase(Context context);
+
+    abstract protected int getReadyMsgId();
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.p2p_responder_main);
+        setPassFailButtonClickListeners();
+        getPassButton().setEnabled(false);
+
+        // Get UI component.
+        mTextView = (TextView) findViewById(id.p2p_resp_text);
+        mMyDeviceView = (TextView) findViewById(id.p2p_my_device);
+
+        // Initialize test components.
+        mTestCase = getTestCase(this);
+
+        // keep screen on while this activity is front view.
+        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        mTestCase.start(this);
+        registerReceiver(mReceiver, mIntentFilter);
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+        mTestCase.stop();
+        unregisterReceiver(mReceiver);
+    }
+
+    /**
+     * Receive the WIFI_P2P_THIS_DEVICE_CHANGED_ACTION action and show the
+     * this device information in the text view.
+     */
+    class P2pBroadcastReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) {
+                final WifiP2pDevice myDevice = (WifiP2pDevice) intent.getParcelableExtra(
+                        WifiP2pManager.EXTRA_WIFI_P2P_DEVICE);
+                if (myDevice != null) {
+                    // need to show in the GUI thread.
+                    mHandler.post(new Runnable() {
+                        @Override
+                        public void run() {
+                            mMyDeviceView.setText("Device Name: " + myDevice.deviceName);
+                        }
+                    });
+                }
+            }
+        }
+    }
+
+    @Override
+    public void onTestStarted() {
+    }
+
+    public void onTestMsgReceived(final String msg) {
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                mTextView.setText(msg);
+            }
+        });
+    }
+
+    @Override
+    public void onTestSuccess() {
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                mTextView.setText(getReadyMsgId());
+                getPassButton().setEnabled(true);
+            }
+        });
+    }
+
+    @Override
+    public void onTestFailed(final String reason) {
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                mTextView.setText(reason);
+            }
+        });
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/ServiceRequesterTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/ServiceRequesterTestActivity.java
index d34117d..2dea01b 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/ServiceRequesterTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/ServiceRequesterTestActivity.java
@@ -15,256 +15,19 @@
  */
 package com.android.cts.verifier.p2p;
 
-import java.util.Collection;
-import java.util.Timer;
-import java.util.TimerTask;
-
-import android.app.AlertDialog;
 import android.content.Context;
-import android.content.DialogInterface;
-import android.net.wifi.p2p.WifiP2pDevice;
-import android.net.wifi.p2p.WifiP2pDeviceList;
-import android.net.wifi.p2p.WifiP2pManager;
-import android.net.wifi.p2p.WifiP2pManager.Channel;
-import android.net.wifi.p2p.WifiP2pManager.PeerListListener;
-import android.os.Bundle;
-import android.os.Handler;
-import android.view.WindowManager;
-import android.widget.ProgressBar;
-import android.widget.TextView;
 
-import com.android.cts.verifier.PassFailButtons;
-import com.android.cts.verifier.R;
-import com.android.cts.verifier.R.id;
+import com.android.cts.verifier.p2p.testcase.ReqTestCase;
 import com.android.cts.verifier.p2p.testcase.ServReqTestSuite;
-import com.android.cts.verifier.p2p.testcase.ServReqTestCase;
-import com.android.cts.verifier.p2p.testcase.TestCase.TestCaseListener;
 
 /**
  * Test activity that sends service discovery request.
  * This activity is invoked from ServiceRequesterTestListActivity.
- * And the test case id to be executed is stored in Intent.
  */
-public class ServiceRequesterTestActivity extends PassFailButtons.Activity
-    implements TestCaseListener {
-
-    /*
-     * The test case id.
-     */
-    static final String EXTRA_TEST_NAME =
-            "com.android.cts.verifier.p2p.testcase.EXTRA_TEST_NAME";
-
-    /*
-     * Timeout for searching devices. The unit is millisecond
-     */
-    private final static int SEARCH_TARGET_TIMEOUT = 8000;
-
-    /*
-     * The target device address.
-     * The service discovery request test needs the responder address.
-     * The target device address is reused until test failed.
-     */
-    private static String sTargetAddr;
-
-    /*
-     * The test case to be executed.
-     */
-    private ServReqTestCase mTestCase;
-
-    /*
-     * The text view to print the test result
-     */
-    private TextView mTextView;
-
-    /*
-     * The progress bar.
-     */
-    private ProgressBar mProgress;
-
-    /*
-     * GUI thread handler.
-     */
-    private Handler mHandler = new Handler();
-
-    /*
-     * Timer object. It's used for searching devices.
-     */
-    private Timer mTimer;
-
-    /*
-     * p2p manager
-     */
-    private WifiP2pManager mP2pMgr;
-    private Channel mChannel;
+public class ServiceRequesterTestActivity extends RequesterTestActivity {
 
     @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.p2p_requester_main);
-        setPassFailButtonClickListeners();
-        getPassButton().setEnabled(false);
-
-        mProgress = (ProgressBar) findViewById(R.id.p2p_progress);
-        mProgress.setVisibility(ProgressBar.VISIBLE);
-        mTextView = (TextView) findViewById(id.p2p_req_text);
-
-        String testId = (String) getIntent().getSerializableExtra(EXTRA_TEST_NAME);
-        mTestCase = ServReqTestSuite.getTestCase(this, testId);
-        setTitle(mTestCase.getTestName());
-
-        // Initialize p2p manager.
-        mP2pMgr = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
-        mChannel = mP2pMgr.initialize(this, getMainLooper(), null);
-
-        // keep screen on while this activity is front view.
-        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
-    }
-
-    @Override
-    protected void onResume() {
-        super.onResume();
-        /*
-         * If the target device is NOT set, search targets and show
-         * the target device list on the dialog.
-         * After the user selection, the specified test will be executed.
-         */
-        if (sTargetAddr == null) {
-            searchTarget();
-            return;
-        }
-
-        mTestCase.setTargetAddress(sTargetAddr);
-        mTestCase.start(this);
-    }
-
-    @Override
-    protected void onPause() {
-        super.onPause();
-        if (mTimer != null) {
-            mTimer.cancel();
-            mTimer = null;
-        }
-        mTestCase.stop();
-    }
-
-    @Override
-    public String getTestId() {
-        return mTestCase.getTestId();
-    }
-
-    @Override
-    public void onTestStarted() {
-        mHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                mTextView.setText(R.string.p2p_executing_test);
-                mProgress.setVisibility(ProgressBar.VISIBLE);
-            }
-        });
-    }
-
-    @Override
-    public void onTestFailed(final String reason) {
-        // if test failed, forget target device address.
-        sTargetAddr = null;
-
-        mHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                mProgress.setVisibility(ProgressBar.INVISIBLE);
-                mTextView.setText(reason);
-            }
-        });
-    }
-
-    @Override
-    public void onTestSuccess() {
-        mHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                mProgress.setVisibility(ProgressBar.INVISIBLE);
-                mTextView.setText(R.string.p2p_result_success);
-                getPassButton().setEnabled(true);
-            }
-        });
-    }
-
-    /**
-     * Search devices and show the found devices on the dialog.
-     * After user selection, the specified test will be executed.
-     */
-    private void searchTarget() {
-        // Discover peers.
-        mP2pMgr.discoverPeers(mChannel, null);
-        mTextView.setText(R.string.p2p_searching_target);
-        mProgress.setVisibility(ProgressBar.VISIBLE);
-
-        /*
-         * Show the peer list dialog after searching devices for 8 seconds.
-         */
-        if (mTimer == null) {
-            mTimer = new Timer(true);
-        }
-        mTimer.schedule(new TimerTask() {
-            @Override
-            public void run() {
-                mP2pMgr.requestPeers(mChannel, new PeerListListener() {
-                    @Override
-                    public void onPeersAvailable(WifiP2pDeviceList _peers) {
-                        final WifiP2pDeviceList peers = _peers;
-                        /*
-                         * Need to show dialog in GUI thread.
-                         */
-                        mHandler.post(new Runnable() {
-                            @Override
-                            public void run() {
-                                mProgress.setVisibility(ProgressBar.INVISIBLE);
-                                if (peers.getDeviceList().size() == 0) {
-                                    mTextView.setText(
-                                            R.string.p2p_target_not_found_error);
-                                } else {
-                                    showSelectTargetDialog(peers);
-                                }
-                            }
-                        });
-                    }
-                });
-            }
-        }, SEARCH_TARGET_TIMEOUT);
-    }
-
-    /**
-     * Show the found device list on the dialog.
-     * The target device address selected by user is stored in {@link #mTargetAddr}.
-     * After user selection, the specified test will be executed.
-     * @param peers
-     * @param testIndex
-     */
-    private void showSelectTargetDialog(WifiP2pDeviceList peers) {
-        final Collection<WifiP2pDevice> peerList = peers.getDeviceList();
-        final CharSequence[] items = new CharSequence[peerList.size()];
-        int i=0;
-        for (WifiP2pDevice dev: peerList) {
-            items[i++] = dev.deviceName;
-        }
-
-        new AlertDialog.Builder(this)
-                .setIcon(android.R.drawable.ic_dialog_info)
-                .setTitle(R.string.p2p_search_target)
-                .setItems(items, new android.content.DialogInterface.OnClickListener() {
-            @Override
-            public void onClick(DialogInterface dialog, int which) {
-                int i=0;
-                for (WifiP2pDevice dev: peerList) {
-                    if (i == which) {
-                        sTargetAddr = dev.deviceAddress;
-                        mTestCase.setTargetAddress(sTargetAddr);
-                        mTestCase.start(ServiceRequesterTestActivity.this);
-                        break;
-                    }
-                    i++;
-                }
-            }
-        }).show();
+    protected ReqTestCase getTestCase(Context context, String testId) {
+        return ServReqTestSuite.getTestCase(context, testId);
     }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/ServiceRequesterTestListActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/ServiceRequesterTestListActivity.java
index 7d0e66c..ecade33 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/ServiceRequesterTestListActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/ServiceRequesterTestListActivity.java
@@ -15,82 +15,34 @@
  */
 package com.android.cts.verifier.p2p;
 
-import android.content.Intent;
-import android.database.DataSetObserver;
+import java.util.ArrayList;
+
+import android.content.Context;
 import android.os.Bundle;
 
-import com.android.cts.verifier.ArrayTestListAdapter;
-import com.android.cts.verifier.PassFailButtons;
 import com.android.cts.verifier.R;
-import com.android.cts.verifier.TestListAdapter;
-import com.android.cts.verifier.TestListAdapter.TestListItem;
-import com.android.cts.verifier.p2p.testcase.ServReqTestCase;
+import com.android.cts.verifier.p2p.testcase.ReqTestCase;
 import com.android.cts.verifier.p2p.testcase.ServReqTestSuite;
-import com.android.cts.verifier.p2p.testcase.TestCase;
 
 /**
  * Activity that lists all the service discovery requester tests.
  */
-public class ServiceRequesterTestListActivity extends PassFailButtons.TestListActivity {
-
-    /**
-     * Test list view adapter
-     */
-    protected TestListAdapter mAdapter;
+public class ServiceRequesterTestListActivity extends RequesterTestListActivity {
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-
-        setContentView(R.layout.pass_fail_list);
-        setPassFailButtonClickListeners();
         setInfoResources(R.string.p2p_service_discovery_requester,
                 R.string.p2p_service_discovery_requester_info, -1);
-
-        getPassButton().setEnabled(false);
-
-        mAdapter = getTestListAdapter();
-        setTestListAdapter(mAdapter);
     }
 
-    /**
-     * Get test list view adapter
-     * @return
-     */
-    private TestListAdapter getTestListAdapter() {
-        ArrayTestListAdapter adapter = new ArrayTestListAdapter(this);
-
-        for (ServReqTestCase testcase: ServReqTestSuite.getTestSuite(this)) {
-            addTestCase(adapter, testcase);
-        }
-
-        adapter.registerDataSetObserver(new DataSetObserver() {
-            @Override
-            public void onChanged() {
-                updatePassButton();
-            }
-        });
-
-        return adapter;
+    @Override
+    protected ArrayList<ReqTestCase> getTestSuite(Context context) {
+        return ServReqTestSuite.getTestSuite(context);
     }
 
-    /**
-     * Add test case to test list view adapter.
-     * @param adapter
-     * @param testcase
-     */
-    private void addTestCase(ArrayTestListAdapter adapter, TestCase testcase) {
-        Intent intent = new Intent(this, ServiceRequesterTestActivity.class);
-        intent.putExtra(ServiceRequesterTestActivity.EXTRA_TEST_NAME,
-                testcase.getTestId());
-        adapter.add(TestListItem.newTest(testcase.getTestName(), testcase.getTestId(),
-                intent, null));
-    }
-
-    /**
-     * Enable Pass Button when the all tests passed.
-     */
-    private void updatePassButton() {
-        getPassButton().setEnabled(mAdapter.allTestsPassed());
+    @Override
+    protected Class<?> getRequesterActivityClass() {
+        return ServiceRequesterTestActivity.class;
     }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/ServiceResponderTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/ServiceResponderTestActivity.java
index 2753673..d732383 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/ServiceResponderTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/ServiceResponderTestActivity.java
@@ -15,139 +15,32 @@
  */
 package com.android.cts.verifier.p2p;
 
-import android.content.BroadcastReceiver;
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.net.wifi.p2p.WifiP2pDevice;
-import android.net.wifi.p2p.WifiP2pManager;
 import android.os.Bundle;
-import android.os.Handler;
-import android.view.WindowManager;
-import android.widget.TextView;
 
-import com.android.cts.verifier.PassFailButtons;
 import com.android.cts.verifier.R;
-import com.android.cts.verifier.R.id;
 import com.android.cts.verifier.p2p.testcase.ServRespTestCase;
-import com.android.cts.verifier.p2p.testcase.TestCase.TestCaseListener;
+import com.android.cts.verifier.p2p.testcase.TestCase;
 
 /**
  * Test activity that responds service discovery request.
  */
-public class ServiceResponderTestActivity extends PassFailButtons.Activity
-    implements TestCaseListener {
-
-    /*
-     * Test case to be executed
-     */
-    private ServRespTestCase mTestCase;
-
-    /*
-     * Text view to show the result of the test.
-     */
-    private TextView mTextView;
-
-    /*
-     * Text view to show own device name.
-     * It would be helpful to select this device on the other device.
-     */
-    private TextView mMyDeviceView;
-
-    /*
-     * BroadcastReceiver to obtain own device information.
-     */
-    private final P2pBroadcastReceiver mReceiver = new P2pBroadcastReceiver();
-    private final IntentFilter mIntentFilter = new IntentFilter();
-    private Handler mHandler = new Handler();
-
-    /**
-     * Constructor
-     */
-    public ServiceResponderTestActivity() {
-        mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
-    }
+public class ServiceResponderTestActivity extends ResponderTestActivity {
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        setContentView(R.layout.p2p_responder_main);
         setInfoResources(R.string.p2p_service_discovery_responder,
                 R.string.p2p_service_discovery_responder_info, -1);
-        setPassFailButtonClickListeners();
-        getPassButton().setEnabled(false);
-
-        // Get UI component.
-        mTextView = (TextView) findViewById(id.p2p_resp_text);
-        mMyDeviceView = (TextView) findViewById(id.p2p_my_device);
-
-        // Initialize test components.
-        mTestCase = new ServRespTestCase(this);
-
-        // keep screen on while this activity is front view.
-        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
     }
 
     @Override
-    protected void onResume() {
-        super.onResume();
-        mTestCase.start(this);
-        registerReceiver(mReceiver, mIntentFilter);
+    protected TestCase getTestCase(Context context) {
+        return new ServRespTestCase(context);
     }
 
     @Override
-    protected void onPause() {
-        super.onPause();
-        mTestCase.stop();
-        unregisterReceiver(mReceiver);
-    }
-
-    /**
-     * Receive the WIFI_P2P_THIS_DEVICE_CHANGED_ACTION action and show the
-     * this device information in the text view.
-     */
-    class P2pBroadcastReceiver extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) {
-                final WifiP2pDevice myDevice = (WifiP2pDevice) intent.getParcelableExtra(
-                        WifiP2pManager.EXTRA_WIFI_P2P_DEVICE);
-                if (myDevice != null) {
-                    // need to show in the GUI thread.
-                    mHandler.post(new Runnable() {
-                        @Override
-                        public void run() {
-                            mMyDeviceView.setText("Device Name: " + myDevice.deviceName);
-                        }
-                    });
-                }
-            }
-        }
-    }
-
-    @Override
-    public void onTestStarted() {
-    }
-
-    @Override
-    public void onTestSuccess() {
-        mHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                mTextView.setText(R.string.p2p_responder_ready);
-                getPassButton().setEnabled(true);
-            }
-        });
-    }
-
-    @Override
-    public void onTestFailed(final String reason) {
-        mHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                mTextView.setText(reason);
-            }
-        });
+    protected int getReadyMsgId() {
+        return R.string.p2p_service_responder_ready;
     }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ConnectReqTestCase.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ConnectReqTestCase.java
new file mode 100644
index 0000000..02e7040
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ConnectReqTestCase.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2012 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.p2p.testcase;
+
+import android.content.Context;
+import android.net.wifi.WpsInfo;
+import android.net.wifi.p2p.WifiP2pConfig;
+import android.net.wifi.p2p.WifiP2pDevice;
+import android.net.wifi.p2p.WifiP2pInfo;
+
+import com.android.cts.verifier.R;
+
+/**
+ * A base class for connection request test.
+ */
+public abstract class ConnectReqTestCase extends ReqTestCase {
+
+    protected P2pBroadcastReceiverTest mReceiverTest;
+
+    public ConnectReqTestCase(Context context) {
+        super(context);
+    }
+
+    /**
+     * Set up the test case.
+     */
+    protected void setUp() {
+        super.setUp();
+        mReceiverTest = new P2pBroadcastReceiverTest(mContext);
+        mReceiverTest.init(mChannel);
+    }
+
+    /**
+     * Tear down the test case.
+     */
+    protected void tearDown() {
+        super.tearDown();
+        if (mReceiverTest != null) {
+            mReceiverTest.close();
+        }
+        if (mP2pMgr != null) {
+            mP2pMgr.cancelConnect(mChannel, null);
+            mP2pMgr.removeGroup(mChannel, null);
+        }
+    }
+
+    /**
+     * Tries to connect the target devices.
+     * @param isJoin if true, try to join the group. otherwise, try go negotiation.
+     * @param wpsConfig wps configuration method.
+     * @return true if succeeded.
+     * @throws InterruptedException
+     */
+    protected boolean connectTest(boolean isJoin, int wpsConfig) throws InterruptedException {
+        notifyTestMsg(R.string.p2p_searching_target);
+
+        /*
+         * Search target device and check its capability.
+         */
+        ActionListenerTest actionListener = new ActionListenerTest();
+        mP2pMgr.discoverPeers(mChannel, actionListener);
+        if (!actionListener.check(ActionListenerTest.SUCCESS, TIMEOUT)) {
+            mReason = mContext.getString(R.string.p2p_discover_peers_error);
+            return false;
+        }
+
+        WifiP2pDevice dev = mReceiverTest.waitDeviceFound(mTargetAddress, TIMEOUT);
+        if (dev == null) {
+            mReason = mContext.getString(R.string.p2p_target_not_found_error);
+            return false;
+        }
+
+        if (!isJoin && dev.isGroupOwner()) {
+            // target device should be p2p device.
+            mReason = mContext.getString(R.string.p2p_target_invalid_role_error);
+            return false;
+        } else if (isJoin && !dev.isGroupOwner()) {
+            //target device should be group owner.
+            mReason = mContext.getString(R.string.p2p_target_invalid_role_error2);
+            return false;
+        }
+
+        if (wpsConfig == WpsInfo.PBC) {
+            notifyTestMsg(R.string.p2p_connecting_with_pbc);
+        } else {
+            notifyTestMsg(R.string.p2p_connecting_with_pin);
+        }
+
+        /*
+         * Try to connect the target device.
+         */
+        WifiP2pConfig config = new WifiP2pConfig();
+        config.deviceAddress = dev.deviceAddress;
+        config.wps.setup = wpsConfig;
+        mP2pMgr.connect(mChannel, config, actionListener);
+        if (!actionListener.check(ActionListenerTest.SUCCESS, TIMEOUT)) {
+            mReason = mContext.getString(R.string.p2p_connect_error);
+            return false;
+        }
+
+        /*
+         * Check if the connection broadcast is received.
+         */
+        WifiP2pInfo p2pInfo = mReceiverTest.waitConnectionNotice(TIMEOUT_FOR_USER_ACTION);
+        if (p2pInfo == null) {
+            mReason = mContext.getString(R.string.p2p_connection_error);
+            return false;
+        }
+
+        /*
+         * Wait until peer gets marked conencted.
+         */
+        notifyTestMsg(R.string.p2p_waiting_for_peer_to_connect);
+        if (mReceiverTest.waitPeerConnected(mTargetAddress, TIMEOUT) != true) {
+            mReason = mContext.getString(R.string.p2p_connection_error);
+            return false;
+        }
+
+        /*
+         * Remove the p2p group manualy.
+         */
+        mP2pMgr.removeGroup(mChannel, actionListener);
+        if (!actionListener.check(ActionListenerTest.SUCCESS, TIMEOUT)) {
+            mReason = mContext.getString(R.string.p2p_remove_group_error);
+            return false;
+        }
+
+        notifyTestMsg(R.string.p2p_waiting_for_peer_to_disconnect);
+
+        /*
+         * Check if p2p disconnection broadcast is received
+         */
+        p2pInfo = mReceiverTest.waitDisconnectionNotice(TIMEOUT);
+        if (p2pInfo == null) {
+            mReason = mContext.getString(R.string.p2p_connection_error);
+            return false;
+        }
+
+        /* Wait until peer gets marked disconnected */
+
+        if (mReceiverTest.waitPeerDisconnected(mTargetAddress, TIMEOUT) != true) {
+            mReason = mContext.getString(R.string.p2p_detect_disconnection_error);
+            return false;
+        }
+
+        return true;
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/DnsSdTxtRecordListenerTest.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/DnsSdTxtRecordListenerTest.java
index a342be4..3d8f2ce 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/DnsSdTxtRecordListenerTest.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/DnsSdTxtRecordListenerTest.java
@@ -61,8 +61,8 @@
 
     @Override
     public void onDnsSdTxtRecordAvailable(String fullDomainName,
-            Map<String, String> record, WifiP2pDevice srcDevice) {
-        Log.d(TAG, fullDomainName + " " + record + " received from "
+            Map<String, String> txtRecordMap, WifiP2pDevice srcDevice) {
+        Log.d(TAG, fullDomainName + " " + txtRecordMap + " received from "
                 + srcDevice.deviceAddress);
 
         /*
@@ -70,7 +70,7 @@
          * The response from other devices are ignored.
          */
         if (srcDevice.deviceAddress.equalsIgnoreCase(mTargetAddr)) {
-            receiveCallback(new Argument(fullDomainName, record));
+            receiveCallback(new Argument(fullDomainName, txtRecordMap));
         }
     }
 
@@ -78,14 +78,14 @@
         String ippDomainName = "myprinter._ipp._tcp.local.";
         String afpDomainName = "example._afpovertcp._tcp.local.";
 
-        HashMap<String, String> IppTxtRecord = new HashMap<String, String>();
-        HashMap<String, String> afpTxtRecord = new HashMap<String, String>();
-        IppTxtRecord.put("txtvers", "1");
-        IppTxtRecord.put("pdl", "application/postscript");
+        Map<String, String> ippTxtRecord = new HashMap<String, String>();
+        Map<String, String> afpTxtRecord = new HashMap<String, String>();
+        ippTxtRecord.put("txtvers", "1");
+        ippTxtRecord.put("pdl", "application/postscript");
 
-        IPP_DNS_TXT.add(new Argument(ippDomainName, IppTxtRecord));
+        IPP_DNS_TXT.add(new Argument(ippDomainName, ippTxtRecord));
         AFP_DNS_TXT.add(new Argument(afpDomainName, afpTxtRecord));
-        ALL_DNS_TXT.add(new Argument(ippDomainName, IppTxtRecord));
+        ALL_DNS_TXT.add(new Argument(ippDomainName, ippTxtRecord));
         ALL_DNS_TXT.add(new Argument(afpDomainName, afpTxtRecord));
     }
 
@@ -95,16 +95,16 @@
     static class Argument extends ListenerArgument {
 
         private String mFullDomainName;
-        private Map<String, String> mRecord;
+        private Map<String, String> mTxtRecordMap;
 
         /**
          * Set the argument of {@link #onDnsSdTxtRecordAvailable}.
          * @param fullDomainName full domain name.
-         * @param record txt record.
+         * @param txtRecordMap txt record map.
          */
-        Argument(String fullDomainName, Map<String, String> record) {
+        Argument(String fullDomainName, Map<String, String> txtRecordMap) {
             mFullDomainName = fullDomainName;
-            mRecord = record;
+            mTxtRecordMap = txtRecordMap;
         }
 
         @Override
@@ -114,7 +114,7 @@
             }
             Argument arg = (Argument)obj;
             return equals(mFullDomainName, arg.mFullDomainName) &&
-                    equals(mRecord, arg.mRecord);
+                    equals(mTxtRecordMap, arg.mTxtRecordMap);
         }
 
         private boolean equals(String s1, String s2) {
@@ -139,7 +139,7 @@
 
         @Override
         public String toString() {
-            return "domainName=" + mFullDomainName + " record='" + mRecord + "'";
+            return "domainName=" + mFullDomainName + " record='" + mTxtRecordMap + "'";
         }
     }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/GoNegReqPbcTestCase.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/GoNegReqPbcTestCase.java
new file mode 100644
index 0000000..1b14350
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/GoNegReqPbcTestCase.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2012 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.p2p.testcase;
+
+import android.content.Context;
+import android.net.wifi.WpsInfo;
+
+/**
+ * Test case to try go negotiation with wps push button.
+ */
+public class GoNegReqPbcTestCase extends ConnectReqTestCase {
+
+    public GoNegReqPbcTestCase(Context context) {
+        super(context);
+    }
+
+    @Override
+    protected boolean executeTest() throws InterruptedException {
+        return connectTest(false, WpsInfo.PBC);
+    }
+
+    @Override
+    public String getTestName() {
+        return "Go negotiation test (push button)";
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/GoNegReqPinTestCase.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/GoNegReqPinTestCase.java
new file mode 100644
index 0000000..dda4e4e
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/GoNegReqPinTestCase.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2012 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.p2p.testcase;
+
+import android.content.Context;
+import android.net.wifi.WpsInfo;
+
+/**
+ * Test case to try go negotiation with wps pin code.
+ */
+public class GoNegReqPinTestCase extends ConnectReqTestCase {
+
+    public GoNegReqPinTestCase(Context context) {
+        super(context);
+    }
+
+    @Override
+    protected boolean executeTest() throws InterruptedException {
+        return connectTest(false, WpsInfo.DISPLAY);
+    }
+
+    @Override
+    public String getTestName() {
+        return "Go negotiation test (PIN)";
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/GoNegReqTestSuite.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/GoNegReqTestSuite.java
new file mode 100644
index 0000000..9905ac8
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/GoNegReqTestSuite.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2012 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.p2p.testcase;
+
+import java.util.ArrayList;
+
+import android.content.Context;
+
+/**
+ * Test suite for go negotiation requester.
+ */
+public class GoNegReqTestSuite {
+
+    private static ArrayList<ReqTestCase> sTestSuite = null;
+
+    /**
+     * Return test suite.
+     * @param context
+     * @return
+     */
+    public static ArrayList<ReqTestCase> getTestSuite(Context context) {
+        initialize(context);
+        return sTestSuite;
+    }
+
+    /**
+     * Return the specified test case.
+     * @param context
+     * @param testId
+     * @return
+     */
+    public static ReqTestCase getTestCase(Context context,
+            String testId) {
+        initialize(context);
+
+        for (ReqTestCase test: sTestSuite) {
+            if (test.getTestId().equals(testId)) {
+                return test;
+            }
+        }
+        return null;
+    }
+
+    private static void initialize(Context context) {
+        if (sTestSuite != null) {
+            return;
+        }
+
+        sTestSuite = new ArrayList<ReqTestCase>();
+        sTestSuite.add(new GoNegReqPbcTestCase(context));
+        sTestSuite.add(new GoNegReqPinTestCase(context));
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/GoNegRespTestCase.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/GoNegRespTestCase.java
new file mode 100644
index 0000000..ebf41a4
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/GoNegRespTestCase.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2012 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.p2p.testcase;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.wifi.p2p.WifiP2pInfo;
+import android.net.wifi.p2p.WifiP2pManager;
+
+/**
+ * Test case for go negotiation response.
+ *
+ * The requester devices tries to connect this device.
+ */
+public class GoNegRespTestCase extends TestCase {
+
+    private final IntentFilter mIntentFilter = new IntentFilter();
+    private WifiP2pBroadcastReceiver mReceiver;
+
+    public GoNegRespTestCase(Context context) {
+        super(context);
+        mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
+        mReceiver = new WifiP2pBroadcastReceiver();
+    }
+
+    @Override
+    protected void setUp() {
+        mContext.registerReceiver(mReceiver, mIntentFilter);
+        super.setUp();
+    }
+
+    @Override
+    protected boolean executeTest() throws InterruptedException {
+
+        mP2pMgr.discoverPeers(mChannel, null);
+
+        // wait until p2p device is trying go negotiation.
+        return true;
+    }
+
+
+    @Override
+    protected void tearDown() {
+        // wait until p2p device is trying go negotiation.
+        synchronized(this) {
+            try {
+                wait();
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+        }
+        if (mP2pMgr != null) {
+            mP2pMgr.cancelConnect(mChannel, null);
+            mP2pMgr.removeGroup(mChannel, null);
+        }
+        mContext.unregisterReceiver(mReceiver);
+
+        super.tearDown();
+    }
+
+
+    @Override
+    public String getTestName() {
+        return "Go negotiation responder test";
+    }
+
+    private class WifiP2pBroadcastReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {
+                synchronized(this) {
+                    WifiP2pInfo p2pInfo = (WifiP2pInfo)intent.getParcelableExtra(
+                            WifiP2pManager.EXTRA_WIFI_P2P_INFO);
+                    if (p2pInfo.groupFormed && !p2pInfo.isGroupOwner) {
+                        /*
+                         * Remove p2p group for next test once your device became p2p client.
+                         * In the case of GO, p2p group will be removed automatically because
+                         * target device will cut the connection.
+                         */
+                        mP2pMgr.removeGroup(mChannel, null);
+                    } else if (!p2pInfo.groupFormed) {
+                        /*
+                         * find again.
+                         */
+                        mP2pMgr.discoverPeers(mChannel, null);
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/GoTestCase.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/GoTestCase.java
new file mode 100644
index 0000000..73d822e
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/GoTestCase.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2012 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.p2p.testcase;
+
+import android.content.Context;
+import android.net.wifi.p2p.WifiP2pInfo;
+
+import com.android.cts.verifier.R;
+
+/**
+ * A test case which accepts a connection from p2p client.
+ *
+ * The requester device tries to join this device.
+ */
+public class GoTestCase extends TestCase {
+
+    protected P2pBroadcastReceiverTest mReceiverTest;
+
+    public GoTestCase(Context context) {
+        super(context);
+    }
+
+    @Override
+    protected void setUp() {
+        super.setUp();
+        mReceiverTest = new P2pBroadcastReceiverTest(mContext);
+        mReceiverTest.init(mChannel);
+    }
+
+    @Override
+    protected boolean executeTest() throws InterruptedException {
+
+        ActionListenerTest listener = new ActionListenerTest();
+
+        /*
+         * Add renderer service
+         */
+        mP2pMgr.addLocalService(mChannel, LocalServices.createRendererService(),
+                listener);
+        if (!listener.check(ActionListenerTest.SUCCESS, TIMEOUT)) {
+            mReason = mContext.getString(R.string.p2p_add_local_service_error);
+            return false;
+        }
+
+        /*
+         * Add IPP service
+         */
+        mP2pMgr.addLocalService(mChannel, LocalServices.createIppService(),
+                listener);
+        if (!listener.check(ActionListenerTest.SUCCESS, TIMEOUT)) {
+            mReason = mContext.getString(R.string.p2p_add_local_service_error);
+            return false;
+        }
+
+        /*
+         * Add AFP service
+         */
+        mP2pMgr.addLocalService(mChannel, LocalServices.createAfpService(),
+                listener);
+        if (!listener.check(ActionListenerTest.SUCCESS, TIMEOUT)) {
+            mReason = mContext.getString(R.string.p2p_add_local_service_error);
+            return false;
+        }
+
+        /*
+         * Start up an autonomous group owner.
+         */
+        mP2pMgr.createGroup(mChannel, listener);
+        if (!listener.check(ActionListenerTest.SUCCESS, TIMEOUT)) {
+            mReason = mContext.getString(R.string.p2p_ceate_group_error);
+            return false;
+        }
+
+        /*
+         * Check whether createGroup() is succeeded.
+         */
+        WifiP2pInfo info = mReceiverTest.waitConnectionNotice(TIMEOUT);
+        if (info == null || !info.isGroupOwner) {
+            mReason = mContext.getString(R.string.p2p_ceate_group_error);
+            return false;
+        }
+
+        // wait until p2p client is joining.
+        return true;
+    }
+
+    @Override
+    protected void tearDown() {
+
+        // wait until p2p client is joining.
+        synchronized(this) {
+            try {
+                wait();
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+        }
+
+        if (mP2pMgr != null) {
+            mP2pMgr.cancelConnect(mChannel, null);
+            mP2pMgr.removeGroup(mChannel, null);
+        }
+        if (mReceiverTest != null) {
+            mReceiverTest.close();
+        }
+        super.tearDown();
+    }
+
+    @Override
+    public String getTestName() {
+        return "Accept client connection test";
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/LocalServices.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/LocalServices.java
new file mode 100644
index 0000000..2e8fdce
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/LocalServices.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2012 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.p2p.testcase;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceInfo;
+import android.net.wifi.p2p.nsd.WifiP2pServiceInfo;
+import android.net.wifi.p2p.nsd.WifiP2pUpnpServiceInfo;
+
+public class LocalServices {
+
+
+    /**
+     * Create UPnP MediaRenderer local service.
+     * @return
+     */
+    static WifiP2pServiceInfo createRendererService() {
+        List<String> services = new ArrayList<String>();
+        services.add("urn:schemas-upnp-org:service:AVTransport:1");
+        services.add("urn:schemas-upnp-org:service:ConnectionManager:1");
+        return WifiP2pUpnpServiceInfo.newInstance(
+                "6859dede-8574-59ab-9332-123456789011",
+                "urn:schemas-upnp-org:device:MediaRenderer:1",
+                services);
+    }
+
+    /**
+     * Create Bonjour IPP local service.
+     * @return
+     */
+    static WifiP2pServiceInfo createIppService() {
+        Map<String, String> txtRecord = new HashMap<String, String>();
+        txtRecord.put("txtvers", "1");
+        txtRecord.put("pdl", "application/postscript");
+        return WifiP2pDnsSdServiceInfo.newInstance("MyPrinter",
+                "_ipp._tcp", txtRecord);
+    }
+
+    /**
+     * Create Bonjour AFP local service.
+     * @return
+     */
+    static WifiP2pServiceInfo createAfpService() {
+        return WifiP2pDnsSdServiceInfo.newInstance("Example",
+                "_afpovertcp._tcp", null);
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/P2pBroadcastReceiverTest.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/P2pBroadcastReceiverTest.java
new file mode 100644
index 0000000..14c3ddb
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/P2pBroadcastReceiverTest.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2012 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.p2p.testcase;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.wifi.p2p.WifiP2pDevice;
+import android.net.wifi.p2p.WifiP2pDeviceList;
+import android.net.wifi.p2p.WifiP2pInfo;
+import android.net.wifi.p2p.WifiP2pManager;
+import android.net.wifi.p2p.WifiP2pManager.Channel;
+import android.net.wifi.p2p.WifiP2pManager.PeerListListener;
+import android.util.Log;
+
+/**
+ * The utility class for testing wifi direct broadcast intent.
+ */
+public class P2pBroadcastReceiverTest extends BroadcastReceiver
+    implements PeerListListener {
+
+    private static final String TAG = "P2pBroadcastReceiverTest";
+
+    private final IntentFilter mIntentFilter = new IntentFilter();
+    private Context mContext;
+    private WifiP2pManager mP2pMgr;
+    private Channel mChannel;
+
+    private WifiP2pDeviceList mPeers;
+    private WifiP2pInfo mP2pInfo;
+
+    public P2pBroadcastReceiverTest(Context context) {
+        this.mContext = context;
+        mP2pMgr = (WifiP2pManager) context.getSystemService(Context.WIFI_P2P_SERVICE);
+        mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
+        mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
+        mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
+        mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
+    }
+
+    public void init(Channel c) {
+        mChannel = c;
+        mContext.registerReceiver(this, mIntentFilter);
+    }
+
+    public synchronized void close() {
+        mContext.unregisterReceiver(this);
+        notifyAll();
+    }
+
+    /**
+     * Wait until the specified target device is found.
+     *
+     * @param targetAddr the p2p device address of the target device.
+     * @param msec timeout value.
+     * @return the found device. Return null if the target device is not found
+     * within the given timeout.
+     * @throws InterruptedException
+     */
+    public synchronized WifiP2pDevice waitDeviceFound(String targetAddr, long msec)
+            throws InterruptedException {
+
+        Timeout t = new Timeout(msec);
+        while (!t.isTimeout()) {
+            if (mPeers != null) {
+                for (WifiP2pDevice dev: mPeers.getDeviceList()) {
+                    if (dev.deviceAddress.equals(targetAddr)) {
+                        return dev;
+                    }
+                }
+            }
+            wait(t.getRemainTime());
+        }
+        Log.e(TAG, "Appropriate WIFI_P2P_PEERS_CHANGED_ACTION didn't occur");
+
+        return null;
+    }
+
+    /**
+     * Wait until a p2p group is created.
+     *
+     * @param msec timeout value
+     * @return a established p2p information. Return null if a connection is NOT
+     * established within the given timeout.
+     * @throws InterruptedException
+     */
+    public synchronized WifiP2pInfo waitConnectionNotice(long msec) throws InterruptedException {
+        Timeout t = new Timeout(msec);
+        while (!t.isTimeout()) {
+            if (mP2pInfo != null && mP2pInfo.groupFormed) {
+                return mP2pInfo;
+            }
+            wait(t.getRemainTime());
+        }
+        Log.e(TAG, "Appropriate WIFI_P2P_CONNECTION_CHANGED_ACTION didn't occur");
+
+        return null;
+    }
+
+    /**
+     * Wait until a station gets connected.
+     * @param msec
+     * @return
+     * @throws InterruptedException
+     */
+    public synchronized boolean waitPeerConnected(String targetAddr, long msec)
+            throws InterruptedException {
+
+        Timeout t = new Timeout(msec);
+        while (!t.isTimeout()) {
+            if (mPeers != null) {
+                for (WifiP2pDevice dev: mPeers.getDeviceList()) {
+                    if (dev.deviceAddress.equals(targetAddr)) {
+                        if (dev.status == WifiP2pDevice.CONNECTED) {
+                            return true;
+                        }
+                    }
+                }
+            }
+            wait(t.getRemainTime());
+        }
+        Log.e(TAG, "Appropriate WIFI_P2P_PEERS_CHANGED_ACTION didn't occur");
+
+        return false;
+    }
+
+    /**
+     * Wait until a station gets disconnected.
+     * @param msec
+     * @return
+     * @throws InterruptedException
+     */
+    public synchronized boolean waitPeerDisconnected(String targetAddr, long msec)
+            throws InterruptedException {
+
+        Timeout t = new Timeout(msec);
+
+        boolean devicePresent;
+
+        while (!t.isTimeout()) {
+            devicePresent = false;
+            if (mPeers != null) {
+                for (WifiP2pDevice dev: mPeers.getDeviceList()) {
+                    if (dev.deviceAddress.equals(targetAddr)) {
+                        if (dev.status != WifiP2pDevice.CONNECTED) {
+                            return true;
+                        }
+                        devicePresent = true;
+                    }
+                }
+            }
+            if (!devicePresent) return true;
+            wait(t.getRemainTime());
+        }
+        Log.e(TAG, "Appropriate WIFI_P2P_PEERS_CHANGED_ACTION didn't occur");
+
+        return false;
+    }
+
+    /**
+     * Wait until a connection is disconnected.
+     *
+     * @param msec timeout value.
+     * @return a disconnected p2p information. Return null if a connection is NOT disconnected
+     * within the given timeout.
+     * @throws InterruptedException
+     */
+    public synchronized WifiP2pInfo waitDisconnectionNotice(long msec) throws InterruptedException {
+        Timeout t = new Timeout(msec);
+        while (!t.isTimeout()) {
+            if (mP2pInfo != null && !mP2pInfo.groupFormed) {
+                return mP2pInfo;
+            }
+            wait(t.getRemainTime());
+        }
+        Log.e(TAG, "WIFI_P2P_CONNECTION_CHANGED_ACTION didn't occur");
+
+        return null;
+    }
+
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        String action = intent.getAction();
+        if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
+            Log.d(TAG, "WIFI_P2P_PEERS_CHANGED_ACTION");
+            mP2pMgr.requestPeers(mChannel, this);
+        } else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {
+            Log.d(TAG, "WIFI_P2P_CONNECTION_CHANGED_ACTION");
+            synchronized(this) {
+                mP2pInfo = (WifiP2pInfo)intent.getParcelableExtra(
+                        WifiP2pManager.EXTRA_WIFI_P2P_INFO);
+                notifyAll();
+            }
+        }
+    }
+
+    @Override
+    public synchronized void onPeersAvailable(WifiP2pDeviceList peers) {
+        Log.d(TAG, "onPeersAvailable()");
+        mPeers = peers;
+        notifyAll();
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/P2pClientPbcTestCase.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/P2pClientPbcTestCase.java
new file mode 100644
index 0000000..249af3b7
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/P2pClientPbcTestCase.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2012 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.p2p.testcase;
+
+import com.android.cts.verifier.R;
+
+import android.content.Context;
+import android.net.wifi.WpsInfo;
+import android.net.wifi.p2p.nsd.WifiP2pUpnpServiceRequest;
+
+/**
+ * Test case to join a p2p group with wps push button.
+ */
+public class P2pClientPbcTestCase extends ConnectReqTestCase {
+
+    public P2pClientPbcTestCase(Context context) {
+        super(context);
+    }
+
+    @Override
+    protected boolean executeTest() throws InterruptedException {
+
+        if (!checkUpnpService()) {
+            return false;
+        }
+
+        return connectTest(true, WpsInfo.PBC);
+    }
+
+    /**
+     * Check UPnP service on GO through service discovery request.
+     * @return true if success.
+     * @throws InterruptedException
+     */
+    private boolean checkUpnpService() throws InterruptedException {
+        notifyTestMsg(R.string.p2p_checking_serv_capab);
+        ActionListenerTest actionListener = new ActionListenerTest();
+
+        /*
+         * Check UPnP services.
+         */
+        WifiP2pUpnpServiceRequest upnpReq = WifiP2pUpnpServiceRequest.newInstance();
+
+        /*
+         * add UPnP request.
+         */
+        mP2pMgr.addServiceRequest(mChannel, upnpReq, actionListener);
+        if (!actionListener.check(ActionListenerTest.SUCCESS, TIMEOUT)) {
+            mReason = mContext.getString(R.string.p2p_add_service_request_error);
+            return false;
+        }
+
+        /*
+         * Initialize listener test objects.
+         */
+        UPnPServiceResponseListenerTest upnpListener =
+                new UPnPServiceResponseListenerTest(mTargetAddress);
+        DnsSdResponseListenerTest dnsListener =
+                new DnsSdResponseListenerTest(mTargetAddress);
+        DnsSdTxtRecordListenerTest txtListener =
+                new DnsSdTxtRecordListenerTest(mTargetAddress);
+
+        /*
+         * set service response listener callback.
+         */
+        mP2pMgr.setUpnpServiceResponseListener(mChannel, upnpListener);
+        mP2pMgr.setDnsSdResponseListeners(mChannel, dnsListener, txtListener);
+
+        /*
+         * discover services
+         */
+        mP2pMgr.discoverServices(mChannel, actionListener);
+        if (!actionListener.check(ActionListenerTest.SUCCESS, TIMEOUT)) {
+            mReason = mContext.getString(R.string.p2p_discover_services_error);
+            return false;
+        }
+
+        /*
+         * Receive only UPnP service.
+         */
+        Timeout t = new Timeout(TIMEOUT);
+        if (!dnsListener.check(DnsSdResponseListenerTest.NO_DNS_PTR,
+                t.getRemainTime())) {
+            mReason = getListenerError(dnsListener);
+            return false;
+        }
+        if (!txtListener.check(DnsSdTxtRecordListenerTest.NO_DNS_TXT,
+                t.getRemainTime())) {
+            mReason = getListenerError(txtListener);
+            return false;
+        }
+        if (!upnpListener.check(
+                UPnPServiceResponseListenerTest.ALL_UPNP_SERVICES,
+                t.getRemainTime())) {
+            mReason = getListenerError(upnpListener);
+            return false;
+        }
+
+        return true;
+    }
+
+    private String getListenerError(ListenerTest listener) {
+        StringBuilder sb = new StringBuilder();
+        sb.append(mContext.getText(R.string.p2p_receive_invalid_response_error));
+        sb.append(listener.getReason());
+        return sb.toString();
+    }
+
+    @Override
+    public String getTestName() {
+        return "Join p2p group test (push button)";
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/P2pClientPinTestCase.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/P2pClientPinTestCase.java
new file mode 100644
index 0000000..063918e
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/P2pClientPinTestCase.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2012 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.p2p.testcase;
+
+import android.content.Context;
+import android.net.wifi.WpsInfo;
+import android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceRequest;
+
+import com.android.cts.verifier.R;
+
+/**
+ * Test case to join a p2p group with wps pincode.
+ */
+public class P2pClientPinTestCase extends ConnectReqTestCase {
+
+    public P2pClientPinTestCase(Context context) {
+        super(context);
+    }
+
+    @Override
+    protected boolean executeTest() throws InterruptedException {
+
+        if (!checkBonjourService()) {
+            return false;
+        }
+
+        return connectTest(true, WpsInfo.DISPLAY);
+    }
+
+    /**
+     * Check Bonjour service on GO through service discovery request.
+     * @return true if success.
+     * @throws InterruptedException
+     */
+    private boolean checkBonjourService() throws InterruptedException {
+        notifyTestMsg(R.string.p2p_checking_serv_capab);
+        ActionListenerTest actionListener = new ActionListenerTest();
+
+        /*
+         * add Bonjour request.
+         */
+        WifiP2pDnsSdServiceRequest bonjourReq =
+            WifiP2pDnsSdServiceRequest.newInstance();
+        mP2pMgr.addServiceRequest(mSubChannel, bonjourReq, actionListener);
+        if (!actionListener.check(ActionListenerTest.SUCCESS, TIMEOUT)) {
+            mReason = mContext.getString(R.string.p2p_add_service_request_error);
+            return false;
+        }
+
+        /*
+         * Initialize listener test objects.
+         */
+        UPnPServiceResponseListenerTest upnpListener =
+                new UPnPServiceResponseListenerTest(mTargetAddress);
+        DnsSdResponseListenerTest dnsListener =
+                new DnsSdResponseListenerTest(mTargetAddress);
+        DnsSdTxtRecordListenerTest txtListener =
+                new DnsSdTxtRecordListenerTest(mTargetAddress);
+
+        /*
+         * set service response listener callback.
+         */
+        mP2pMgr.setUpnpServiceResponseListener(mSubChannel, upnpListener);
+        mP2pMgr.setDnsSdResponseListeners(mSubChannel, dnsListener, txtListener);
+
+        /*
+         * discover services
+         */
+        mP2pMgr.discoverServices(mChannel, actionListener);
+        if (!actionListener.check(ActionListenerTest.SUCCESS, TIMEOUT)) {
+            mReason = mContext.getString(R.string.p2p_discover_services_error);
+            return false;
+        }
+
+        /*
+         * Receive only Bonjour service.
+         */
+        Timeout t = new Timeout(TIMEOUT);
+        if (!dnsListener.check(DnsSdResponseListenerTest.ALL_DNS_PTR,
+                t.getRemainTime())) {
+            mReason = getListenerError(dnsListener);
+            return false;
+        }
+        if (!txtListener.check(DnsSdTxtRecordListenerTest.ALL_DNS_TXT,
+                t.getRemainTime())) {
+            mReason = getListenerError(txtListener);
+            return false;
+        }
+        if (!upnpListener.check(
+                UPnPServiceResponseListenerTest.NO_UPNP_SERVICES,
+                t.getRemainTime())) {
+            mReason = getListenerError(upnpListener);
+            return false;
+        }
+
+        return true;
+    }
+
+    private String getListenerError(ListenerTest listener) {
+        StringBuilder sb = new StringBuilder();
+        sb.append(mContext.getText(R.string.p2p_receive_invalid_response_error));
+        sb.append(listener.getReason());
+        return sb.toString();
+    }
+
+    @Override
+    public String getTestName() {
+        return "Join p2p group test (PIN)";
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/P2pClientTestSuite.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/P2pClientTestSuite.java
new file mode 100644
index 0000000..a9fd27a
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/P2pClientTestSuite.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2012 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.p2p.testcase;
+
+import java.util.ArrayList;
+
+import android.content.Context;
+
+/**
+ * Test suite to join a p2p group.
+ */
+public class P2pClientTestSuite {
+
+    private static ArrayList<ReqTestCase> sTestSuite = null;
+
+    /**
+     * Return test suite.
+     * @param context
+     * @return
+     */
+    public static ArrayList<ReqTestCase> getTestSuite(Context context) {
+        initialize(context);
+        return sTestSuite;
+    }
+
+    /**
+     * Return the specified test case.
+     * @param context
+     * @param testId
+     * @return
+     */
+    public static ReqTestCase getTestCase(Context context,
+            String testId) {
+        initialize(context);
+
+        for (ReqTestCase test: sTestSuite) {
+            if (test.getTestId().equals(testId)) {
+                return test;
+            }
+        }
+        return null;
+    }
+
+    private static void initialize(Context context) {
+        if (sTestSuite != null) {
+            return;
+        }
+
+        sTestSuite = new ArrayList<ReqTestCase>();
+        sTestSuite.add(new P2pClientPbcTestCase(context));
+        sTestSuite.add(new P2pClientPinTestCase(context));
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ReqTestCase.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ReqTestCase.java
new file mode 100644
index 0000000..244724f
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ReqTestCase.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2012 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.p2p.testcase;
+
+import android.content.Context;
+
+/**
+ * A base test case for requester.
+ */
+public abstract class ReqTestCase extends TestCase {
+
+    public ReqTestCase(Context context) {
+        super(context);
+    }
+
+    /**
+     * The target device address.
+     * The requester checks only the response of this target device.
+     */
+    protected String mTargetAddress;
+
+    /**
+     * Set target device address.
+     * @param targetAddress
+     */
+    public void setTargetAddress(String targetAddress) {
+        this.mTargetAddress = targetAddress;
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServReqAllTestCase01.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServReqAllTestCase01.java
index f2936ed..aefbdef 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServReqAllTestCase01.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServReqAllTestCase01.java
@@ -19,6 +19,8 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import com.android.cts.verifier.R;
+
 import android.content.Context;
 import android.net.wifi.p2p.nsd.WifiP2pServiceInfo;
 import android.net.wifi.p2p.nsd.WifiP2pServiceRequest;
@@ -36,6 +38,8 @@
     @Override
     protected boolean executeTest() throws InterruptedException {
 
+        notifyTestMsg(R.string.p2p_checking_serv_capab);
+
         /*
          * create request to search all services.
          */
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServReqAllTestCase02.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServReqAllTestCase02.java
index 0888cdf..e1ba990 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServReqAllTestCase02.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServReqAllTestCase02.java
@@ -19,6 +19,8 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import com.android.cts.verifier.R;
+
 import android.content.Context;
 import android.net.wifi.p2p.nsd.WifiP2pServiceInfo;
 import android.net.wifi.p2p.nsd.WifiP2pServiceRequest;
@@ -37,6 +39,8 @@
     @Override
     protected boolean executeTest() throws InterruptedException {
 
+        notifyTestMsg(R.string.p2p_checking_serv_capab);
+
         /*
          * create request to search all services.
          */
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServReqAllTestCase03.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServReqAllTestCase03.java
index 0d5dcf9..b40d359 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServReqAllTestCase03.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServReqAllTestCase03.java
@@ -19,6 +19,8 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import com.android.cts.verifier.R;
+
 import android.content.Context;
 import android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceRequest;
 import android.net.wifi.p2p.nsd.WifiP2pServiceRequest;
@@ -38,6 +40,8 @@
     @Override
     protected boolean executeTest() throws InterruptedException {
 
+        notifyTestMsg(R.string.p2p_checking_serv_capab);
+
         /*
          * create request to search all services.
          */
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServReqClearRequestTestCase.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServReqClearRequestTestCase.java
index c7e4fa4..1aa271e 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServReqClearRequestTestCase.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServReqClearRequestTestCase.java
@@ -32,6 +32,9 @@
 
     @Override
     protected boolean executeTest() throws InterruptedException {
+
+        notifyTestMsg(R.string.p2p_checking_serv_capab);
+
         ActionListenerTest actionListener = new ActionListenerTest();
 
         /*
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServReqDnsPtrTestCase.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServReqDnsPtrTestCase.java
index 6194bf6..ad6cfad 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServReqDnsPtrTestCase.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServReqDnsPtrTestCase.java
@@ -18,6 +18,8 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import com.android.cts.verifier.R;
+
 import android.content.Context;
 import android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceRequest;
 import android.net.wifi.p2p.nsd.WifiP2pServiceRequest;
@@ -34,6 +36,8 @@
     @Override
     protected boolean executeTest() throws InterruptedException {
 
+        notifyTestMsg(R.string.p2p_checking_serv_capab);
+
         /*
          * create request to search bonjour ipp PTR.
          */
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServReqDnsTxtTestCase.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServReqDnsTxtTestCase.java
index 9fc09b6..4ae55aa 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServReqDnsTxtTestCase.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServReqDnsTxtTestCase.java
@@ -18,6 +18,8 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import com.android.cts.verifier.R;
+
 import android.content.Context;
 import android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceRequest;
 import android.net.wifi.p2p.nsd.WifiP2pServiceRequest;
@@ -34,6 +36,8 @@
     @Override
     protected boolean executeTest() throws InterruptedException {
 
+        notifyTestMsg(R.string.p2p_checking_serv_capab);
+
         /*
          * create request to search bonjour ipp TXT.
          */
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServReqMultiClientTestCase01.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServReqMultiClientTestCase01.java
index a18a0d9..b205326 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServReqMultiClientTestCase01.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServReqMultiClientTestCase01.java
@@ -33,6 +33,9 @@
 
     @Override
     protected boolean executeTest() throws InterruptedException {
+
+        notifyTestMsg(R.string.p2p_checking_serv_capab);
+
         ActionListenerTest actionListener = new ActionListenerTest();
 
         /*
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServReqMultiClientTestCase02.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServReqMultiClientTestCase02.java
index 8844d0d..144d18c 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServReqMultiClientTestCase02.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServReqMultiClientTestCase02.java
@@ -32,6 +32,9 @@
 
     @Override
     protected boolean executeTest() throws InterruptedException {
+
+        notifyTestMsg(R.string.p2p_checking_serv_capab);
+
         ActionListenerTest actionListener = new ActionListenerTest();
 
         /*
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServReqMultiClientTestCase03.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServReqMultiClientTestCase03.java
index dd30df2..8eb71ae 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServReqMultiClientTestCase03.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServReqMultiClientTestCase03.java
@@ -32,6 +32,9 @@
 
     @Override
     protected boolean executeTest() throws InterruptedException {
+
+        notifyTestMsg(R.string.p2p_checking_serv_capab);
+
         ActionListenerTest actionListener = new ActionListenerTest();
 
         WifiP2pDnsSdServiceRequest bonjourReq =
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServReqRemoveRequestTestCase.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServReqRemoveRequestTestCase.java
index 120b3f9..a4f47f6 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServReqRemoveRequestTestCase.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServReqRemoveRequestTestCase.java
@@ -32,6 +32,9 @@
 
     @Override
     protected boolean executeTest() throws InterruptedException {
+
+        notifyTestMsg(R.string.p2p_checking_serv_capab);
+
         ActionListenerTest actionListener = new ActionListenerTest();
 
         /*
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServReqTestCase.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServReqTestCase.java
index bc6b86c..a559996 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServReqTestCase.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServReqTestCase.java
@@ -27,27 +27,13 @@
  * The base class for service discovery requester test case.
  * The common functions are defined in this class.
  */
-public abstract class ServReqTestCase extends TestCase {
+public abstract class ServReqTestCase extends ReqTestCase {
 
     public ServReqTestCase(Context context) {
         super(context);
     }
 
     /**
-     * The target device address.
-     * The requester checks only the response of this target device.
-     */
-    protected String mTargetAddress;
-
-    /**
-     * Set target device address.
-     * @param targetAddress
-     */
-    public void setTargetAddress(String targetAddress) {
-        this.mTargetAddress = targetAddress;
-    }
-
-    /**
      * Search test.
      *
      * 1. Add the specified service requests to the framework.<br>
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServReqTestSuite.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServReqTestSuite.java
index 2611a9f..a493141 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServReqTestSuite.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServReqTestSuite.java
@@ -22,18 +22,18 @@
 
 public class ServReqTestSuite {
 
-    private static ArrayList<ServReqTestCase> sTestSuite = null;
+    private static ArrayList<ReqTestCase> sTestSuite = null;
 
-    public static ArrayList<ServReqTestCase> getTestSuite(Context context) {
+    public static ArrayList<ReqTestCase> getTestSuite(Context context) {
         initialize(context);
         return sTestSuite;
     }
 
-    public static ServReqTestCase getTestCase(Context context,
+    public static ReqTestCase getTestCase(Context context,
             String testId) {
         initialize(context);
 
-        for (ServReqTestCase test: sTestSuite) {
+        for (ReqTestCase test: sTestSuite) {
             if (test.getTestId().equals(testId)) {
                 return test;
             }
@@ -46,7 +46,7 @@
             return;
         }
 
-        sTestSuite = new ArrayList<ServReqTestCase>();
+        sTestSuite = new ArrayList<ReqTestCase>();
         sTestSuite.add(new ServReqAllTestCase01(context));
         sTestSuite.add(new ServReqAllTestCase02(context));
         sTestSuite.add(new ServReqAllTestCase03(context));
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServReqUpnpAllTestCase.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServReqUpnpAllTestCase.java
index e37cc1a..8aa2901 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServReqUpnpAllTestCase.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServReqUpnpAllTestCase.java
@@ -18,6 +18,8 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import com.android.cts.verifier.R;
+
 import android.content.Context;
 import android.net.wifi.p2p.nsd.WifiP2pServiceRequest;
 import android.net.wifi.p2p.nsd.WifiP2pUpnpServiceRequest;
@@ -34,6 +36,8 @@
     @Override
     protected boolean executeTest() throws InterruptedException {
 
+        notifyTestMsg(R.string.p2p_checking_serv_capab);
+
         /*
          * create request to search all UPnP services with "ssdp:all".
          */
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServReqUpnpRootDeviceTestCase.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServReqUpnpRootDeviceTestCase.java
index 4b09818..8a9e37c 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServReqUpnpRootDeviceTestCase.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServReqUpnpRootDeviceTestCase.java
@@ -18,6 +18,8 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import com.android.cts.verifier.R;
+
 import android.content.Context;
 import android.net.wifi.p2p.nsd.WifiP2pServiceRequest;
 import android.net.wifi.p2p.nsd.WifiP2pUpnpServiceRequest;
@@ -34,6 +36,8 @@
     @Override
     protected boolean executeTest() throws InterruptedException {
 
+        notifyTestMsg(R.string.p2p_checking_serv_capab);
+
         /*
          * create request to search UPnP root device
          */
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServRespTestCase.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServRespTestCase.java
index e71d12f..838a4be 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServRespTestCase.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ServRespTestCase.java
@@ -15,16 +15,10 @@
  */
 package com.android.cts.verifier.p2p.testcase;
 
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
 import java.util.Timer;
 import java.util.TimerTask;
 
 import android.content.Context;
-import android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceInfo;
-import android.net.wifi.p2p.nsd.WifiP2pServiceInfo;
-import android.net.wifi.p2p.nsd.WifiP2pUpnpServiceInfo;
 
 import com.android.cts.verifier.R;
 
@@ -56,7 +50,8 @@
         /*
          * Add renderer service
          */
-        mP2pMgr.addLocalService(mChannel, createRendererService(), listenerTest);
+        mP2pMgr.addLocalService(mChannel, LocalServices.createRendererService(),
+                listenerTest);
         if (!listenerTest.check(ActionListenerTest.SUCCESS, TIMEOUT)) {
             mReason = mContext.getString(R.string.p2p_add_local_service_error);
             return false;
@@ -65,7 +60,8 @@
         /*
          * Add IPP service
          */
-        mP2pMgr.addLocalService(mChannel, createIppService(), listenerTest);
+        mP2pMgr.addLocalService(mChannel, LocalServices.createIppService(),
+                listenerTest);
         if (!listenerTest.check(ActionListenerTest.SUCCESS, TIMEOUT)) {
             mReason = mContext.getString(R.string.p2p_add_local_service_error);
             return false;
@@ -74,7 +70,8 @@
         /*
          * Add AFP service
          */
-        mP2pMgr.addLocalService(mChannel, createAfpService(), listenerTest);
+        mP2pMgr.addLocalService(mChannel, LocalServices.createAfpService(),
+                listenerTest);
         if (!listenerTest.check(ActionListenerTest.SUCCESS, TIMEOUT)) {
             mReason = mContext.getString(R.string.p2p_add_local_service_error);
             return false;
@@ -116,45 +113,12 @@
                 e.printStackTrace();
             }
         }
-        mTimer.cancel();
+        if (mTimer != null) {
+            mTimer.cancel();
+        }
         super.tearDown();
     }
 
-    /**
-     * Create UPnP MediaRenderer local service.
-     * @return
-     */
-    private WifiP2pServiceInfo createRendererService() {
-        List<String> services = new ArrayList<String>();
-        services.add("urn:schemas-upnp-org:service:AVTransport:1");
-        services.add("urn:schemas-upnp-org:service:ConnectionManager:1");
-        return WifiP2pUpnpServiceInfo.newInstance(
-                "6859dede-8574-59ab-9332-123456789011",
-                "urn:schemas-upnp-org:device:MediaRenderer:1",
-                services);
-    }
-
-    /**
-     * Create Bonjour IPP local service.
-     * @return
-     */
-    private WifiP2pServiceInfo createIppService() {
-        HashMap<String, String> txtRecord = new HashMap<String, String>();
-        txtRecord.put("txtvers", "1");
-        txtRecord.put("pdl", "application/postscript");
-        return WifiP2pDnsSdServiceInfo.newInstance("MyPrinter",
-                "_ipp._tcp", txtRecord);
-    }
-
-    /**
-     * Create Bonjour AFP local service.
-     * @return
-     */
-    private WifiP2pServiceInfo createAfpService() {
-        return WifiP2pDnsSdServiceInfo.newInstance("Example",
-                "_afpovertcp._tcp", null);
-    }
-
     @Override
     public String getTestName() {
         return "Service discovery responder test";
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/TestCase.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/TestCase.java
index 21312f3..f34bdb2 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/TestCase.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/TestCase.java
@@ -35,7 +35,14 @@
  */
 public abstract class TestCase {
 
+    /*
+     * The test case id.
+     */
+    public static final String EXTRA_TEST_NAME =
+            "com.android.cts.verifier.p2p.testcase.EXTRA_TEST_NAME";
+
     protected static final int TIMEOUT = 25000;
+    protected static final int TIMEOUT_FOR_USER_ACTION = 60000;
     protected static final int SUCCESS = 0;
 
     protected Context mContext;
@@ -107,6 +114,7 @@
             mThread = null;
         }
     }
+
     /**
      * Return test name.
      * @return test name.
@@ -148,6 +156,14 @@
     }
 
     /**
+     * Notify a message to the application.
+     * @param id
+     */
+    protected void notifyTestMsg(int id) {
+        mListener.onTestMsgReceived(mContext.getString(id));
+    }
+
+    /**
      * Get reason for the failure.
      * @return
      */
@@ -166,6 +182,12 @@
         public void onTestStarted();
 
         /**
+         * This function is invoked when the test notify a message to application.
+         * @param msg
+         */
+        public void onTestMsgReceived(String msg);
+
+        /**
          * This function is invoked when the test is success.
          */
         public void onTestSuccess();
diff --git a/tests/expectations/knownfailures.txt b/tests/expectations/knownfailures.txt
index 6430cd1..9cfaf73 100644
--- a/tests/expectations/knownfailures.txt
+++ b/tests/expectations/knownfailures.txt
@@ -25,10 +25,6 @@
     bug: 6404341
   },
   {
-    name: "android.opengl.cts.AttachShaderTest#test_glAttachShaders_programobject_attach_fragshaderobject",
-    bug: 6292666
-  },
-  {
     name: "android.openglperf.cts.GlVboPerfTest#testVboWithVaryingIndexBufferNumbers",
     bug: 5898262
   },
diff --git a/tests/res/drawable/faces.jpg b/tests/res/drawable/faces.jpg
index 9892af0..0672022 100644
--- a/tests/res/drawable/faces.jpg
+++ b/tests/res/drawable/faces.jpg
Binary files differ
diff --git a/tests/tests/opengl/src/android/opengl/cts/AttachShaderTest.java b/tests/tests/opengl/src/android/opengl/cts/AttachShaderTest.java
index 034a77a..21efd6f 100644
--- a/tests/tests/opengl/src/android/opengl/cts/AttachShaderTest.java
+++ b/tests/tests/opengl/src/android/opengl/cts/AttachShaderTest.java
@@ -32,7 +32,9 @@
         intent.putExtra(OpenGLES20NativeActivity.EXTRA_VIEW_TYPE, viewType);
         intent.putExtra(OpenGLES20NativeActivity.EXTRA_VIEW_INDEX, viewIndex);
         setActivityIntent(intent);
-        return getActivity();
+        OpenGLES20ActivityOne activity = getActivity();
+        assertTrue(activity.waitForFrameDrawn());
+        return activity;
     }
 
     /**
@@ -61,10 +63,8 @@
 
     public void test_glAttachedShaders_invalidshader() throws Throwable {
         mActivity = getShaderActivity(Constants.SHADER, 2);
-        int shaderCount = mActivity.getNoOfAttachedShaders();
-        assertEquals(1, shaderCount);
         int error = mActivity.glGetError();
-        assertEquals(GLES20.GL_INVALID_VALUE, error);
+        assertTrue(GLES20.GL_NO_ERROR != error);
     }
 
     /**
@@ -78,7 +78,7 @@
     public void test_glAttachedShaders_attach_same_shader() throws Throwable {
         mActivity = getShaderActivity(Constants.SHADER, 3);
         int error = mActivity.glGetError();
-        assertEquals(GLES20.GL_INVALID_OPERATION, error);
+        assertTrue(GLES20.GL_NO_ERROR != error);
     }
 
     /**
@@ -113,19 +113,19 @@
     public void test_glAttachShaders_emptyvertexshader_emptyvertexshader() throws Throwable {
         mActivity = getShaderActivity(Constants.SHADER, 7);
         int error = mActivity.glGetError();
-        assertEquals(GLES20.GL_INVALID_OPERATION, error);
+        assertTrue(GLES20.GL_NO_ERROR != error);
     }
 
     public void test_glAttachShaders_programobject_attach_fragshaderobject() throws Throwable {
         mActivity = getShaderActivity(Constants.SHADER, 8);
         int error = mActivity.glGetError();
-        assertEquals(GLES20.GL_INVALID_VALUE, error);
+        assertEquals(GLES20.GL_NO_ERROR, error);
     }
 
     public void test_glAttachShaders_invalidshader_attach_valid_handle() throws Throwable{
         mActivity = getShaderActivity(Constants.SHADER, 9);
         int error = mActivity.glGetError();
-        assertEquals(GLES20.GL_INVALID_VALUE, error);
+        assertTrue(GLES20.GL_NO_ERROR != error);
     }
 
     public void test_glAttachShaders_successfulcompile_attach_frag() throws Throwable {
diff --git a/tests/tests/opengl/src/android/opengl/cts/NativeAttachShaderTest.java b/tests/tests/opengl/src/android/opengl/cts/NativeAttachShaderTest.java
index 1a51b6e..dbe3ea6 100755
--- a/tests/tests/opengl/src/android/opengl/cts/NativeAttachShaderTest.java
+++ b/tests/tests/opengl/src/android/opengl/cts/NativeAttachShaderTest.java
@@ -37,7 +37,9 @@
         intent.putExtra(OpenGLES20NativeActivity.EXTRA_VIEW_TYPE, viewType);
         intent.putExtra(OpenGLES20NativeActivity.EXTRA_VIEW_INDEX, viewIndex);
         setActivityIntent(intent);
-        return getActivity();
+        OpenGLES20NativeActivity activity = getActivity();
+        assertTrue(activity.waitForFrameDrawn());
+        return activity;
     }
 
     /**
@@ -66,7 +68,7 @@
     public void test_glAttachedShaders_invalidshader() throws Throwable {
         mActivity = getShaderActivity(Constants.SHADER, 2);
         int error = mActivity.mRenderer.mAttachShaderError;
-        assertEquals(GLES20.GL_INVALID_VALUE, error);
+        assertTrue(GLES20.GL_NO_ERROR != error);
     }
 
     /**
@@ -80,7 +82,7 @@
     public void test_glAttachedShaders_attach_same_shader() throws Throwable {
         mActivity = getShaderActivity(Constants.SHADER, 3);
         int error = mActivity.mRenderer.mAttachShaderError;
-        assertEquals(GLES20.GL_INVALID_OPERATION, error);
+        assertTrue(GLES20.GL_NO_ERROR != error);
     }
 
     /**
@@ -103,7 +105,7 @@
     public void test_glAttachShaders_emptyfragshader_emptyfragshader() throws Throwable {
         mActivity = getShaderActivity(Constants.SHADER, 5);
         int error = mActivity.mRenderer.mAttachShaderError;
-        assertEquals(GLES20.GL_INVALID_OPERATION, error);
+        assertTrue(GLES20.GL_NO_ERROR != error);
     }
 
     public void test_glAttachShaders_emptyfragshader_emptyvertexshader() throws Throwable {
diff --git a/tests/tests/opengl/src/android/opengl/cts/OpenGLES20ActivityOne.java b/tests/tests/opengl/src/android/opengl/cts/OpenGLES20ActivityOne.java
index 4a4e4ca..a8388c2 100644
--- a/tests/tests/opengl/src/android/opengl/cts/OpenGLES20ActivityOne.java
+++ b/tests/tests/opengl/src/android/opengl/cts/OpenGLES20ActivityOne.java
@@ -23,6 +23,10 @@
 import android.view.Window;
 import android.view.WindowManager;
 
+import java.lang.InterruptedException;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
 public class OpenGLES20ActivityOne extends Activity {
 
     public static final String EXTRA_VIEW_TYPE = "viewType";
@@ -31,6 +35,7 @@
     OpenGLES20View view;
     Renderer mRenderer;
     int mRendererType;
+    private CountDownLatch mLatch = new CountDownLatch(1);
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
@@ -41,18 +46,28 @@
         int viewType = getIntent().getIntExtra(EXTRA_VIEW_TYPE, -1);
         int viewIndex = getIntent().getIntExtra(EXTRA_VIEW_INDEX, -1);
 
-        view = new OpenGLES20View(this, viewType, viewIndex);
+        view = new OpenGLES20View(this, viewType, viewIndex, mLatch);
         setContentView(view);
     }
 
     public int getNoOfAttachedShaders() {
-       return ((RendererBase)mRenderer).mShaderCount[0];
+        return ((RendererBase)mRenderer).mShaderCount[0];
     }
 
     public int glGetError() {
         return ((RendererBase)mRenderer).mError;
     }
 
+    public boolean waitForFrameDrawn() {
+        boolean result = false;
+        try {
+            result = mLatch.await(10L, TimeUnit.SECONDS);
+        } catch (InterruptedException e) {
+            // just return false
+        }
+        return result;
+    }
+
     @Override
     protected void onPause() {
         super.onPause();
@@ -64,43 +79,43 @@
     @Override
     protected void onResume() {
         super.onResume();
-        if(view != null) {
+        if (view != null) {
             view.onResume();
         }
     }
 
     class OpenGLES20View extends GLSurfaceView {
 
-        public OpenGLES20View(Context context, int type, int index) {
+        public OpenGLES20View(Context context, int type, int index, CountDownLatch latch) {
             super(context);
             setEGLContextClientVersion(2);
-            if(type == Constants.SHADER) {
-                if(index == 1) {
-                    mRenderer = new RendererOneShaderTest();
-                }else if(index == 2) {
-                    mRenderer = new RendererTwoShaderTest();
-                }else if(index == 3) {
-                    mRenderer = new RendererThreeShaderTest();
-                }else if(index == 4) {
-                    mRenderer = new RendererFourShaderTest();
-                }else if(index == 5) {
-                    mRenderer = new RendererFiveShaderTest();
-                }else if(index == 6) {
-                    mRenderer = new RendererSixShaderTest();
-                }else if(index == 7) {
-                    mRenderer = new RendererSevenShaderTest();
-                }else if(index == 8) {
-                    mRenderer = new RendererEightShaderTest();
-                }else if(index == 9) {
-                    mRenderer = new RendererNineShaderTest();
-                }else if(index == 10) {
-                    mRenderer = new RendererTenShaderTest();
-                }else {
+            if (type == Constants.SHADER) {
+                if (index == 1) {
+                    mRenderer = new RendererOneShaderTest(latch);
+                } else if(index == 2) {
+                    mRenderer = new RendererTwoShaderTest(latch);
+                } else if(index == 3) {
+                    mRenderer = new RendererThreeShaderTest(latch);
+                } else if(index == 4) {
+                    mRenderer = new RendererFourShaderTest(latch);
+                } else if(index == 5) {
+                    mRenderer = new RendererFiveShaderTest(latch);
+                } else if(index == 6) {
+                    mRenderer = new RendererSixShaderTest(latch);
+                } else if(index == 7) {
+                    mRenderer = new RendererSevenShaderTest(latch);
+                } else if(index == 8) {
+                    mRenderer = new RendererEightShaderTest(latch);
+                } else if(index == 9) {
+                    mRenderer = new RendererNineShaderTest(latch);
+                } else if(index == 10) {
+                    mRenderer = new RendererTenShaderTest(latch);
+                } else {
                     throw new RuntimeException();
                 }
-            }else if(type == Constants.PROGRAM) {
-                if(index == 1) {
-                    mRenderer = new RendererOneProgramTest();
+            } else if (type == Constants.PROGRAM) {
+                if (index == 1) {
+                    mRenderer = new RendererOneProgramTest(latch);
                 }
             }
             setRenderer(mRenderer);
diff --git a/tests/tests/opengl/src/android/opengl/cts/OpenGLES20NativeActivity.java b/tests/tests/opengl/src/android/opengl/cts/OpenGLES20NativeActivity.java
index 4579ebf..36f986b 100755
--- a/tests/tests/opengl/src/android/opengl/cts/OpenGLES20NativeActivity.java
+++ b/tests/tests/opengl/src/android/opengl/cts/OpenGLES20NativeActivity.java
@@ -23,6 +23,10 @@
 import android.view.Window;
 import android.view.WindowManager;
 
+import java.lang.InterruptedException;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
 import javax.microedition.khronos.egl.EGLConfig;
 import javax.microedition.khronos.opengles.GL10;
 
@@ -37,6 +41,8 @@
     GL2Renderer mRenderer;
     int mRendererType;
 
+    private CountDownLatch mLatch = new CountDownLatch(1);
+
     /**
      * Called when the activity is first created.
      */
@@ -50,10 +56,20 @@
         int viewType = getIntent().getIntExtra(EXTRA_VIEW_TYPE, -1);
         int viewIndex = getIntent().getIntExtra(EXTRA_VIEW_INDEX, -1);
 
-        view = new OpenGLES20View(this, viewType, viewIndex);
+        view = new OpenGLES20View(this, viewType, viewIndex, mLatch);
         setContentView(view);
     }
 
+    public boolean waitForFrameDrawn() {
+        boolean result = false;
+        try {
+            result = mLatch.await(10L, TimeUnit.SECONDS);
+        } catch (InterruptedException e) {
+            // just return false
+        }
+        return result;
+    }
+
     @Override
     protected void onPause() {
         super.onPause();
@@ -69,10 +85,10 @@
     }
 
     class OpenGLES20View extends GLSurfaceView {
-        public OpenGLES20View(Context context, int category, int testCase) {
+        public OpenGLES20View(Context context, int category, int testCase, CountDownLatch latch) {
             super(context);
             setEGLContextClientVersion(2);
-            mRenderer = new GL2Renderer(category, testCase);
+            mRenderer = new GL2Renderer(category, testCase, latch);
             setRenderer(mRenderer);
         }
 
@@ -93,9 +109,12 @@
     int mAttachShaderError = -1;
     int mShaderCount = -1;
 
-    public GL2Renderer(int category, int testcase) {
+    private CountDownLatch mLatch;
+
+    public GL2Renderer(int category, int testcase, CountDownLatch latch) {
         this.mCategory = category;
         this.mTestCase = testcase;
+        mLatch = latch;
     }
 
     public void onDrawFrame(GL10 gl) {
@@ -113,5 +132,6 @@
         Log.i(TAG,"error:" + mAttachShaderError);
         this.mShaderCount = GL2JniLibOne.getAttachedShaderCount();
         Log.i(TAG,"ShaderCount:" + mShaderCount);
+        mLatch.countDown();
     }
 }
diff --git a/tests/tests/opengl/src/android/opengl/cts/RendererBase.java b/tests/tests/opengl/src/android/opengl/cts/RendererBase.java
index b64f47a..d015fcd 100644
--- a/tests/tests/opengl/src/android/opengl/cts/RendererBase.java
+++ b/tests/tests/opengl/src/android/opengl/cts/RendererBase.java
@@ -23,15 +23,25 @@
 import android.opengl.GLSurfaceView;
 import android.opengl.GLSurfaceView.Renderer;
 
+import java.util.concurrent.CountDownLatch;
+
 public abstract class RendererBase implements GLSurfaceView.Renderer {
 
     FloatBuffer floatBuffer;
     int mProgram;
     int maPositionHandle;
 
-    int[] mShaderCount;
+    int[] mShaderCount = null;
     int mError;
 
+    // child may need to manipulate them directly
+    protected CountDownLatch mLatch;
+    protected boolean mDrawn = false;
+
+    public RendererBase(CountDownLatch latch) {
+        mLatch = latch;
+    }
+
     @Override
     public void onSurfaceChanged(GL10 gl, int width, int height) {
 
@@ -44,4 +54,17 @@
         return shader;
     }
 
+    @Override
+    public void onDrawFrame(GL10 gl) {
+        if (mDrawn) {
+            return;
+        }
+        mDrawn = true;
+        doOnDrawFrame(gl);
+        mLatch.countDown();
+    }
+
+    /// dummy method to be overridden by child
+    public void doOnDrawFrame(GL10 gl) {
+    }
 }
diff --git a/tests/tests/opengl/src/android/opengl/cts/RendererEightShaderTest.java b/tests/tests/opengl/src/android/opengl/cts/RendererEightShaderTest.java
index eba7601..c2d1a19 100644
--- a/tests/tests/opengl/src/android/opengl/cts/RendererEightShaderTest.java
+++ b/tests/tests/opengl/src/android/opengl/cts/RendererEightShaderTest.java
@@ -17,13 +17,13 @@
 
 import javax.microedition.khronos.egl.EGLConfig;
 import javax.microedition.khronos.opengles.GL10;
-
+import java.util.concurrent.CountDownLatch;
 import android.opengl.GLES20;
 
 public class RendererEightShaderTest extends RendererBase {
-    @Override
-    public void onDrawFrame(GL10 gl) {
 
+    public RendererEightShaderTest(CountDownLatch latch) {
+        super(latch);
     }
 
     @Override
@@ -36,5 +36,6 @@
         GLES20.glAttachShader(mProgram, shaderOne);
 
         mError = GLES20.glGetError();
+        mLatch.countDown();
     }
 }
diff --git a/tests/tests/opengl/src/android/opengl/cts/RendererFiveShaderTest.java b/tests/tests/opengl/src/android/opengl/cts/RendererFiveShaderTest.java
index 0dce725..f40c896 100644
--- a/tests/tests/opengl/src/android/opengl/cts/RendererFiveShaderTest.java
+++ b/tests/tests/opengl/src/android/opengl/cts/RendererFiveShaderTest.java
@@ -17,14 +17,15 @@
 
 import javax.microedition.khronos.egl.EGLConfig;
 import javax.microedition.khronos.opengles.GL10;
-
+import java.util.concurrent.CountDownLatch;
 import android.opengl.GLES20;
 import android.util.Log;
 
 
 public class RendererFiveShaderTest extends RendererBase {
-    @Override
-    public void onDrawFrame(GL10 gl) {
+
+    public RendererFiveShaderTest(CountDownLatch latch) {
+        super(latch);
     }
 
     @Override
@@ -40,5 +41,6 @@
         int[] shaders = new int[10];
         GLES20.glGetAttachedShaders(mProgram, 10, mShaderCount, 0, shaders, 0);
         mError = GLES20.glGetError();
+        mLatch.countDown();
     }
 }
diff --git a/tests/tests/opengl/src/android/opengl/cts/RendererFourShaderTest.java b/tests/tests/opengl/src/android/opengl/cts/RendererFourShaderTest.java
index 2382c6d..dd98b68 100644
--- a/tests/tests/opengl/src/android/opengl/cts/RendererFourShaderTest.java
+++ b/tests/tests/opengl/src/android/opengl/cts/RendererFourShaderTest.java
@@ -17,14 +17,15 @@
 
 import javax.microedition.khronos.egl.EGLConfig;
 import javax.microedition.khronos.opengles.GL10;
-
+import java.util.concurrent.CountDownLatch;
 import android.opengl.GLES20;
 import android.util.Log;
 
 
 public class RendererFourShaderTest extends RendererBase {
-    @Override
-    public void onDrawFrame(GL10 gl) {
+
+    public RendererFourShaderTest(CountDownLatch latch) {
+        super(latch);
     }
 
     @Override
@@ -41,5 +42,6 @@
         }
         mError = GLES20.glGetError();
         GLES20.glLinkProgram(mProgram);
+        mLatch.countDown();
     }
 }
diff --git a/tests/tests/opengl/src/android/opengl/cts/RendererNineShaderTest.java b/tests/tests/opengl/src/android/opengl/cts/RendererNineShaderTest.java
index 64cc9d0..54b6634 100644
--- a/tests/tests/opengl/src/android/opengl/cts/RendererNineShaderTest.java
+++ b/tests/tests/opengl/src/android/opengl/cts/RendererNineShaderTest.java
@@ -17,13 +17,13 @@
 
 import javax.microedition.khronos.egl.EGLConfig;
 import javax.microedition.khronos.opengles.GL10;
-
+import java.util.concurrent.CountDownLatch;
 import android.opengl.GLES20;
 
 public class RendererNineShaderTest extends RendererBase {
-    @Override
-    public void onDrawFrame(GL10 gl) {
 
+    public RendererNineShaderTest(CountDownLatch latch) {
+        super(latch);
     }
 
     @Override
@@ -37,5 +37,6 @@
         GLES20.glAttachShader(mProgram, shaderOne);
 
         mError = GLES20.glGetError();
+        mLatch.countDown();
     }
 }
diff --git a/tests/tests/opengl/src/android/opengl/cts/RendererOneProgramTest.java b/tests/tests/opengl/src/android/opengl/cts/RendererOneProgramTest.java
index 3aceeaa..dff3adb 100644
--- a/tests/tests/opengl/src/android/opengl/cts/RendererOneProgramTest.java
+++ b/tests/tests/opengl/src/android/opengl/cts/RendererOneProgramTest.java
@@ -17,14 +17,14 @@
 
 import javax.microedition.khronos.egl.EGLConfig;
 import javax.microedition.khronos.opengles.GL10;
-
+import java.util.concurrent.CountDownLatch;
 import android.opengl.GLES20;
 import android.util.Log;
 
 public class RendererOneProgramTest extends RendererBase {
-    @Override
-    public void onDrawFrame(GL10 gl) {
 
+    public RendererOneProgramTest(CountDownLatch latch) {
+        super(latch);
     }
 
     @Override
@@ -35,5 +35,6 @@
         int mProgramTwo = GLES20.glCreateProgram();
         GLES20.glAttachShader(mProgram, mProgramTwo);
         mError = GLES20.glGetError();
+        mLatch.countDown();
     }
 }
diff --git a/tests/tests/opengl/src/android/opengl/cts/RendererOneShaderTest.java b/tests/tests/opengl/src/android/opengl/cts/RendererOneShaderTest.java
index 83f7f43..1c88854 100644
--- a/tests/tests/opengl/src/android/opengl/cts/RendererOneShaderTest.java
+++ b/tests/tests/opengl/src/android/opengl/cts/RendererOneShaderTest.java
@@ -23,6 +23,7 @@
 
 import android.opengl.GLES20;
 
+import java.util.concurrent.CountDownLatch;
 
 public class RendererOneShaderTest extends RendererBase {
 
@@ -37,8 +38,12 @@
             + " gl_FragColor = vec4 (0.63671875, 0.76953125, 0.22265625, 1.0); \n"
             + "}  \n";
 
+    public RendererOneShaderTest(CountDownLatch latch) {
+        super(latch);
+    }
+
     @Override
-    public void onDrawFrame(GL10 gl) {
+    public void doOnDrawFrame(GL10 gl) {
         GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
         GLES20.glUseProgram(mProgram);
 
diff --git a/tests/tests/opengl/src/android/opengl/cts/RendererSevenShaderTest.java b/tests/tests/opengl/src/android/opengl/cts/RendererSevenShaderTest.java
index b225572..4338d59 100644
--- a/tests/tests/opengl/src/android/opengl/cts/RendererSevenShaderTest.java
+++ b/tests/tests/opengl/src/android/opengl/cts/RendererSevenShaderTest.java
@@ -17,12 +17,13 @@
 
 import javax.microedition.khronos.egl.EGLConfig;
 import javax.microedition.khronos.opengles.GL10;
-
+import java.util.concurrent.CountDownLatch;
 import android.opengl.GLES20;
 
 public class RendererSevenShaderTest extends RendererBase {
-    @Override
-    public void onDrawFrame(GL10 gl) {
+
+    public RendererSevenShaderTest(CountDownLatch latch) {
+        super(latch);
     }
 
     @Override
@@ -35,5 +36,6 @@
         GLES20.glAttachShader(mProgram, shaderOne);
         GLES20.glAttachShader(mProgram, shaderTwo);
         mError = GLES20.glGetError();
+        mLatch.countDown();
     }
 }
diff --git a/tests/tests/opengl/src/android/opengl/cts/RendererSixShaderTest.java b/tests/tests/opengl/src/android/opengl/cts/RendererSixShaderTest.java
index 989bd7f..e998448 100644
--- a/tests/tests/opengl/src/android/opengl/cts/RendererSixShaderTest.java
+++ b/tests/tests/opengl/src/android/opengl/cts/RendererSixShaderTest.java
@@ -17,12 +17,13 @@
 
 import javax.microedition.khronos.egl.EGLConfig;
 import javax.microedition.khronos.opengles.GL10;
-
+import java.util.concurrent.CountDownLatch;
 import android.opengl.GLES20;
 
 public class RendererSixShaderTest extends RendererBase {
-    @Override
-    public void onDrawFrame(GL10 gl) {
+
+    public RendererSixShaderTest(CountDownLatch latch) {
+        super(latch);
     }
 
     @Override
@@ -38,5 +39,6 @@
         int[] shaders = new int[10];
         GLES20.glGetAttachedShaders(mProgram, 10, mShaderCount, 0, shaders, 0);
         mError = GLES20.glGetError();
+        mLatch.countDown();
     }
 }
diff --git a/tests/tests/opengl/src/android/opengl/cts/RendererTenShaderTest.java b/tests/tests/opengl/src/android/opengl/cts/RendererTenShaderTest.java
index 0d8e86e..5879ddc 100644
--- a/tests/tests/opengl/src/android/opengl/cts/RendererTenShaderTest.java
+++ b/tests/tests/opengl/src/android/opengl/cts/RendererTenShaderTest.java
@@ -17,15 +17,14 @@
 
 import javax.microedition.khronos.egl.EGLConfig;
 import javax.microedition.khronos.opengles.GL10;
-
+import java.util.concurrent.CountDownLatch;
 import android.opengl.GLES20;
 
 public class RendererTenShaderTest extends RendererBase {
     private String fragmentShaderCode = Shaders.successfulcompile_frag;
 
-    @Override
-    public void onDrawFrame(GL10 gl) {
-
+    public RendererTenShaderTest(CountDownLatch latch) {
+        super(latch);
     }
 
     @Override
@@ -38,5 +37,6 @@
         GLES20.glLinkProgram(mProgram);
 
         mError = GLES20.glGetError();
+        mLatch.countDown();
     }
 }
diff --git a/tests/tests/opengl/src/android/opengl/cts/RendererThreeShaderTest.java b/tests/tests/opengl/src/android/opengl/cts/RendererThreeShaderTest.java
index 430c1a0..8064904 100644
--- a/tests/tests/opengl/src/android/opengl/cts/RendererThreeShaderTest.java
+++ b/tests/tests/opengl/src/android/opengl/cts/RendererThreeShaderTest.java
@@ -17,7 +17,7 @@
 
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
-
+import java.util.concurrent.CountDownLatch;
 import javax.microedition.khronos.egl.EGLConfig;
 import javax.microedition.khronos.opengles.GL10;
 
@@ -36,8 +36,13 @@
             + "void main(){              \n"
             + " gl_FragColor = vec4 (0.63671875, 0.76953125, 0.22265625, 1.0); \n"
             + "}  \n";
+
+    public RendererThreeShaderTest(CountDownLatch latch) {
+        super(latch);
+    }
+
     @Override
-    public void onDrawFrame(GL10 gl) {
+    public void doOnDrawFrame(GL10 gl) {
         GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
         GLES20.glUseProgram(mProgram);
 
diff --git a/tests/tests/opengl/src/android/opengl/cts/RendererTwoShaderTest.java b/tests/tests/opengl/src/android/opengl/cts/RendererTwoShaderTest.java
index 53d90af..99b3e75 100644
--- a/tests/tests/opengl/src/android/opengl/cts/RendererTwoShaderTest.java
+++ b/tests/tests/opengl/src/android/opengl/cts/RendererTwoShaderTest.java
@@ -15,33 +15,26 @@
  */
 package android.opengl.cts;
 
+import android.opengl.GLES20;
+
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
+import java.util.concurrent.CountDownLatch;
 
 import javax.microedition.khronos.egl.EGLConfig;
 import javax.microedition.khronos.opengles.GL10;
 
-import android.opengl.GLES20;
-
 public class RendererTwoShaderTest extends RendererBase {
     private final String fragmentShaderCode = "precision mediump float;  \n"
             + "void main(){              \n"
             + " gl_FragColor = vec4 (0.63671875, 0.76953125, 0.22265625, 1.0); \n"
             + "}  \n";
-    @Override
-    public void onDrawFrame(GL10 gl) {
-        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
-        GLES20.glUseProgram(mProgram);
 
-        GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT,
-                false, 12, floatBuffer);
-        GLES20.glEnableVertexAttribArray(maPositionHandle);
-        GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3);
-        mShaderCount = new int[1];
-        int[] shaders = new int[10];
-        GLES20.glGetAttachedShaders(mProgram, 10, mShaderCount, 0, shaders, 0);
+    public RendererTwoShaderTest(CountDownLatch latch) {
+        super(latch);
     }
 
+
     @Override
     public void onSurfaceCreated(GL10 gl, EGLConfig config) {
         GLES20.glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
@@ -50,18 +43,10 @@
         int vertexShaderOne = 9999;
         int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
         mProgram =  GLES20.glCreateProgram();
+        // some driver crashes instead of returning error.
         GLES20.glAttachShader(mProgram, vertexShaderOne);
         mError = GLES20.glGetError();
-        GLES20.glAttachShader(mProgram, fragmentShader);
-        GLES20.glLinkProgram(mProgram);
-        int[] linkStatus = new int[1];
-        GLES20.glGetProgramiv(mProgram, GLES20.GL_LINK_STATUS, linkStatus, 0);
-        mShaderCount = new int[1];
-        int[] shaders = new int[10];
-        GLES20.glGetAttachedShaders(mProgram, 10, mShaderCount, 0, shaders, 0);
-        if (linkStatus[0] != GLES20.GL_TRUE) {
-           //do nothing
-        }
+        mLatch.countDown();
     }
 
     public void initShapes(){