From 06b47c520dc9814da6a0fcaaf548b65ffea7cab8 Mon Sep 17 00:00:00 2001 From: bdodson Date: Thu, 29 Jun 2017 08:57:01 -0700 Subject: [PATCH] Listen for Wifi-Direct networks and include them in the network list BUG=webrtc:7708 TBR=magjed@webrtc.org Review-Url: https://codereview.webrtc.org/2951803003 Cr-Commit-Position: refs/heads/master@{#18839} --- .../org/webrtc/NetworkMonitorAutoDetect.java | 106 +++++++++++++++++- .../src/jni/androidnetworkmonitor_jni.cc | 4 + 2 files changed, 108 insertions(+), 2 deletions(-) diff --git a/webrtc/sdk/android/api/org/webrtc/NetworkMonitorAutoDetect.java b/webrtc/sdk/android/api/org/webrtc/NetworkMonitorAutoDetect.java index 7805bc594f..77b77be95c 100644 --- a/webrtc/sdk/android/api/org/webrtc/NetworkMonitorAutoDetect.java +++ b/webrtc/sdk/android/api/org/webrtc/NetworkMonitorAutoDetect.java @@ -10,7 +10,6 @@ package org.webrtc; -import android.Manifest.permission; import android.annotation.SuppressLint; import android.content.BroadcastReceiver; import android.content.Context; @@ -26,9 +25,15 @@ import android.net.NetworkInfo; import android.net.NetworkRequest; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; +import android.net.wifi.p2p.WifiP2pGroup; +import android.net.wifi.p2p.WifiP2pManager; import android.os.Build; import android.telephony.TelephonyManager; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; import java.util.ArrayList; +import java.util.Collections; import java.util.List; /** @@ -402,6 +407,90 @@ public class NetworkMonitorAutoDetect extends BroadcastReceiver { } } + /** Maintains the information about wifi direct (aka WifiP2p) networks. */ + static class WifiDirectManagerDelegate extends BroadcastReceiver { + // Network "handle" for the Wifi P2p network. We have to bind to the default network id + // (NETWORK_UNSPECIFIED) for these addresses. + private static final int WIFI_P2P_NETWORK_HANDLE = 0; + private final Context context; + private final Observer observer; + // Network information about a WifiP2p (aka WiFi-Direct) network, or null if no such network is + // connected. + private NetworkInformation wifiP2pNetworkInfo = null; + + WifiDirectManagerDelegate(Observer observer, Context context) { + this.context = context; + this.observer = observer; + IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION); + intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION); + context.registerReceiver(this, intentFilter); + } + + // BroadcastReceiver + @Override + @SuppressLint("InlinedApi") + public void onReceive(Context context, Intent intent) { + if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(intent.getAction())) { + WifiP2pGroup wifiP2pGroup = intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_GROUP); + onWifiP2pGroupChange(wifiP2pGroup); + } else if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(intent.getAction())) { + int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, 0 /* default to unknown */); + onWifiP2pStateChange(state); + } + } + + /** Releases the broadcast receiver. */ + public void release() { + context.unregisterReceiver(this); + } + + public List getActiveNetworkList() { + if (wifiP2pNetworkInfo != null) { + return Collections.singletonList(wifiP2pNetworkInfo); + } + + return Collections.emptyList(); + } + + /** Handle a change notification about the wifi p2p group. */ + private void onWifiP2pGroupChange(WifiP2pGroup wifiP2pGroup) { + if (wifiP2pGroup == null || wifiP2pGroup.getInterface() == null) { + return; + } + + NetworkInterface wifiP2pInterface; + try { + wifiP2pInterface = NetworkInterface.getByName(wifiP2pGroup.getInterface()); + } catch (SocketException e) { + Logging.e(TAG, "Unable to get WifiP2p network interface", e); + return; + } + + List interfaceAddresses = Collections.list(wifiP2pInterface.getInetAddresses()); + IPAddress[] ipAddresses = new IPAddress[interfaceAddresses.size()]; + for (int i = 0; i < interfaceAddresses.size(); ++i) { + ipAddresses[i] = new IPAddress(interfaceAddresses.get(i).getAddress()); + } + + wifiP2pNetworkInfo = + new NetworkInformation( + wifiP2pGroup.getInterface(), + ConnectionType.CONNECTION_WIFI, + WIFI_P2P_NETWORK_HANDLE, + ipAddresses); + observer.onNetworkConnect(wifiP2pNetworkInfo); + } + + /** Handle a state change notification about wifi p2p. */ + private void onWifiP2pStateChange(int state) { + if (state == WifiP2pManager.WIFI_P2P_STATE_DISABLED) { + wifiP2pNetworkInfo = null; + observer.onNetworkDisconnect(WIFI_P2P_NETWORK_HANDLE); + } + } + } + static final long INVALID_NET_ID = -1; private static final String TAG = "NetworkMonitorAutoDetect"; @@ -417,6 +506,7 @@ public class NetworkMonitorAutoDetect extends BroadcastReceiver { // connectivityManagerDelegate and wifiManagerDelegate are only non-final for testing. private ConnectivityManagerDelegate connectivityManagerDelegate; private WifiManagerDelegate wifiManagerDelegate; + private WifiDirectManagerDelegate wifiDirectManagerDelegate; private boolean isRegistered; private ConnectionType connectionType; @@ -449,6 +539,10 @@ public class NetworkMonitorAutoDetect extends BroadcastReceiver { wifiSSID = getWifiSSID(networkState); intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION); + if (PeerConnectionFactory.fieldTrialsFindFullName("IncludeWifiDirect").equals("Enabled")) { + wifiDirectManagerDelegate = new WifiDirectManagerDelegate(observer, context); + } + registerReceiver(); if (connectivityManagerDelegate.supportNetworkCallback()) { // On Android 6.0.0, the WRITE_SETTINGS permission is necessary for @@ -496,7 +590,12 @@ public class NetworkMonitorAutoDetect extends BroadcastReceiver { } List getActiveNetworkList() { - return connectivityManagerDelegate.getActiveNetworkList(); + ArrayList result = + new ArrayList(connectivityManagerDelegate.getActiveNetworkList()); + if (wifiDirectManagerDelegate != null) { + result.addAll(wifiDirectManagerDelegate.getActiveNetworkList()); + } + return result; } public void destroy() { @@ -506,6 +605,9 @@ public class NetworkMonitorAutoDetect extends BroadcastReceiver { if (mobileNetworkCallback != null) { connectivityManagerDelegate.releaseCallback(mobileNetworkCallback); } + if (wifiDirectManagerDelegate != null) { + wifiDirectManagerDelegate.release(); + } unregisterReceiver(); } diff --git a/webrtc/sdk/android/src/jni/androidnetworkmonitor_jni.cc b/webrtc/sdk/android/src/jni/androidnetworkmonitor_jni.cc index e2576ccba2..4047f79dba 100644 --- a/webrtc/sdk/android/src/jni/androidnetworkmonitor_jni.cc +++ b/webrtc/sdk/android/src/jni/androidnetworkmonitor_jni.cc @@ -229,6 +229,10 @@ rtc::NetworkBindingResult AndroidNetworkMonitor::BindSocketToNetwork( const rtc::IPAddress& address) { RTC_CHECK(thread_checker_.CalledOnValidThread()); + if (socket_fd == 0 /* NETWORK_UNSPECIFIED */) { + return rtc::NetworkBindingResult::NOT_IMPLEMENTED; + } + jmethodID network_binding_supported_id = GetMethodID( jni(), *j_network_monitor_class_, "networkBindingSupported", "()Z"); // Android prior to Lollipop didn't have support for binding sockets to