Create network change notifier and pass the event to NetworkManager
BUG= Review URL: https://codereview.webrtc.org/1391703003 Cr-Commit-Position: refs/heads/master@{#10325}
This commit is contained in:
@ -14,6 +14,7 @@
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
|
||||
<instrumentation
|
||||
android:name="android.test.InstrumentationTestRunner"
|
||||
|
@ -0,0 +1,288 @@
|
||||
/*
|
||||
* libjingle
|
||||
* Copyright 2015 Google Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.webrtc;
|
||||
|
||||
import static org.webrtc.NetworkMonitorAutoDetect.ConnectionType;
|
||||
import static org.webrtc.NetworkMonitorAutoDetect.ConnectivityManagerDelegate;
|
||||
import static org.webrtc.NetworkMonitorAutoDetect.INVALID_NET_ID;
|
||||
import static org.webrtc.NetworkMonitorAutoDetect.NetworkState;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.Network;
|
||||
import android.net.wifi.WifiManager;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.test.ActivityTestCase;
|
||||
import android.test.UiThreadTest;
|
||||
import android.test.suitebuilder.annotation.MediumTest;
|
||||
import android.test.suitebuilder.annotation.SmallTest;
|
||||
|
||||
/**
|
||||
* Tests for org.webrtc.NetworkMonitor.
|
||||
*/
|
||||
@SuppressLint("NewApi")
|
||||
public class NetworkMonitorTest extends ActivityTestCase {
|
||||
/**
|
||||
* Listens for alerts fired by the NetworkMonitor when network status changes.
|
||||
*/
|
||||
private static class NetworkMonitorTestObserver
|
||||
implements NetworkMonitor.NetworkObserver {
|
||||
private boolean receivedNotification = false;
|
||||
|
||||
@Override
|
||||
public void onConnectionTypeChanged(ConnectionType connectionType) {
|
||||
receivedNotification = true;
|
||||
}
|
||||
|
||||
public boolean hasReceivedNotification() {
|
||||
return receivedNotification;
|
||||
}
|
||||
|
||||
public void resetHasReceivedNotification() {
|
||||
receivedNotification = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mocks out calls to the ConnectivityManager.
|
||||
*/
|
||||
private static class MockConnectivityManagerDelegate extends ConnectivityManagerDelegate {
|
||||
private boolean activeNetworkExists;
|
||||
private int networkType;
|
||||
private int networkSubtype;
|
||||
|
||||
@Override
|
||||
public NetworkState getNetworkState() {
|
||||
return new NetworkState(activeNetworkExists, networkType, networkSubtype);
|
||||
}
|
||||
|
||||
// Dummy implementations to avoid NullPointerExceptions in default implementations:
|
||||
|
||||
@Override
|
||||
public int getDefaultNetId() {
|
||||
return INVALID_NET_ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Network[] getAllNetworks() {
|
||||
return new Network[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public NetworkState getNetworkState(Network network) {
|
||||
return new NetworkState(false, -1, -1);
|
||||
}
|
||||
|
||||
public void setActiveNetworkExists(boolean networkExists) {
|
||||
activeNetworkExists = networkExists;
|
||||
}
|
||||
|
||||
public void setNetworkType(int networkType) {
|
||||
this.networkType = networkType;
|
||||
}
|
||||
|
||||
public void setNetworkSubtype(int networkSubtype) {
|
||||
this.networkSubtype = networkSubtype;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mocks out calls to the WifiManager.
|
||||
*/
|
||||
private static class MockWifiManagerDelegate
|
||||
extends NetworkMonitorAutoDetect.WifiManagerDelegate {
|
||||
private String wifiSSID;
|
||||
|
||||
@Override
|
||||
public String getWifiSSID() {
|
||||
return wifiSSID;
|
||||
}
|
||||
|
||||
public void setWifiSSID(String wifiSSID) {
|
||||
this.wifiSSID = wifiSSID;
|
||||
}
|
||||
}
|
||||
|
||||
// A dummy NetworkMonitorAutoDetect.Observer.
|
||||
private static class TestNetworkMonitorAutoDetectObserver
|
||||
implements NetworkMonitorAutoDetect.Observer {
|
||||
|
||||
@Override
|
||||
public void onConnectionTypeChanged(ConnectionType newConnectionType) {}
|
||||
}
|
||||
|
||||
private static final Object lock = new Object();
|
||||
private static Handler uiThreadHandler = null;
|
||||
|
||||
private NetworkMonitorAutoDetect receiver;
|
||||
private MockConnectivityManagerDelegate connectivityDelegate;
|
||||
private MockWifiManagerDelegate wifiDelegate;
|
||||
|
||||
private static Handler getUiThreadHandler() {
|
||||
synchronized (lock) {
|
||||
if (uiThreadHandler == null ) {
|
||||
uiThreadHandler = new Handler(Looper.getMainLooper());
|
||||
}
|
||||
return uiThreadHandler;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to create a network monitor and delegates for testing.
|
||||
*/
|
||||
private void createTestMonitor() {
|
||||
Context context = getInstrumentation().getTargetContext();
|
||||
NetworkMonitor.resetInstanceForTests(context);
|
||||
NetworkMonitor.setAutoDetectConnectivityState(true);
|
||||
receiver = NetworkMonitor.getAutoDetectorForTest();
|
||||
assertNotNull(receiver);
|
||||
|
||||
connectivityDelegate = new MockConnectivityManagerDelegate();
|
||||
connectivityDelegate.setActiveNetworkExists(true);
|
||||
receiver.setConnectivityManagerDelegateForTests(connectivityDelegate);
|
||||
|
||||
wifiDelegate = new MockWifiManagerDelegate();
|
||||
receiver.setWifiManagerDelegateForTests(wifiDelegate);
|
||||
wifiDelegate.setWifiSSID("foo");
|
||||
}
|
||||
|
||||
private NetworkMonitorAutoDetect.ConnectionType getCurrentConnectionType() {
|
||||
final NetworkMonitorAutoDetect.NetworkState networkState =
|
||||
receiver.getCurrentNetworkState();
|
||||
return receiver.getCurrentConnectionType(networkState);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
getUiThreadHandler().post(new Runnable() {
|
||||
public void run() {
|
||||
createTestMonitor();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the receiver registers for connectivity intents during construction.
|
||||
*/
|
||||
@UiThreadTest
|
||||
@SmallTest
|
||||
public void testNetworkMonitorRegistersInConstructor() throws InterruptedException {
|
||||
Context context = getInstrumentation().getTargetContext();
|
||||
|
||||
NetworkMonitorAutoDetect.Observer observer = new TestNetworkMonitorAutoDetectObserver();
|
||||
|
||||
NetworkMonitorAutoDetect receiver = new NetworkMonitorAutoDetect(observer, context);
|
||||
|
||||
assertTrue(receiver.isReceiverRegisteredForTesting());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that when there is an intent indicating a change in network connectivity, it sends a
|
||||
* notification to Java observers.
|
||||
*/
|
||||
@UiThreadTest
|
||||
@MediumTest
|
||||
public void testNetworkMonitorJavaObservers() throws InterruptedException {
|
||||
// Initialize the NetworkMonitor with a connection.
|
||||
Intent connectivityIntent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
|
||||
receiver.onReceive(getInstrumentation().getTargetContext(), connectivityIntent);
|
||||
|
||||
// We shouldn't be re-notified if the connection hasn't actually changed.
|
||||
NetworkMonitorTestObserver observer = new NetworkMonitorTestObserver();
|
||||
NetworkMonitor.addNetworkObserver(observer);
|
||||
receiver.onReceive(getInstrumentation().getTargetContext(), connectivityIntent);
|
||||
assertFalse(observer.hasReceivedNotification());
|
||||
|
||||
// We shouldn't be notified if we're connected to non-Wifi and the Wifi SSID changes.
|
||||
wifiDelegate.setWifiSSID("bar");
|
||||
receiver.onReceive(getInstrumentation().getTargetContext(), connectivityIntent);
|
||||
assertFalse(observer.hasReceivedNotification());
|
||||
|
||||
// We should be notified when we change to Wifi.
|
||||
connectivityDelegate.setNetworkType(ConnectivityManager.TYPE_WIFI);
|
||||
receiver.onReceive(getInstrumentation().getTargetContext(), connectivityIntent);
|
||||
assertTrue(observer.hasReceivedNotification());
|
||||
observer.resetHasReceivedNotification();
|
||||
|
||||
// We should be notified when the Wifi SSID changes.
|
||||
wifiDelegate.setWifiSSID("foo");
|
||||
receiver.onReceive(getInstrumentation().getTargetContext(), connectivityIntent);
|
||||
assertTrue(observer.hasReceivedNotification());
|
||||
observer.resetHasReceivedNotification();
|
||||
|
||||
// We shouldn't be re-notified if the Wifi SSID hasn't actually changed.
|
||||
receiver.onReceive(getInstrumentation().getTargetContext(), connectivityIntent);
|
||||
assertFalse(observer.hasReceivedNotification());
|
||||
|
||||
// Mimic that connectivity has been lost and ensure that the observer gets the notification.
|
||||
connectivityDelegate.setActiveNetworkExists(false);
|
||||
Intent noConnectivityIntent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
|
||||
receiver.onReceive(getInstrumentation().getTargetContext(), noConnectivityIntent);
|
||||
assertTrue(observer.hasReceivedNotification());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that ConnectivityManagerDelegate doesn't crash. This test cannot rely on having any
|
||||
* active network connections so it cannot usefully check results, but it can at least check
|
||||
* that the functions don't crash.
|
||||
*/
|
||||
@UiThreadTest
|
||||
@SmallTest
|
||||
public void testConnectivityManagerDelegateDoesNotCrash() {
|
||||
ConnectivityManagerDelegate delegate =
|
||||
new ConnectivityManagerDelegate(getInstrumentation().getTargetContext());
|
||||
delegate.getNetworkState();
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
Network[] networks = delegate.getAllNetworks();
|
||||
if (networks.length >= 1) {
|
||||
delegate.getNetworkState(networks[0]);
|
||||
delegate.hasInternetCapability(networks[0]);
|
||||
}
|
||||
delegate.getDefaultNetId();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that NetworkMonitorAutoDetect queryable APIs don't crash. This test cannot rely
|
||||
* on having any active network connections so it cannot usefully check results, but it can at
|
||||
* least check that the functions don't crash.
|
||||
*/
|
||||
@UiThreadTest
|
||||
@SmallTest
|
||||
public void testQueryableAPIsDoNotCrash() {
|
||||
NetworkMonitorAutoDetect.Observer observer = new TestNetworkMonitorAutoDetectObserver();
|
||||
NetworkMonitorAutoDetect ncn =
|
||||
new NetworkMonitorAutoDetect(observer, getInstrumentation().getTargetContext());
|
||||
ncn.getDefaultNetId();
|
||||
}
|
||||
}
|
228
talk/app/webrtc/java/android/org/webrtc/NetworkMonitor.java
Normal file
228
talk/app/webrtc/java/android/org/webrtc/NetworkMonitor.java
Normal file
@ -0,0 +1,228 @@
|
||||
/*
|
||||
* libjingle
|
||||
* Copyright 2015 Google Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.webrtc;
|
||||
|
||||
import static org.webrtc.NetworkMonitorAutoDetect.ConnectionType;
|
||||
import static org.webrtc.NetworkMonitorAutoDetect.INVALID_NET_ID;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Borrowed from Chromium's src/net/android/java/src/org/chromium/net/NetworkChangeNotifier.java
|
||||
*
|
||||
* Triggers updates to the underlying network state from OS networking events.
|
||||
*
|
||||
* WARNING: This class is not thread-safe.
|
||||
*/
|
||||
public class NetworkMonitor {
|
||||
/**
|
||||
* Alerted when the connection type of the network changes.
|
||||
* The alert is fired on the UI thread.
|
||||
*/
|
||||
public interface NetworkObserver {
|
||||
public void onConnectionTypeChanged(ConnectionType connectionType);
|
||||
}
|
||||
|
||||
private static final String TAG = "NetworkMonitor";
|
||||
private static NetworkMonitor instance;
|
||||
|
||||
private final Context applicationContext;
|
||||
|
||||
// Native observers of the connection type changes.
|
||||
private final ArrayList<Long> nativeNetworkObservers;
|
||||
// Java observers of the connection type changes.
|
||||
private final ArrayList<NetworkObserver> networkObservers;
|
||||
|
||||
// Object that detects the connection type changes.
|
||||
private NetworkMonitorAutoDetect autoDetector;
|
||||
|
||||
private ConnectionType currentConnectionType = ConnectionType.CONNECTION_UNKNOWN;
|
||||
|
||||
private NetworkMonitor(Context context) {
|
||||
assertIsTrue(context != null);
|
||||
applicationContext =
|
||||
context.getApplicationContext() == null ? context : context.getApplicationContext();
|
||||
|
||||
nativeNetworkObservers = new ArrayList<Long>();
|
||||
networkObservers = new ArrayList<NetworkObserver>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the singleton once.
|
||||
* Called from the native code.
|
||||
*/
|
||||
public static NetworkMonitor init(Context context) {
|
||||
if (!isInitialized()) {
|
||||
instance = new NetworkMonitor(context);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static boolean isInitialized() {
|
||||
return instance != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the singleton instance.
|
||||
*/
|
||||
public static NetworkMonitor getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables auto detection of the current network state based on notifications from the system.
|
||||
* Note that passing true here requires the embedding app have the platform ACCESS_NETWORK_STATE
|
||||
* permission.
|
||||
*
|
||||
* @param shouldAutoDetect true if the NetworkMonitor should listen for system changes in
|
||||
* network connectivity.
|
||||
*/
|
||||
public static void setAutoDetectConnectivityState(boolean shouldAutoDetect) {
|
||||
getInstance().setAutoDetectConnectivityStateInternal(shouldAutoDetect);
|
||||
}
|
||||
|
||||
private static void assertIsTrue(boolean condition) {
|
||||
if (!condition) {
|
||||
throw new AssertionError("Expected to be true");
|
||||
}
|
||||
}
|
||||
|
||||
// Called by the native code.
|
||||
private void startMonitoring(long nativeObserver) {
|
||||
Log.d(TAG, "Start monitoring from native observer " + nativeObserver);
|
||||
nativeNetworkObservers.add(nativeObserver);
|
||||
setAutoDetectConnectivityStateInternal(true);
|
||||
}
|
||||
|
||||
// Called by the native code.
|
||||
private void stopMonitoring(long nativeObserver) {
|
||||
Log.d(TAG, "Stop monitoring from native observer " + nativeObserver);
|
||||
setAutoDetectConnectivityStateInternal(false);
|
||||
nativeNetworkObservers.remove(nativeObserver);
|
||||
}
|
||||
|
||||
private ConnectionType getCurrentConnectionType() {
|
||||
return currentConnectionType;
|
||||
}
|
||||
|
||||
private int getCurrentDefaultNetId() {
|
||||
return autoDetector == null ? INVALID_NET_ID : autoDetector.getDefaultNetId();
|
||||
}
|
||||
|
||||
private void destroyAutoDetector() {
|
||||
if (autoDetector != null) {
|
||||
autoDetector.destroy();
|
||||
autoDetector = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void setAutoDetectConnectivityStateInternal(boolean shouldAutoDetect) {
|
||||
if (!shouldAutoDetect) {
|
||||
destroyAutoDetector();
|
||||
return;
|
||||
}
|
||||
if (autoDetector == null) {
|
||||
autoDetector = new NetworkMonitorAutoDetect(
|
||||
new NetworkMonitorAutoDetect.Observer() {
|
||||
@Override
|
||||
public void onConnectionTypeChanged(ConnectionType newConnectionType) {
|
||||
updateCurrentConnectionType(newConnectionType);
|
||||
}
|
||||
},
|
||||
applicationContext);
|
||||
final NetworkMonitorAutoDetect.NetworkState networkState =
|
||||
autoDetector.getCurrentNetworkState();
|
||||
updateCurrentConnectionType(autoDetector.getCurrentConnectionType(networkState));
|
||||
}
|
||||
}
|
||||
|
||||
private void updateCurrentConnectionType(ConnectionType newConnectionType) {
|
||||
currentConnectionType = newConnectionType;
|
||||
notifyObserversOfConnectionTypeChange(newConnectionType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Alerts all observers of a connection change.
|
||||
*/
|
||||
private void notifyObserversOfConnectionTypeChange(ConnectionType newConnectionType) {
|
||||
for (long nativeObserver : nativeNetworkObservers) {
|
||||
nativeNotifyConnectionTypeChanged(nativeObserver);
|
||||
}
|
||||
for (NetworkObserver observer : networkObservers) {
|
||||
observer.onConnectionTypeChanged(newConnectionType);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an observer for any connection type changes.
|
||||
*/
|
||||
public static void addNetworkObserver(NetworkObserver observer) {
|
||||
getInstance().addNetworkObserverInternal(observer);
|
||||
}
|
||||
|
||||
private void addNetworkObserverInternal(NetworkObserver observer) {
|
||||
networkObservers.add(observer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an observer for any connection type changes.
|
||||
*/
|
||||
public static void removeNetworkObserver(NetworkObserver observer) {
|
||||
getInstance().removeNetworkObserverInternal(observer);
|
||||
}
|
||||
|
||||
private void removeNetworkObserverInternal(NetworkObserver observer) {
|
||||
networkObservers.remove(observer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if there currently is connectivity.
|
||||
*/
|
||||
public static boolean isOnline() {
|
||||
ConnectionType connectionType = getInstance().getCurrentConnectionType();
|
||||
return connectionType != ConnectionType.CONNECTION_UNKNOWN
|
||||
&& connectionType != ConnectionType.CONNECTION_NONE;
|
||||
}
|
||||
|
||||
private native long nativeCreateNetworkMonitor();
|
||||
|
||||
private native void nativeNotifyConnectionTypeChanged(long nativePtr);
|
||||
|
||||
// For testing only.
|
||||
static void resetInstanceForTests(Context context) {
|
||||
instance = new NetworkMonitor(context);
|
||||
}
|
||||
|
||||
// For testing only.
|
||||
public static NetworkMonitorAutoDetect getAutoDetectorForTest() {
|
||||
return getInstance().autoDetector;
|
||||
}
|
||||
}
|
@ -0,0 +1,424 @@
|
||||
/*
|
||||
* libjingle
|
||||
* Copyright 2015 Google Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.webrtc;
|
||||
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
|
||||
|
||||
import android.Manifest.permission;
|
||||
import android.annotation.SuppressLint;
|
||||
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.Network;
|
||||
import android.net.NetworkCapabilities;
|
||||
import android.net.NetworkInfo;
|
||||
import android.net.wifi.WifiInfo;
|
||||
import android.net.wifi.WifiManager;
|
||||
import android.os.Build;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* Borrowed from Chromium's
|
||||
* src/net/android/java/src/org/chromium/net/NetworkChangeNotifierAutoDetect.java
|
||||
*
|
||||
* Used by the NetworkMonitor to listen to platform changes in connectivity.
|
||||
* Note that use of this class requires that the app have the platform
|
||||
* ACCESS_NETWORK_STATE permission.
|
||||
*/
|
||||
public class NetworkMonitorAutoDetect extends BroadcastReceiver {
|
||||
static enum ConnectionType {
|
||||
CONNECTION_UNKNOWN,
|
||||
CONNECTION_ETHERNET,
|
||||
CONNECTION_WIFI,
|
||||
CONNECTION_4G,
|
||||
CONNECTION_3G,
|
||||
CONNECTION_2G,
|
||||
CONNECTION_BLUETOOTH,
|
||||
CONNECTION_NONE
|
||||
}
|
||||
|
||||
static class NetworkState {
|
||||
private final boolean connected;
|
||||
// Defined from ConnectivityManager.TYPE_XXX for non-mobile; for mobile, it is
|
||||
// further divided into 2G, 3G, or 4G from the subtype.
|
||||
private final int type;
|
||||
// Defined from NetworkInfo.subtype, which is one of the TelephonyManager.NETWORK_TYPE_XXXs.
|
||||
// Will be useful to find the maximum bandwidth.
|
||||
private final int subtype;
|
||||
|
||||
public NetworkState(boolean connected, int type, int subtype) {
|
||||
this.connected = connected;
|
||||
this.type = type;
|
||||
this.subtype = subtype;
|
||||
}
|
||||
|
||||
public boolean isConnected() {
|
||||
return connected;
|
||||
}
|
||||
|
||||
public int getNetworkType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public int getNetworkSubType() {
|
||||
return subtype;
|
||||
}
|
||||
}
|
||||
|
||||
/** Queries the ConnectivityManager for information about the current connection. */
|
||||
static class ConnectivityManagerDelegate {
|
||||
private final ConnectivityManager connectivityManager;
|
||||
|
||||
ConnectivityManagerDelegate(Context context) {
|
||||
connectivityManager =
|
||||
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
}
|
||||
|
||||
// For testing.
|
||||
ConnectivityManagerDelegate() {
|
||||
// All the methods below should be overridden.
|
||||
connectivityManager = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns connection type and status information about the current
|
||||
* default network.
|
||||
*/
|
||||
NetworkState getNetworkState() {
|
||||
return getNetworkState(connectivityManager.getActiveNetworkInfo());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns connection type and status information about |network|.
|
||||
* Only callable on Lollipop and newer releases.
|
||||
*/
|
||||
@SuppressLint("NewApi")
|
||||
NetworkState getNetworkState(Network network) {
|
||||
return getNetworkState(connectivityManager.getNetworkInfo(network));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns connection type and status information gleaned from networkInfo.
|
||||
*/
|
||||
NetworkState getNetworkState(NetworkInfo networkInfo) {
|
||||
if (networkInfo == null || !networkInfo.isConnected()) {
|
||||
return new NetworkState(false, -1, -1);
|
||||
}
|
||||
return new NetworkState(true, networkInfo.getType(), networkInfo.getSubtype());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all connected networks.
|
||||
* Only callable on Lollipop and newer releases.
|
||||
*/
|
||||
@SuppressLint("NewApi")
|
||||
Network[] getAllNetworks() {
|
||||
return connectivityManager.getAllNetworks();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the NetID of the current default network. Returns
|
||||
* INVALID_NET_ID if no current default network connected.
|
||||
* Only callable on Lollipop and newer releases.
|
||||
*/
|
||||
@SuppressLint("NewApi")
|
||||
int getDefaultNetId() {
|
||||
// Android Lollipop had no API to get the default network; only an
|
||||
// API to return the NetworkInfo for the default network. To
|
||||
// determine the default network one can find the network with
|
||||
// type matching that of the default network.
|
||||
final NetworkInfo defaultNetworkInfo = connectivityManager.getActiveNetworkInfo();
|
||||
if (defaultNetworkInfo == null) {
|
||||
return INVALID_NET_ID;
|
||||
}
|
||||
final Network[] networks = getAllNetworks();
|
||||
int defaultNetId = INVALID_NET_ID;
|
||||
for (Network network : networks) {
|
||||
if (!hasInternetCapability(network)) {
|
||||
continue;
|
||||
}
|
||||
final NetworkInfo networkInfo = connectivityManager.getNetworkInfo(network);
|
||||
if (networkInfo != null && networkInfo.getType() == defaultNetworkInfo.getType()) {
|
||||
// There should not be multiple connected networks of the
|
||||
// same type. At least as of Android Marshmallow this is
|
||||
// not supported. If this becomes supported this assertion
|
||||
// may trigger. At that point we could consider using
|
||||
// ConnectivityManager.getDefaultNetwork() though this
|
||||
// may give confusing results with VPNs and is only
|
||||
// available with Android Marshmallow.
|
||||
assert defaultNetId == INVALID_NET_ID;
|
||||
defaultNetId = networkToNetId(network);
|
||||
}
|
||||
}
|
||||
return defaultNetId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if {@code network} can provide Internet access. Can be used to
|
||||
* ignore specialized networks (e.g. IMS, FOTA).
|
||||
*/
|
||||
@SuppressLint("NewApi")
|
||||
boolean hasInternetCapability(Network network) {
|
||||
final NetworkCapabilities capabilities =
|
||||
connectivityManager.getNetworkCapabilities(network);
|
||||
return capabilities != null && capabilities.hasCapability(NET_CAPABILITY_INTERNET);
|
||||
}
|
||||
}
|
||||
|
||||
/** Queries the WifiManager for SSID of the current Wifi connection. */
|
||||
static class WifiManagerDelegate {
|
||||
private final Context context;
|
||||
private final WifiManager wifiManager;
|
||||
private final boolean hasWifiPermission;
|
||||
|
||||
WifiManagerDelegate(Context context) {
|
||||
this.context = context;
|
||||
|
||||
hasWifiPermission = context.getPackageManager().checkPermission(
|
||||
permission.ACCESS_WIFI_STATE, context.getPackageName())
|
||||
== PackageManager.PERMISSION_GRANTED;
|
||||
wifiManager = hasWifiPermission
|
||||
? (WifiManager) context.getSystemService(Context.WIFI_SERVICE) : null;
|
||||
}
|
||||
|
||||
// For testing.
|
||||
WifiManagerDelegate() {
|
||||
// All the methods below should be overridden.
|
||||
context = null;
|
||||
wifiManager = null;
|
||||
hasWifiPermission = false;
|
||||
}
|
||||
|
||||
String getWifiSSID() {
|
||||
final Intent intent = context.registerReceiver(null,
|
||||
new IntentFilter(WifiManager.NETWORK_STATE_CHANGED_ACTION));
|
||||
if (intent != null) {
|
||||
final WifiInfo wifiInfo = intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO);
|
||||
if (wifiInfo != null) {
|
||||
final String ssid = wifiInfo.getSSID();
|
||||
if (ssid != null) {
|
||||
return ssid;
|
||||
}
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
boolean getHasWifiPermission() {
|
||||
return hasWifiPermission;
|
||||
}
|
||||
}
|
||||
|
||||
static final int INVALID_NET_ID = -1;
|
||||
private static final String TAG = "NetworkMonitorAutoDetect";
|
||||
private static final int UNKNOWN_LINK_SPEED = -1;
|
||||
private final IntentFilter intentFilter;
|
||||
|
||||
// Observer for the connection type change.
|
||||
private final Observer observer;
|
||||
|
||||
private final Context context;
|
||||
// connectivityManagerDelegates and wifiManagerDelegate are only non-final for testing.
|
||||
private ConnectivityManagerDelegate connectivityManagerDelegate;
|
||||
private WifiManagerDelegate wifiManagerDelegate;
|
||||
private boolean isRegistered;
|
||||
private ConnectionType connectionType;
|
||||
private String wifiSSID;
|
||||
|
||||
/**
|
||||
* Observer interface by which observer is notified of network changes.
|
||||
*/
|
||||
public static interface Observer {
|
||||
/**
|
||||
* Called when default network changes.
|
||||
*/
|
||||
public void onConnectionTypeChanged(ConnectionType newConnectionType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a NetworkMonitorAutoDetect. Should only be called on UI thread.
|
||||
*/
|
||||
public NetworkMonitorAutoDetect(Observer observer, Context context) {
|
||||
this.observer = observer;
|
||||
this.context = context;
|
||||
connectivityManagerDelegate = new ConnectivityManagerDelegate(context);
|
||||
wifiManagerDelegate = new WifiManagerDelegate(context);
|
||||
|
||||
final NetworkState networkState = connectivityManagerDelegate.getNetworkState();
|
||||
connectionType = getCurrentConnectionType(networkState);
|
||||
wifiSSID = getCurrentWifiSSID(networkState);
|
||||
intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
|
||||
registerReceiver();
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows overriding the ConnectivityManagerDelegate for tests.
|
||||
*/
|
||||
void setConnectivityManagerDelegateForTests(ConnectivityManagerDelegate delegate) {
|
||||
connectivityManagerDelegate = delegate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows overriding the WifiManagerDelegate for tests.
|
||||
*/
|
||||
void setWifiManagerDelegateForTests(WifiManagerDelegate delegate) {
|
||||
wifiManagerDelegate = delegate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the object has registered to receive network connectivity intents.
|
||||
* Visible for testing.
|
||||
*/
|
||||
boolean isReceiverRegisteredForTesting() {
|
||||
return isRegistered;
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
unregisterReceiver();
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a BroadcastReceiver in the given context.
|
||||
*/
|
||||
private void registerReceiver() {
|
||||
if (!isRegistered) {
|
||||
isRegistered = true;
|
||||
context.registerReceiver(this, intentFilter);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters the BroadcastReceiver in the given context.
|
||||
*/
|
||||
private void unregisterReceiver() {
|
||||
if (isRegistered) {
|
||||
isRegistered = false;
|
||||
context.unregisterReceiver(this);
|
||||
}
|
||||
}
|
||||
|
||||
public NetworkState getCurrentNetworkState() {
|
||||
return connectivityManagerDelegate.getNetworkState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns NetID of device's current default connected network used for
|
||||
* communication.
|
||||
* Only implemented on Lollipop and newer releases, returns INVALID_NET_ID
|
||||
* when not implemented.
|
||||
*/
|
||||
public int getDefaultNetId() {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||
return INVALID_NET_ID;
|
||||
}
|
||||
return connectivityManagerDelegate.getDefaultNetId();
|
||||
}
|
||||
|
||||
public ConnectionType getCurrentConnectionType(NetworkState networkState) {
|
||||
if (!networkState.isConnected()) {
|
||||
return ConnectionType.CONNECTION_NONE;
|
||||
}
|
||||
|
||||
switch (networkState.getNetworkType()) {
|
||||
case ConnectivityManager.TYPE_ETHERNET:
|
||||
return ConnectionType.CONNECTION_ETHERNET;
|
||||
case ConnectivityManager.TYPE_WIFI:
|
||||
return ConnectionType.CONNECTION_WIFI;
|
||||
case ConnectivityManager.TYPE_WIMAX:
|
||||
return ConnectionType.CONNECTION_4G;
|
||||
case ConnectivityManager.TYPE_BLUETOOTH:
|
||||
return ConnectionType.CONNECTION_BLUETOOTH;
|
||||
case ConnectivityManager.TYPE_MOBILE:
|
||||
// Use information from TelephonyManager to classify the connection.
|
||||
switch (networkState.getNetworkSubType()) {
|
||||
case TelephonyManager.NETWORK_TYPE_GPRS:
|
||||
case TelephonyManager.NETWORK_TYPE_EDGE:
|
||||
case TelephonyManager.NETWORK_TYPE_CDMA:
|
||||
case TelephonyManager.NETWORK_TYPE_1xRTT:
|
||||
case TelephonyManager.NETWORK_TYPE_IDEN:
|
||||
return ConnectionType.CONNECTION_2G;
|
||||
case TelephonyManager.NETWORK_TYPE_UMTS:
|
||||
case TelephonyManager.NETWORK_TYPE_EVDO_0:
|
||||
case TelephonyManager.NETWORK_TYPE_EVDO_A:
|
||||
case TelephonyManager.NETWORK_TYPE_HSDPA:
|
||||
case TelephonyManager.NETWORK_TYPE_HSUPA:
|
||||
case TelephonyManager.NETWORK_TYPE_HSPA:
|
||||
case TelephonyManager.NETWORK_TYPE_EVDO_B:
|
||||
case TelephonyManager.NETWORK_TYPE_EHRPD:
|
||||
case TelephonyManager.NETWORK_TYPE_HSPAP:
|
||||
return ConnectionType.CONNECTION_3G;
|
||||
case TelephonyManager.NETWORK_TYPE_LTE:
|
||||
return ConnectionType.CONNECTION_4G;
|
||||
default:
|
||||
return ConnectionType.CONNECTION_UNKNOWN;
|
||||
}
|
||||
default:
|
||||
return ConnectionType.CONNECTION_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
private String getCurrentWifiSSID(NetworkState networkState) {
|
||||
if (getCurrentConnectionType(networkState) != ConnectionType.CONNECTION_WIFI) return "";
|
||||
return wifiManagerDelegate.getWifiSSID();
|
||||
}
|
||||
|
||||
// BroadcastReceiver
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
final NetworkState networkState = getCurrentNetworkState();
|
||||
if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
|
||||
connectionTypeChanged(networkState);
|
||||
}
|
||||
}
|
||||
|
||||
private void connectionTypeChanged(NetworkState networkState) {
|
||||
ConnectionType newConnectionType = getCurrentConnectionType(networkState);
|
||||
String newWifiSSID = getCurrentWifiSSID(networkState);
|
||||
if (newConnectionType == connectionType && newWifiSSID.equals(wifiSSID)) return;
|
||||
|
||||
connectionType = newConnectionType;
|
||||
wifiSSID = newWifiSSID;
|
||||
Log.d(TAG, "Network connectivity changed, type is: " + connectionType);
|
||||
observer.onConnectionTypeChanged(newConnectionType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts NetID of network. Only available on Lollipop and newer releases.
|
||||
*/
|
||||
@SuppressLint("NewApi")
|
||||
private static int networkToNetId(Network network) {
|
||||
// NOTE(pauljensen): This depends on Android framework implementation details.
|
||||
// Fortunately this functionality is unlikely to ever change.
|
||||
// TODO(honghaiz): When we update to Android M SDK, use Network.getNetworkHandle().
|
||||
return Integer.parseInt(network.toString());
|
||||
}
|
||||
}
|
85
talk/app/webrtc/java/jni/androidnetworkmonitor_jni.cc
Normal file
85
talk/app/webrtc/java/jni/androidnetworkmonitor_jni.cc
Normal file
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* libjingle
|
||||
* Copyright 2015 Google Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "talk/app/webrtc/java/jni/androidnetworkmonitor_jni.h"
|
||||
|
||||
#include "webrtc/base/common.h"
|
||||
#include "talk/app/webrtc/java/jni/classreferenceholder.h"
|
||||
#include "talk/app/webrtc/java/jni/jni_helpers.h"
|
||||
|
||||
namespace webrtc_jni {
|
||||
jobject AndroidNetworkMonitor::application_context_ = nullptr;
|
||||
|
||||
// static
|
||||
void AndroidNetworkMonitor::SetAndroidContext(JNIEnv* jni, jobject context) {
|
||||
if (application_context_) {
|
||||
jni->DeleteGlobalRef(application_context_);
|
||||
}
|
||||
application_context_ = NewGlobalRef(jni, context);
|
||||
}
|
||||
|
||||
AndroidNetworkMonitor::AndroidNetworkMonitor()
|
||||
: j_network_monitor_class_(jni(),
|
||||
FindClass(jni(), "org/webrtc/NetworkMonitor")),
|
||||
j_network_monitor_(
|
||||
jni(),
|
||||
jni()->CallStaticObjectMethod(
|
||||
*j_network_monitor_class_,
|
||||
GetStaticMethodID(
|
||||
jni(),
|
||||
*j_network_monitor_class_,
|
||||
"init",
|
||||
"(Landroid/content/Context;)Lorg/webrtc/NetworkMonitor;"),
|
||||
application_context_)) {
|
||||
ASSERT(application_context_ != nullptr);
|
||||
CHECK_EXCEPTION(jni()) << "Error during NetworkMonitor.init";
|
||||
}
|
||||
|
||||
void AndroidNetworkMonitor::Start() {
|
||||
RTC_CHECK(thread_checker_.CalledOnValidThread());
|
||||
jmethodID m =
|
||||
GetMethodID(jni(), *j_network_monitor_class_, "startMonitoring", "(J)V");
|
||||
jni()->CallVoidMethod(*j_network_monitor_, m, jlongFromPointer(this));
|
||||
CHECK_EXCEPTION(jni()) << "Error during NetworkMonitor.startMonitoring";
|
||||
}
|
||||
|
||||
void AndroidNetworkMonitor::Stop() {
|
||||
RTC_CHECK(thread_checker_.CalledOnValidThread());
|
||||
jmethodID m =
|
||||
GetMethodID(jni(), *j_network_monitor_class_, "stopMonitoring", "(J)V");
|
||||
jni()->CallVoidMethod(*j_network_monitor_, m, jlongFromPointer(this));
|
||||
CHECK_EXCEPTION(jni()) << "Error during NetworkMonitor.stopMonitoring";
|
||||
}
|
||||
|
||||
JOW(void, NetworkMonitor_nativeNotifyConnectionTypeChanged)(
|
||||
JNIEnv* jni, jobject j_monitor, jlong j_native_monitor) {
|
||||
rtc::NetworkMonitorInterface* network_monitor =
|
||||
reinterpret_cast<rtc::NetworkMonitorInterface*>(j_native_monitor);
|
||||
network_monitor->OnNetworksChanged();
|
||||
}
|
||||
|
||||
} // namespace webrtc_jni
|
67
talk/app/webrtc/java/jni/androidnetworkmonitor_jni.h
Normal file
67
talk/app/webrtc/java/jni/androidnetworkmonitor_jni.h
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* libjingle
|
||||
* Copyright 2015 Google Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef TALK_APP_WEBRTC_JAVA_JNI_ANDROIDNETWORKMONITOR_JNI_H_
|
||||
#define TALK_APP_WEBRTC_JAVA_JNI_ANDROIDNETWORKMONITOR_JNI_H_
|
||||
|
||||
#include "webrtc/base/networkmonitor.h"
|
||||
|
||||
#include "webrtc/base/thread_checker.h"
|
||||
#include "talk/app/webrtc/java/jni/jni_helpers.h"
|
||||
|
||||
namespace webrtc_jni {
|
||||
|
||||
class AndroidNetworkMonitor : public rtc::NetworkMonitorBase {
|
||||
public:
|
||||
AndroidNetworkMonitor();
|
||||
|
||||
static void SetAndroidContext(JNIEnv* jni, jobject context);
|
||||
|
||||
void Start() override;
|
||||
void Stop() override;
|
||||
|
||||
private:
|
||||
JNIEnv* jni() { return AttachCurrentThreadIfNeeded(); }
|
||||
|
||||
ScopedGlobalRef<jclass> j_network_monitor_class_;
|
||||
ScopedGlobalRef<jobject> j_network_monitor_;
|
||||
rtc::ThreadChecker thread_checker_;
|
||||
static jobject application_context_;
|
||||
};
|
||||
|
||||
class AndroidNetworkMonitorFactory : public rtc::NetworkMonitorFactory {
|
||||
public:
|
||||
AndroidNetworkMonitorFactory() {}
|
||||
|
||||
rtc::NetworkMonitorInterface* CreateNetworkMonitor() override {
|
||||
return new AndroidNetworkMonitor();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace webrtc_jni
|
||||
|
||||
#endif // TALK_APP_WEBRTC_JAVA_JNI_ANDROIDNETWORKMONITOR_JNI_H_
|
@ -78,6 +78,7 @@ ClassReferenceHolder::ClassReferenceHolder(JNIEnv* jni) {
|
||||
LoadClass(jni, "org/webrtc/VideoCapturerAndroid");
|
||||
LoadClass(jni, "org/webrtc/VideoCapturerAndroid$NativeObserver");
|
||||
LoadClass(jni, "org/webrtc/EglBase");
|
||||
LoadClass(jni, "org/webrtc/NetworkMonitor");
|
||||
LoadClass(jni, "org/webrtc/MediaCodecVideoEncoder");
|
||||
LoadClass(jni, "org/webrtc/MediaCodecVideoEncoder$OutputBufferInfo");
|
||||
LoadClass(jni, "org/webrtc/MediaCodecVideoEncoder$VideoCodecType");
|
||||
|
@ -76,6 +76,7 @@
|
||||
#include "webrtc/base/checks.h"
|
||||
#include "webrtc/base/logging.h"
|
||||
#include "webrtc/base/logsinks.h"
|
||||
#include "webrtc/base/networkmonitor.h"
|
||||
#include "webrtc/base/messagequeue.h"
|
||||
#include "webrtc/base/ssladapter.h"
|
||||
#include "webrtc/base/stringutils.h"
|
||||
@ -88,6 +89,7 @@
|
||||
#include "talk/app/webrtc/java/jni/androidmediadecoder_jni.h"
|
||||
#include "talk/app/webrtc/java/jni/androidmediaencoder_jni.h"
|
||||
#include "talk/app/webrtc/java/jni/androidvideocapturer_jni.h"
|
||||
#include "talk/app/webrtc/java/jni/androidnetworkmonitor_jni.h"
|
||||
#include "webrtc/modules/video_render/video_render_internal.h"
|
||||
#include "webrtc/system_wrappers/interface/logcat_trace_context.h"
|
||||
using webrtc::LogcatTraceContext;
|
||||
@ -1023,6 +1025,7 @@ JOW(jboolean, PeerConnectionFactory_initializeAndroidGlobals)(
|
||||
jboolean video_hw_acceleration) {
|
||||
bool failure = false;
|
||||
video_hw_acceleration_enabled = video_hw_acceleration;
|
||||
AndroidNetworkMonitor::SetAndroidContext(jni, context);
|
||||
if (!factory_static_initialized) {
|
||||
if (initialize_video) {
|
||||
failure |= webrtc::SetRenderAndroidVM(GetJVM());
|
||||
@ -1063,18 +1066,29 @@ class OwnedFactoryAndThreads {
|
||||
Thread* signaling_thread,
|
||||
WebRtcVideoEncoderFactory* encoder_factory,
|
||||
WebRtcVideoDecoderFactory* decoder_factory,
|
||||
rtc::NetworkMonitorFactory* network_monitor_factory,
|
||||
PeerConnectionFactoryInterface* factory)
|
||||
: worker_thread_(worker_thread),
|
||||
signaling_thread_(signaling_thread),
|
||||
encoder_factory_(encoder_factory),
|
||||
decoder_factory_(decoder_factory),
|
||||
network_monitor_factory_(network_monitor_factory),
|
||||
factory_(factory) {}
|
||||
|
||||
~OwnedFactoryAndThreads() { CHECK_RELEASE(factory_); }
|
||||
~OwnedFactoryAndThreads() {
|
||||
CHECK_RELEASE(factory_);
|
||||
if (network_monitor_factory_ != nullptr) {
|
||||
rtc::NetworkMonitorFactory::ReleaseFactory(network_monitor_factory_);
|
||||
}
|
||||
}
|
||||
|
||||
PeerConnectionFactoryInterface* factory() { return factory_; }
|
||||
WebRtcVideoEncoderFactory* encoder_factory() { return encoder_factory_; }
|
||||
WebRtcVideoDecoderFactory* decoder_factory() { return decoder_factory_; }
|
||||
rtc::NetworkMonitorFactory* network_monitor_factory() {
|
||||
return network_monitor_factory_;
|
||||
}
|
||||
void clear_network_monitor_factory() { network_monitor_factory_ = nullptr; }
|
||||
void InvokeJavaCallbacksOnFactoryThreads();
|
||||
|
||||
private:
|
||||
@ -1084,6 +1098,7 @@ class OwnedFactoryAndThreads {
|
||||
const scoped_ptr<Thread> signaling_thread_;
|
||||
WebRtcVideoEncoderFactory* encoder_factory_;
|
||||
WebRtcVideoDecoderFactory* decoder_factory_;
|
||||
rtc::NetworkMonitorFactory* network_monitor_factory_;
|
||||
PeerConnectionFactoryInterface* factory_; // Const after ctor except dtor.
|
||||
};
|
||||
|
||||
@ -1132,11 +1147,15 @@ JOW(jlong, PeerConnectionFactory_nativeCreatePeerConnectionFactory)(
|
||||
<< "Failed to start threads";
|
||||
WebRtcVideoEncoderFactory* encoder_factory = nullptr;
|
||||
WebRtcVideoDecoderFactory* decoder_factory = nullptr;
|
||||
rtc::NetworkMonitorFactory* network_monitor_factory = nullptr;
|
||||
|
||||
#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
|
||||
if (video_hw_acceleration_enabled) {
|
||||
encoder_factory = new MediaCodecVideoEncoderFactory();
|
||||
decoder_factory = new MediaCodecVideoDecoderFactory();
|
||||
}
|
||||
network_monitor_factory = new AndroidNetworkMonitorFactory();
|
||||
rtc::NetworkMonitorFactory::SetFactory(network_monitor_factory);
|
||||
#endif
|
||||
rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
|
||||
webrtc::CreatePeerConnectionFactory(worker_thread,
|
||||
@ -1149,7 +1168,7 @@ JOW(jlong, PeerConnectionFactory_nativeCreatePeerConnectionFactory)(
|
||||
OwnedFactoryAndThreads* owned_factory = new OwnedFactoryAndThreads(
|
||||
worker_thread, signaling_thread,
|
||||
encoder_factory, decoder_factory,
|
||||
factory.release());
|
||||
network_monitor_factory, factory.release());
|
||||
owned_factory->InvokeJavaCallbacksOnFactoryThreads();
|
||||
return jlongFromPointer(owned_factory);
|
||||
}
|
||||
@ -1247,13 +1266,29 @@ JOW(void, PeerConnectionFactory_nativeSetOptions)(
|
||||
bool disable_encryption =
|
||||
jni->GetBooleanField(options, disable_encryption_field);
|
||||
|
||||
jfieldID disable_network_monitor_field =
|
||||
jni->GetFieldID(options_class, "disableNetworkMonitor", "Z");
|
||||
bool disable_network_monitor =
|
||||
jni->GetBooleanField(options, disable_network_monitor_field);
|
||||
|
||||
PeerConnectionFactoryInterface::Options options_to_set;
|
||||
|
||||
// This doesn't necessarily match the c++ version of this struct; feel free
|
||||
// to add more parameters as necessary.
|
||||
options_to_set.network_ignore_mask = network_ignore_mask;
|
||||
options_to_set.disable_encryption = disable_encryption;
|
||||
options_to_set.disable_network_monitor = disable_network_monitor;
|
||||
factory->SetOptions(options_to_set);
|
||||
|
||||
if (disable_network_monitor) {
|
||||
OwnedFactoryAndThreads* owner =
|
||||
reinterpret_cast<OwnedFactoryAndThreads*>(native_factory);
|
||||
if (owner->network_monitor_factory()) {
|
||||
rtc::NetworkMonitorFactory::ReleaseFactory(
|
||||
owner->network_monitor_factory());
|
||||
owner->clear_network_monitor_factory();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JOW(void, PeerConnectionFactory_nativeSetVideoHwAccelerationOptions)(
|
||||
|
@ -55,6 +55,7 @@ public class PeerConnectionFactory {
|
||||
|
||||
public int networkIgnoreMask;
|
||||
public boolean disableEncryption;
|
||||
public boolean disableNetworkMonitor;
|
||||
}
|
||||
|
||||
// |context| is an android.content.Context object, but we keep it untyped here
|
||||
|
@ -541,11 +541,13 @@ class PeerConnectionFactoryInterface : public rtc::RefCountInterface {
|
||||
Options() :
|
||||
disable_encryption(false),
|
||||
disable_sctp_data_channels(false),
|
||||
disable_network_monitor(false),
|
||||
network_ignore_mask(rtc::kDefaultNetworkIgnoreMask),
|
||||
ssl_max_version(rtc::SSL_PROTOCOL_DTLS_10) {
|
||||
}
|
||||
bool disable_encryption;
|
||||
bool disable_sctp_data_channels;
|
||||
bool disable_network_monitor;
|
||||
|
||||
// Sets the network types to ignore. For instance, calling this with
|
||||
// ADAPTER_TYPE_ETHERNET | ADAPTER_TYPE_LOOPBACK will ignore Ethernet and
|
||||
|
@ -104,6 +104,8 @@
|
||||
'app/webrtc/java/jni/androidmediadecoder_jni.h',
|
||||
'app/webrtc/java/jni/androidmediaencoder_jni.cc',
|
||||
'app/webrtc/java/jni/androidmediaencoder_jni.h',
|
||||
'app/webrtc/java/jni/androidnetworkmonitor_jni.cc',
|
||||
'app/webrtc/java/jni/androidnetworkmonitor_jni.h',
|
||||
'app/webrtc/java/jni/surfacetexturehelper_jni.cc',
|
||||
'app/webrtc/java/jni/surfacetexturehelper_jni.h',
|
||||
]
|
||||
@ -156,6 +158,8 @@
|
||||
'app/webrtc/java/android/org/webrtc/GlShader.java',
|
||||
'app/webrtc/java/android/org/webrtc/GlUtil.java',
|
||||
'app/webrtc/java/android/org/webrtc/GlTextureFrameBuffer.java',
|
||||
'app/webrtc/java/android/org/webrtc/NetworkMonitor.java',
|
||||
'app/webrtc/java/android/org/webrtc/NetworkMonitorAutoDetect.java',
|
||||
'app/webrtc/java/android/org/webrtc/RendererCommon.java',
|
||||
'app/webrtc/java/android/org/webrtc/SurfaceTextureHelper.java',
|
||||
'app/webrtc/java/android/org/webrtc/SurfaceViewRenderer.java',
|
||||
|
@ -237,6 +237,8 @@ static_library("rtc_base") {
|
||||
"nethelpers.h",
|
||||
"network.cc",
|
||||
"network.h",
|
||||
"networkmonitor.cc",
|
||||
"networkmonitor.h",
|
||||
"nullsocketserver.h",
|
||||
"pathutils.cc",
|
||||
"pathutils.h",
|
||||
|
@ -219,6 +219,8 @@
|
||||
'nethelpers.h',
|
||||
'network.cc',
|
||||
'network.h',
|
||||
'networkmonitor.cc',
|
||||
'networkmonitor.h',
|
||||
'nullsocketserver.h',
|
||||
'openssl.h',
|
||||
'openssladapter.cc',
|
||||
|
@ -48,6 +48,7 @@
|
||||
#include <algorithm>
|
||||
|
||||
#include "webrtc/base/logging.h"
|
||||
#include "webrtc/base/networkmonitor.h"
|
||||
#include "webrtc/base/scoped_ptr.h"
|
||||
#include "webrtc/base/socket.h" // includes something that makes windows happy
|
||||
#include "webrtc/base/stream.h"
|
||||
@ -329,6 +330,11 @@ BasicNetworkManager::BasicNetworkManager()
|
||||
BasicNetworkManager::~BasicNetworkManager() {
|
||||
}
|
||||
|
||||
void BasicNetworkManager::OnNetworksChanged() {
|
||||
LOG(LS_VERBOSE) << "Network change was observed at the network manager";
|
||||
UpdateNetworksOnce();
|
||||
}
|
||||
|
||||
#if defined(__native_client__)
|
||||
|
||||
bool BasicNetworkManager::CreateNetworks(bool include_ignored,
|
||||
@ -663,6 +669,7 @@ void BasicNetworkManager::StartUpdating() {
|
||||
thread_->Post(this, kSignalNetworksMessage);
|
||||
} else {
|
||||
thread_->Post(this, kUpdateNetworksMessage);
|
||||
StartNetworkMonitor();
|
||||
}
|
||||
++start_count_;
|
||||
}
|
||||
@ -676,13 +683,36 @@ void BasicNetworkManager::StopUpdating() {
|
||||
if (!start_count_) {
|
||||
thread_->Clear(this);
|
||||
sent_first_update_ = false;
|
||||
StopNetworkMonitor();
|
||||
}
|
||||
}
|
||||
|
||||
void BasicNetworkManager::StartNetworkMonitor() {
|
||||
NetworkMonitorFactory* factory = NetworkMonitorFactory::GetFactory();
|
||||
if (factory == nullptr) {
|
||||
return;
|
||||
}
|
||||
network_monitor_.reset(factory->CreateNetworkMonitor());
|
||||
if (!network_monitor_) {
|
||||
return;
|
||||
}
|
||||
network_monitor_->SignalNetworksChanged.connect(
|
||||
this, &BasicNetworkManager::OnNetworksChanged);
|
||||
network_monitor_->Start();
|
||||
}
|
||||
|
||||
void BasicNetworkManager::StopNetworkMonitor() {
|
||||
if (!network_monitor_) {
|
||||
return;
|
||||
}
|
||||
network_monitor_->Stop();
|
||||
network_monitor_.reset();
|
||||
}
|
||||
|
||||
void BasicNetworkManager::OnMessage(Message* msg) {
|
||||
switch (msg->message_id) {
|
||||
case kUpdateNetworksMessage: {
|
||||
DoUpdateNetworks();
|
||||
case kUpdateNetworksMessage: {
|
||||
UpdateNetworksContinually();
|
||||
break;
|
||||
}
|
||||
case kSignalNetworksMessage: {
|
||||
@ -694,7 +724,7 @@ void BasicNetworkManager::OnMessage(Message* msg) {
|
||||
}
|
||||
}
|
||||
|
||||
void BasicNetworkManager::DoUpdateNetworks() {
|
||||
void BasicNetworkManager::UpdateNetworksOnce() {
|
||||
if (!start_count_)
|
||||
return;
|
||||
|
||||
@ -711,7 +741,10 @@ void BasicNetworkManager::DoUpdateNetworks() {
|
||||
sent_first_update_ = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BasicNetworkManager::UpdateNetworksContinually() {
|
||||
UpdateNetworksOnce();
|
||||
thread_->PostDelayed(kNetworksUpdateIntervalMs, this, kUpdateNetworksMessage);
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,7 @@ struct ifaddrs;
|
||||
namespace rtc {
|
||||
|
||||
class Network;
|
||||
class NetworkMonitorInterface;
|
||||
class Thread;
|
||||
|
||||
enum AdapterType {
|
||||
@ -147,7 +148,6 @@ class NetworkManagerBase : public NetworkManager {
|
||||
|
||||
private:
|
||||
friend class NetworkTest;
|
||||
void DoUpdateNetworks();
|
||||
|
||||
EnumerationPermission enumeration_permission_;
|
||||
|
||||
@ -164,7 +164,8 @@ class NetworkManagerBase : public NetworkManager {
|
||||
// Basic implementation of the NetworkManager interface that gets list
|
||||
// of networks using OS APIs.
|
||||
class BasicNetworkManager : public NetworkManagerBase,
|
||||
public MessageHandler {
|
||||
public MessageHandler,
|
||||
public sigslot::has_slots<> {
|
||||
public:
|
||||
BasicNetworkManager();
|
||||
~BasicNetworkManager() override;
|
||||
@ -222,7 +223,17 @@ class BasicNetworkManager : public NetworkManagerBase,
|
||||
private:
|
||||
friend class NetworkTest;
|
||||
|
||||
void DoUpdateNetworks();
|
||||
// Creates a network monitor and listens for network updates.
|
||||
void StartNetworkMonitor();
|
||||
// Stops and removes the network monitor.
|
||||
void StopNetworkMonitor();
|
||||
// Called when it receives updates from the network monitor.
|
||||
void OnNetworksChanged();
|
||||
|
||||
// Updates the networks and reschedules the next update.
|
||||
void UpdateNetworksContinually();
|
||||
// Only updates the networks; does not reschedule the next update.
|
||||
void UpdateNetworksOnce();
|
||||
|
||||
Thread* thread_;
|
||||
bool sent_first_update_;
|
||||
@ -230,6 +241,7 @@ class BasicNetworkManager : public NetworkManagerBase,
|
||||
std::vector<std::string> network_ignore_list_;
|
||||
int network_ignore_mask_;
|
||||
bool ignore_non_default_routes_;
|
||||
scoped_ptr<NetworkMonitorInterface> network_monitor_;
|
||||
};
|
||||
|
||||
// Represents a Unix-type network interface, with a name and single address.
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
#include "webrtc/base/network.h"
|
||||
|
||||
#include "webrtc/base/networkmonitor.h"
|
||||
#include <vector>
|
||||
#if defined(WEBRTC_POSIX)
|
||||
#include <sys/types.h>
|
||||
@ -26,6 +27,20 @@
|
||||
|
||||
namespace rtc {
|
||||
|
||||
class FakeNetworkMonitor : public NetworkMonitorBase {
|
||||
public:
|
||||
void Start() override {}
|
||||
void Stop() override {}
|
||||
};
|
||||
|
||||
class FakeNetworkMonitorFactory : public NetworkMonitorFactory {
|
||||
public:
|
||||
FakeNetworkMonitorFactory() {}
|
||||
NetworkMonitorInterface* CreateNetworkMonitor() {
|
||||
return new FakeNetworkMonitor();
|
||||
}
|
||||
};
|
||||
|
||||
class NetworkTest : public testing::Test, public sigslot::has_slots<> {
|
||||
public:
|
||||
NetworkTest() : callback_called_(false) {}
|
||||
@ -55,6 +70,18 @@ class NetworkTest : public testing::Test, public sigslot::has_slots<> {
|
||||
return list;
|
||||
}
|
||||
|
||||
NetworkMonitorInterface* GetNetworkMonitor(
|
||||
BasicNetworkManager& network_manager) {
|
||||
return network_manager.network_monitor_.get();
|
||||
}
|
||||
void ClearNetworks(BasicNetworkManager& network_manager) {
|
||||
for (const auto& kv : network_manager.networks_map_) {
|
||||
delete kv.second;
|
||||
}
|
||||
network_manager.networks_.clear();
|
||||
network_manager.networks_map_.clear();
|
||||
}
|
||||
|
||||
#if defined(WEBRTC_POSIX)
|
||||
// Separated from CreateNetworks for tests.
|
||||
static void CallConvertIfAddrs(const BasicNetworkManager& network_manager,
|
||||
@ -790,4 +817,29 @@ TEST_F(NetworkTest, TestIPv6Selection) {
|
||||
EXPECT_EQ(ipv6_network.GetBestIP(), static_cast<IPAddress>(ip));
|
||||
}
|
||||
|
||||
TEST_F(NetworkTest, TestNetworkMonitoring) {
|
||||
BasicNetworkManager manager;
|
||||
manager.SignalNetworksChanged.connect(static_cast<NetworkTest*>(this),
|
||||
&NetworkTest::OnNetworksChanged);
|
||||
FakeNetworkMonitorFactory* factory = new FakeNetworkMonitorFactory();
|
||||
NetworkMonitorFactory::SetFactory(factory);
|
||||
manager.StartUpdating();
|
||||
NetworkMonitorInterface* network_monitor = GetNetworkMonitor(manager);
|
||||
EXPECT_TRUE_WAIT(callback_called_, 1000);
|
||||
callback_called_ = false;
|
||||
|
||||
// Clear the networks so that there will be network changes below.
|
||||
ClearNetworks(manager);
|
||||
// Network manager is started, so the callback is called when the network
|
||||
// monitor fires the network-change event.
|
||||
network_monitor->OnNetworksChanged();
|
||||
EXPECT_TRUE_WAIT(callback_called_, 1000);
|
||||
|
||||
// Network manager is stopped; the network monitor is removed.
|
||||
manager.StopUpdating();
|
||||
EXPECT_TRUE(GetNetworkMonitor(manager) == nullptr);
|
||||
|
||||
NetworkMonitorFactory::ReleaseFactory(factory);
|
||||
}
|
||||
|
||||
} // namespace rtc
|
||||
|
62
webrtc/base/networkmonitor.cc
Normal file
62
webrtc/base/networkmonitor.cc
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2015 The WebRTC Project Authors. All rights reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/base/networkmonitor.h"
|
||||
|
||||
#include "webrtc/base/common.h"
|
||||
|
||||
namespace {
|
||||
const uint32_t UPDATE_NETWORKS_MESSAGE = 1;
|
||||
|
||||
// This is set by NetworkMonitorFactory::SetFactory and the caller of
|
||||
// NetworkMonitorFactory::SetFactory must be responsible for calling
|
||||
// ReleaseFactory to destroy the factory.
|
||||
rtc::NetworkMonitorFactory* network_monitor_factory = nullptr;
|
||||
} // namespace
|
||||
|
||||
namespace rtc {
|
||||
NetworkMonitorInterface::NetworkMonitorInterface() {}
|
||||
|
||||
NetworkMonitorInterface::~NetworkMonitorInterface() {}
|
||||
|
||||
NetworkMonitorBase::NetworkMonitorBase() : thread_(Thread::Current()) {}
|
||||
NetworkMonitorBase::~NetworkMonitorBase() {}
|
||||
|
||||
void NetworkMonitorBase::OnNetworksChanged() {
|
||||
LOG(LS_VERBOSE) << "Network change is received at the network monitor";
|
||||
thread_->Post(this, UPDATE_NETWORKS_MESSAGE);
|
||||
}
|
||||
|
||||
void NetworkMonitorBase::OnMessage(Message* msg) {
|
||||
ASSERT(msg->message_id == UPDATE_NETWORKS_MESSAGE);
|
||||
SignalNetworksChanged();
|
||||
}
|
||||
|
||||
NetworkMonitorFactory::NetworkMonitorFactory() {}
|
||||
NetworkMonitorFactory::~NetworkMonitorFactory() {}
|
||||
|
||||
void NetworkMonitorFactory::SetFactory(NetworkMonitorFactory* factory) {
|
||||
if (network_monitor_factory != nullptr) {
|
||||
delete network_monitor_factory;
|
||||
}
|
||||
network_monitor_factory = factory;
|
||||
}
|
||||
|
||||
void NetworkMonitorFactory::ReleaseFactory(NetworkMonitorFactory* factory) {
|
||||
if (factory == network_monitor_factory) {
|
||||
SetFactory(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
NetworkMonitorFactory* NetworkMonitorFactory::GetFactory() {
|
||||
return network_monitor_factory;
|
||||
}
|
||||
|
||||
} // namespace rtc
|
91
webrtc/base/networkmonitor.h
Normal file
91
webrtc/base/networkmonitor.h
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright 2015 The WebRTC Project Authors. All rights reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_BASE_NETWORKMONITOR_H_
|
||||
#define WEBRTC_BASE_NETWORKMONITOR_H_
|
||||
|
||||
#include "webrtc/base/logging.h"
|
||||
#include "webrtc/base/scoped_ptr.h"
|
||||
#include "webrtc/base/sigslot.h"
|
||||
#include "webrtc/base/thread.h"
|
||||
|
||||
namespace rtc {
|
||||
/*
|
||||
* Receives network-change events via |OnNetworksChanged| and signals the
|
||||
* networks changed event.
|
||||
*
|
||||
* Threading consideration:
|
||||
* It is expected that all upstream operations (from native to Java) are
|
||||
* performed from the worker thread. This includes creating, starting and
|
||||
* stopping the monitor. This avoids the potential race condition when creating
|
||||
* the singleton Java NetworkMonitor class. Downstream operations can be from
|
||||
* any thread, but this class will forward all the downstream operations onto
|
||||
* the worker thread.
|
||||
*
|
||||
* Memory consideration:
|
||||
* NetworkMonitor is owned by the caller (NetworkManager). The global network
|
||||
* monitor factory is owned by the factory itself but needs to be released from
|
||||
* the factory creator.
|
||||
*/
|
||||
// Generic network monitor interface. It starts and stops monitoring network
|
||||
// changes, and fires the SignalNetworksChanged event when networks change.
|
||||
class NetworkMonitorInterface {
|
||||
public:
|
||||
NetworkMonitorInterface();
|
||||
virtual ~NetworkMonitorInterface();
|
||||
|
||||
sigslot::signal0<> SignalNetworksChanged;
|
||||
|
||||
virtual void Start() = 0;
|
||||
virtual void Stop() = 0;
|
||||
|
||||
// Implementations should call this method on the base when networks change,
|
||||
// and the base will fire SignalNetworksChanged on the right thread.
|
||||
virtual void OnNetworksChanged() = 0;
|
||||
};
|
||||
|
||||
class NetworkMonitorBase : public NetworkMonitorInterface,
|
||||
public MessageHandler,
|
||||
public sigslot::has_slots<> {
|
||||
public:
|
||||
NetworkMonitorBase();
|
||||
~NetworkMonitorBase() override;
|
||||
|
||||
void OnNetworksChanged() override;
|
||||
|
||||
void OnMessage(Message* msg) override;
|
||||
|
||||
private:
|
||||
Thread* thread_;
|
||||
};
|
||||
|
||||
/*
|
||||
* NetworkMonitorFactory creates NetworkMonitors.
|
||||
*/
|
||||
class NetworkMonitorFactory {
|
||||
public:
|
||||
// This is not thread-safe; it should be called once (or once per audio/video
|
||||
// call) during the call initialization.
|
||||
static void SetFactory(NetworkMonitorFactory* factory);
|
||||
|
||||
static void ReleaseFactory(NetworkMonitorFactory* factory);
|
||||
static NetworkMonitorFactory* GetFactory();
|
||||
|
||||
virtual NetworkMonitorInterface* CreateNetworkMonitor() = 0;
|
||||
|
||||
virtual ~NetworkMonitorFactory();
|
||||
|
||||
protected:
|
||||
NetworkMonitorFactory();
|
||||
};
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
#endif // WEBRTC_BASE_NETWORKMONITOR_H_
|
@ -14,6 +14,7 @@
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
|
||||
<application android:label="@string/app_name"
|
||||
android:icon="@drawable/ic_launcher"
|
||||
|
@ -236,6 +236,7 @@ public class PeerConnectionClientTest extends InstrumentationTestCase
|
||||
PeerConnectionClient client = PeerConnectionClient.getInstance();
|
||||
PeerConnectionFactory.Options options = new PeerConnectionFactory.Options();
|
||||
options.networkIgnoreMask = 0;
|
||||
options.disableNetworkMonitor = true;
|
||||
client.setPeerConnectionFactoryOptions(options);
|
||||
client.createPeerConnectionFactory(
|
||||
getInstrumentation().getContext(), peerConnectionParameters, this);
|
||||
|
Reference in New Issue
Block a user