Merge "p2p: add cts coverage for new WifiP2pManager API"
diff --git a/tests/cts/net/src/android/net/wifi/cts/ConcurrencyTest.java b/tests/cts/net/src/android/net/wifi/cts/ConcurrencyTest.java
index 5e91366..c80e372 100644
--- a/tests/cts/net/src/android/net/wifi/cts/ConcurrencyTest.java
+++ b/tests/cts/net/src/android/net/wifi/cts/ConcurrencyTest.java
@@ -16,36 +16,66 @@
 
 package android.net.wifi.cts;
 
+import static org.junit.Assert.assertNotEquals;
+
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.PackageManager;
 import android.net.ConnectivityManager;
 import android.net.ConnectivityManager.NetworkCallback;
 import android.net.Network;
 import android.net.NetworkCapabilities;
+import android.net.NetworkInfo;
 import android.net.NetworkRequest;
 import android.net.wifi.WifiManager;
 import android.net.wifi.p2p.WifiP2pManager;
-import static android.net.wifi.p2p.WifiP2pManager.WIFI_P2P_STATE_DISABLED;
-import static android.net.wifi.p2p.WifiP2pManager.WIFI_P2P_STATE_ENABLED;
+import android.provider.Settings;
 import android.test.AndroidTestCase;
+import android.util.Log;
 
 import com.android.compatibility.common.util.SystemUtil;
 
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.LinkedList;
+import java.util.List;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
 
 public class ConcurrencyTest extends AndroidTestCase {
     private class MySync {
-        int expectedWifiState;
-        int expectedP2pState;
+        static final int WIFI_STATE = 0;
+        static final int P2P_STATE = 1;
+        static final int DISCOVERY_STATE = 2;
+        static final int NETWORK_INFO = 3;
+
+        public BitSet pendingSync = new BitSet();
+
+        public int expectedWifiState;
+        public int expectedP2pState;
+        public int expectedDiscoveryState;
+        public NetworkInfo expectedNetworkInfo;
+    }
+
+    private class MyResponse {
+        public boolean valid = false;
+
+        public boolean success;
+        public int p2pState;
+        public int discoveryState;
+        public NetworkInfo networkInfo;
     }
 
     private WifiManager mWifiManager;
+    private WifiP2pManager mWifiP2pManager;
+    private WifiP2pManager.Channel mWifiP2pChannel;
     private MySync mMySync = new MySync();
+    private MyResponse mMyResponse = new MyResponse();
 
-    private static final String TAG = "WifiInfoTest";
+    private static final String TAG = "ConcurrencyTest";
     private static final int TIMEOUT_MSEC = 6000;
     private static final int WAIT_MSEC = 60;
     private static final int DURATION = 10000;
@@ -56,16 +86,33 @@
             final String action = intent.getAction();
             if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
                 synchronized (mMySync) {
+                    mMySync.pendingSync.set(MySync.WIFI_STATE);
                     mMySync.expectedWifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
                             WifiManager.WIFI_STATE_DISABLED);
                     mMySync.notify();
                 }
             } else if(action.equals(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION)) {
                 synchronized (mMySync) {
+                    mMySync.pendingSync.set(MySync.P2P_STATE);
                     mMySync.expectedP2pState = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE,
                             WifiP2pManager.WIFI_P2P_STATE_DISABLED);
                     mMySync.notify();
                 }
+            } else if (action.equals(WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION)) {
+                synchronized (mMySync) {
+                    mMySync.pendingSync.set(MySync.DISCOVERY_STATE);
+                    mMySync.expectedDiscoveryState = intent.getIntExtra(
+                            WifiP2pManager.EXTRA_DISCOVERY_STATE,
+                            WifiP2pManager.WIFI_P2P_DISCOVERY_STOPPED);
+                    mMySync.notify();
+                }
+            } else if (action.equals(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION)) {
+                synchronized (mMySync) {
+                    mMySync.pendingSync.set(MySync.NETWORK_INFO);
+                    mMySync.expectedNetworkInfo = (NetworkInfo) intent.getExtra(
+                            WifiP2pManager.EXTRA_NETWORK_INFO, null);
+                    mMySync.notify();
+                }
             }
         }
     };
