am f61bfdb3: Merge "More wifi direct CTS tests" into jb-dev

* commit 'f61bfdb31eea34f90db88907e32e2b49fe18264c':
  More wifi direct CTS tests
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..249af3b
--- /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();