@@ -81,6 +128,8 @@
         mIntentFilter = new IntentFilter();
         mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
         mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
+        mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION);
+        mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
 
         mContext.registerReceiver(mReceiver, mIntentFilter);
         mWifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE);
@@ -92,6 +141,8 @@
         assertTrue(!mWifiManager.isWifiEnabled());
         mMySync.expectedWifiState = WifiManager.WIFI_STATE_DISABLED;
         mMySync.expectedP2pState = WifiP2pManager.WIFI_P2P_STATE_DISABLED;
+        mMySync.expectedDiscoveryState = WifiP2pManager.WIFI_P2P_DISCOVERY_STOPPED;
+        mMySync.expectedNetworkInfo = null;
     }
 
     @Override
@@ -108,16 +159,66 @@
         super.tearDown();
     }
 
-    private void waitForBroadcasts() {
+    private boolean waitForBroadcasts(List<Integer> waitSyncList) {
         synchronized (mMySync) {
             long timeout = System.currentTimeMillis() + TIMEOUT_MSEC;
-            while (System.currentTimeMillis() < timeout
-                    && (mMySync.expectedWifiState != WifiManager.WIFI_STATE_ENABLED ||
-                    mMySync.expectedP2pState != WifiP2pManager.WIFI_P2P_STATE_ENABLED)) {
+            while (System.currentTimeMillis() < timeout) {
+                List<Integer> handledSyncList = waitSyncList.stream()
+                        .filter(w -> mMySync.pendingSync.get(w))
+                        .collect(Collectors.toList());
+                handledSyncList.forEach(w -> mMySync.pendingSync.clear(w));
+                waitSyncList.removeAll(handledSyncList);
+                if (waitSyncList.isEmpty()) {
+                    break;
+                }
                 try {
                     mMySync.wait(WAIT_MSEC);
                 } catch (InterruptedException e) { }
             }
+            if (!waitSyncList.isEmpty()) {
+                Log.i(TAG, "Missing broadcast: " + waitSyncList);
+            }
+            return waitSyncList.isEmpty();
+        }
+    }
+
+    private boolean waitForBroadcasts(int waitSingleSync) {
+        return waitForBroadcasts(
+                new LinkedList<Integer>(Arrays.asList(waitSingleSync)));
+    }
+
+    private boolean waitForServiceResponse(MyResponse waitResponse) {
+        synchronized (waitResponse) {
+            long timeout = System.currentTimeMillis() + TIMEOUT_MSEC;
+            while (System.currentTimeMillis() < timeout) {
+                try {
+                    waitResponse.wait(WAIT_MSEC);
+                } catch (InterruptedException e) { }
+
+                if (waitResponse.valid) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+
+    // Return true if location is enabled.
+    private boolean isLocationEnabled() {
+        return Settings.Secure.getInt(getContext().getContentResolver(),
+                Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF)
+                != Settings.Secure.LOCATION_MODE_OFF;
+    }
+
+    // Returns true if the device has location feature.
+    private boolean hasLocationFeature() {
+        return getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_LOCATION);
+    }
+
+    private void resetResponse(MyResponse responseObj) {
+        synchronized (responseObj) {
+            responseObj.valid = false;
+            responseObj.networkInfo = null;
         }
     }
 
@@ -148,25 +249,212 @@
         cm.unregisterNetworkCallback(networkCallback);
     }
 
-    public void testConcurrency() {
+    private boolean setupWifiP2p() {
         // Cannot support p2p alone
         if (!WifiFeature.isWifiSupported(getContext())) {
             assertTrue(!WifiFeature.isP2pSupported(getContext()));
-            return;
+            return false;
         }
 
         if (!WifiFeature.isP2pSupported(getContext())) {
             // skip the test if p2p is not supported
+            return false;
+        }
+
+        if (!hasLocationFeature()) {
+            Log.d(TAG, "Skipping test as location is not supported");
+            return false;
+        }
+        if (!isLocationEnabled()) {
+            fail("Please enable location for this test - since P-release WiFi Direct"
+                    + " needs Location enabled.");
+        }
+
+        long timeout = System.currentTimeMillis() + TIMEOUT_MSEC;
+        while (!mWifiManager.isWifiEnabled() && System.currentTimeMillis() < timeout) {
+            try {
+                enableWifi();
+            } catch (InterruptedException e) { }
+        }
+
+        assertTrue(mWifiManager.isWifiEnabled());
+
+        assertTrue(waitForBroadcasts(
+                new LinkedList<Integer>(
+                Arrays.asList(MySync.WIFI_STATE, MySync.P2P_STATE))));
+
+        assertEquals(WifiManager.WIFI_STATE_ENABLED, mMySync.expectedWifiState);
+        assertEquals(WifiP2pManager.WIFI_P2P_STATE_ENABLED, mMySync.expectedP2pState);
+
+        mWifiP2pManager =
+                (WifiP2pManager) getContext().getSystemService(Context.WIFI_P2P_SERVICE);
+        mWifiP2pChannel = mWifiP2pManager.initialize(
+                getContext(), getContext().getMainLooper(), null);
+
+        assertNotNull(mWifiP2pManager);
+        assertNotNull(mWifiP2pChannel);
+
+        assertTrue(waitForBroadcasts(MySync.NETWORK_INFO));
+        // wait for changing to EnabledState
+        assertNotNull(mMySync.expectedNetworkInfo);
+        assertTrue(mMySync.expectedNetworkInfo.isAvailable());
+
+        return true;
+    }
+
+    public void testConcurrency() {
+        if (!setupWifiP2p()) {
             return;
         }
 
-        // Enable wifi
-        SystemUtil.runShellCommand("svc wifi enable");
+        resetResponse(mMyResponse);
+        mWifiP2pManager.requestP2pState(mWifiP2pChannel, new WifiP2pManager.P2pStateListener() {
+            @Override
+            public void onP2pStateAvailable(int state) {
+                synchronized (mMyResponse) {
+                    mMyResponse.valid = true;
+                    mMyResponse.p2pState = state;
+                    mMyResponse.notify();
+                }
+            }
+        });
+        assertTrue(waitForServiceResponse(mMyResponse));
+        assertEquals(WifiP2pManager.WIFI_P2P_STATE_ENABLED, mMyResponse.p2pState);
+    }
 
-        waitForBroadcasts();
+    public void testRequestDiscoveryState() {
+        if (!setupWifiP2p()) {
+            return;
+        }
 
-        assertTrue(mMySync.expectedWifiState == WifiManager.WIFI_STATE_ENABLED);
-        assertTrue(mMySync.expectedP2pState == WifiP2pManager.WIFI_P2P_STATE_ENABLED);
+        resetResponse(mMyResponse);
+        mWifiP2pManager.requestDiscoveryState(
+                mWifiP2pChannel, new WifiP2pManager.DiscoveryStateListener() {
+                    @Override
+                    public void onDiscoveryStateAvailable(int state) {
+                        synchronized (mMyResponse) {
+                            mMyResponse.valid = true;
+                            mMyResponse.discoveryState = state;
+                            mMyResponse.notify();
+                        }
+                    }
+                });
+        assertTrue(waitForServiceResponse(mMyResponse));
+        assertEquals(WifiP2pManager.WIFI_P2P_DISCOVERY_STOPPED, mMyResponse.discoveryState);
+
+        resetResponse(mMyResponse);
+        mWifiP2pManager.discoverPeers(mWifiP2pChannel, new WifiP2pManager.ActionListener() {
+            @Override
+            public void onSuccess() {
+                synchronized (mMyResponse) {
+                    mMyResponse.valid = true;
+                    mMyResponse.success = true;
+                    mMyResponse.notify();
+                }
+            }
+
+            @Override
+            public void onFailure(int reason) {
+                synchronized (mMyResponse) {
+                    Log.d(TAG, "discoveryPeers failure reason: " + reason);
+                    mMyResponse.valid = true;
+                    mMyResponse.success = false;
+                    mMyResponse.notify();
+                }
+            }
+        });
+        assertTrue(waitForServiceResponse(mMyResponse));
+        assertTrue(mMyResponse.success);
+        assertTrue(waitForBroadcasts(MySync.DISCOVERY_STATE));
+
+        resetResponse(mMyResponse);
+        mWifiP2pManager.requestDiscoveryState(mWifiP2pChannel,
+                new WifiP2pManager.DiscoveryStateListener() {
+                    @Override
+                    public void onDiscoveryStateAvailable(int state) {
+                        synchronized (mMyResponse) {
+                            mMyResponse.valid = true;
+                            mMyResponse.discoveryState = state;
+                            mMyResponse.notify();
+                        }
+                    }
+                });
+        assertTrue(waitForServiceResponse(mMyResponse));
+        assertEquals(WifiP2pManager.WIFI_P2P_DISCOVERY_STARTED, mMyResponse.discoveryState);
+
+        mWifiP2pManager.stopPeerDiscovery(mWifiP2pChannel, null);
+    }
+
+    public void testRequestNetworkInfo() {
+        if (!setupWifiP2p()) {
+            return;
+        }
+
+        resetResponse(mMyResponse);
+        mWifiP2pManager.requestNetworkInfo(mWifiP2pChannel,
+                new WifiP2pManager.NetworkInfoListener() {
+                    @Override
+                    public void onNetworkInfoAvailable(NetworkInfo info) {
+                        synchronized (mMyResponse) {
+                            mMyResponse.valid = true;
+                            mMyResponse.networkInfo = info;
+                            mMyResponse.notify();
+                        }
+                    }
+                });
+        assertTrue(waitForServiceResponse(mMyResponse));
+        assertNotNull(mMyResponse.networkInfo);
+        // The state might be IDLE, DISCONNECTED, FAILED before a connection establishment.
+        // Just ensure the state is NOT CONNECTED.
+        assertNotEquals(NetworkInfo.DetailedState.CONNECTED,
+                mMySync.expectedNetworkInfo.getDetailedState());
+
+        resetResponse(mMyResponse);
+        mWifiP2pManager.createGroup(mWifiP2pChannel, new WifiP2pManager.ActionListener() {
+            @Override
+            public void onSuccess() {
+                synchronized (mMyResponse) {
+                    mMyResponse.valid = true;
+                    mMyResponse.success = true;
+                    mMyResponse.notify();
+                }
+            }
+
+            @Override
+            public void onFailure(int reason) {
+                synchronized (mMyResponse) {
+                    Log.d(TAG, "createGroup failure reason: " + reason);
+                    mMyResponse.valid = true;
+                    mMyResponse.success = false;
+                    mMyResponse.notify();
+                }
+            }
+        });
+        assertTrue(waitForServiceResponse(mMyResponse));
+        assertTrue(mMyResponse.success);
+        assertTrue(waitForBroadcasts(MySync.NETWORK_INFO));
+        assertNotNull(mMySync.expectedNetworkInfo);
+        assertEquals(NetworkInfo.DetailedState.CONNECTED,
+                mMySync.expectedNetworkInfo.getDetailedState());
+
+        resetResponse(mMyResponse);
+        mWifiP2pManager.requestNetworkInfo(mWifiP2pChannel,
+                new WifiP2pManager.NetworkInfoListener() {
+                    @Override
+                    public void onNetworkInfoAvailable(NetworkInfo info) {
+                        synchronized (mMyResponse) {
+                            mMyResponse.valid = true;
+                            mMyResponse.networkInfo = info;
+                            mMyResponse.notify();
+                        }
+                    }
+                });
+        assertTrue(waitForServiceResponse(mMyResponse));
+        assertNotNull(mMyResponse.networkInfo);
+        assertEquals(NetworkInfo.DetailedState.CONNECTED,
+                mMyResponse.networkInfo.getDetailedState());
+
+        mWifiP2pManager.removeGroup(mWifiP2pChannel, null);
     }
 
 }