summaryrefslogtreecommitdiffstats
path: root/net/android
diff options
context:
space:
mode:
authorpliard@chromium.org <pliard@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-01-04 12:34:34 +0000
committerpliard@chromium.org <pliard@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-01-04 12:34:34 +0000
commit18eab2d146b6d158992fa6ddc6a266a2a5264c81 (patch)
tree8af2175525100b4eba14d47fa0d5361012be048b /net/android
parent697f88738e456b0eb4291c297095a72f40bdb7b4 (diff)
downloadchromium_src-18eab2d146b6d158992fa6ddc6a266a2a5264c81.zip
chromium_src-18eab2d146b6d158992fa6ddc6a266a2a5264c81.tar.gz
chromium_src-18eab2d146b6d158992fa6ddc6a266a2a5264c81.tar.bz2
Provide NetworkChangeNotifierAndroid with the actual initial connection type.
The Android NetworkChangeNotifier is initialized with connection_type = CONNECTION_UNKNOWN. This means that the result returned by NetworkChangeNotifier::IsOffline() is inaccurate until the first network change happens. This can happen for the whole initialization path if the user starts Chrome after he explicitly disabled WiFi and 3G. This CL updates NetworkChangeNotifier.java to support multiple native observers. This can happen in case NetworkChangeNotifierDelegateAndroid is instantiated multiple times (e.g. when multiple factories are instantiated). Still on the Java side, NetworkChangeNotifier.java was also changed to fetch the actual connection type as soon as the auto-detector (interacting with the Android platform) is enabled. On the native side, NetworkChangeNotifierDelegateAndroid now fetches at construction time the current connection type from the Java side singleton through a direct JNI function call (possible since the delegate is constructed on the JNI thread). NetworkChangeNotifierAndroid::GetCurrentConnectionType() is now a simple wrapper around the delegate's GetCurrentConnectionType() method (which is thread-safe). BUG=166883 Review URL: https://codereview.chromium.org/11628008 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@175138 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/android')
-rw-r--r--net/android/java/src/org/chromium/net/NetworkChangeNotifier.java107
-rw-r--r--net/android/java/src/org/chromium/net/NetworkChangeNotifierAutoDetect.java36
-rw-r--r--net/android/javatests/src/org/chromium/net/NetworkChangeNotifierTest.java12
-rw-r--r--net/android/network_change_notifier_android.cc14
-rw-r--r--net/android/network_change_notifier_android.h8
-rw-r--r--net/android/network_change_notifier_android_unittest.cc145
-rw-r--r--net/android/network_change_notifier_delegate_android.cc66
-rw-r--r--net/android/network_change_notifier_delegate_android.h22
8 files changed, 232 insertions, 178 deletions
diff --git a/net/android/java/src/org/chromium/net/NetworkChangeNotifier.java b/net/android/java/src/org/chromium/net/NetworkChangeNotifier.java
index a2deed7..5710e83 100644
--- a/net/android/java/src/org/chromium/net/NetworkChangeNotifier.java
+++ b/net/android/java/src/org/chromium/net/NetworkChangeNotifier.java
@@ -10,16 +10,18 @@ import org.chromium.base.CalledByNative;
import org.chromium.base.JNINamespace;
import org.chromium.base.NativeClassQualifiedName;
+import java.util.ArrayList;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* Triggers updates to the underlying network state in Chrome.
- * By default, connectivity is assumed and changes must pushed from
- * the embedder via the forceConnectivityState function.
- * Embedders may choose to have this class auto-detect changes in
- * network connectivity by invoking the autoDetectConnectivityState
- * function.
- * This class is not thread-safe.
+ *
+ * By default, connectivity is assumed and changes must pushed from the embedder via the
+ * forceConnectivityState function.
+ * Embedders may choose to have this class auto-detect changes in network connectivity by invoking
+ * the setAutoDetectConnectivityState function.
+ *
+ * WARNING: This class is not thread-safe.
*/
@JNINamespace("net")
public class NetworkChangeNotifier {
@@ -41,48 +43,59 @@ public class NetworkChangeNotifier {
public static final int CONNECTION_NONE = 6;
private final Context mContext;
- private int mNativeChangeNotifier;
+ private final ArrayList<Integer> mNativeChangeNotifiers;
private final CopyOnWriteArrayList<ConnectionTypeObserver> mConnectionTypeObservers;
private NetworkChangeNotifierAutoDetect mAutoDetector;
+ private int mCurrentConnectionType = CONNECTION_UNKNOWN;
private static NetworkChangeNotifier sInstance;
- private NetworkChangeNotifier(Context context, int nativeChangeNotifier) {
+ private NetworkChangeNotifier(Context context) {
mContext = context;
- mNativeChangeNotifier = nativeChangeNotifier;
+ mNativeChangeNotifiers = new ArrayList<Integer>();
mConnectionTypeObservers = new CopyOnWriteArrayList<ConnectionTypeObserver>();
}
- private void destroy() {
- if (mAutoDetector != null) {
- mAutoDetector.destroy();
+ /**
+ * Initializes the singleton once.
+ */
+ @CalledByNative
+ public static NetworkChangeNotifier init(Context context) {
+ if (sInstance == null) {
+ sInstance = new NetworkChangeNotifier(context);
}
- mNativeChangeNotifier = 0;
- mConnectionTypeObservers.clear();
+ return sInstance;
+ }
+
+ static void resetInstanceForTests(Context context) {
+ sInstance = new NetworkChangeNotifier(context);
+ }
+
+ @CalledByNative
+ public int getCurrentConnectionType() {
+ return mCurrentConnectionType;
}
/**
- * Creates the singleton used by the native-side NetworkChangeNotifier.
+ * Adds a native-side observer.
*/
@CalledByNative
- static NetworkChangeNotifier createInstance(Context context, int nativeChangeNotifier) {
- assert sInstance == null;
- sInstance = new NetworkChangeNotifier(context, nativeChangeNotifier);
- return sInstance;
+ public void addNativeObserver(int nativeChangeNotifier) {
+ mNativeChangeNotifiers.add(nativeChangeNotifier);
}
/**
- * Destroys the singleton used by the native-side NetworkChangeNotifier.
+ * Removes a native-side observer.
*/
@CalledByNative
- private static void destroyInstance() {
- assert sInstance != null;
- sInstance.destroy();
- sInstance = null;
+ public void removeNativeObserver(int nativeChangeNotifier) {
+ // Please keep the cast performing the boxing below. It ensures that the right method
+ // overload is used. ArrayList<T> has both remove(int index) and remove(T element).
+ mNativeChangeNotifiers.remove((Integer) nativeChangeNotifier);
}
/**
- * Returns the instance used by the native-side NetworkChangeNotifier.
+ * Returns the singleton instance.
*/
public static NetworkChangeNotifier getInstance() {
assert sInstance != null;
@@ -90,16 +103,14 @@ public class NetworkChangeNotifier {
}
/**
- * Enable 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.
+ * 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 NetworkChangeNotifier should listen
- * for system changes in network connectivity.
+ * @param shouldAutoDetect true if the NetworkChangeNotifier should listen for system changes in
+ * network connectivity.
*/
public static void setAutoDetectConnectivityState(boolean shouldAutoDetect) {
- // We should only get a call to this after the native object is created and
- // hence the singleton initialised.
getInstance().setAutoDetectConnectivityStateInternal(shouldAutoDetect);
}
@@ -117,10 +128,11 @@ public class NetworkChangeNotifier {
new NetworkChangeNotifierAutoDetect.Observer() {
@Override
public void onConnectionTypeChanged(int newConnectionType) {
- notifyObserversOfConnectionTypeChange(newConnectionType);
+ updateCurrentConnectionType(newConnectionType);
}
},
mContext);
+ mCurrentConnectionType = mAutoDetector.getCurrentConnectionType();
}
} else {
destroyAutoDetector();
@@ -128,11 +140,10 @@ public class NetworkChangeNotifier {
}
/**
- * Update the perceived network state when not auto-detecting
- * changes to connectivity.
+ * Updates the perceived network state when not auto-detecting changes to connectivity.
*
- * @param networkAvailable True if the NetworkChangeNotifier should
- * perceive a "connected" state, false implies "disconnected".
+ * @param networkAvailable True if the NetworkChangeNotifier should perceive a "connected"
+ * state, false implies "disconnected".
*/
@CalledByNative
public static void forceConnectivityState(boolean networkAvailable) {
@@ -141,25 +152,24 @@ public class NetworkChangeNotifier {
}
private void forceConnectivityStateInternal(boolean forceOnline) {
- if (mNativeChangeNotifier == 0) {
- return;
- }
- boolean connectionCurrentlyExists =
- nativeGetConnectionType(mNativeChangeNotifier) != CONNECTION_NONE;
+ boolean connectionCurrentlyExists = mCurrentConnectionType != CONNECTION_NONE;
if (connectionCurrentlyExists != forceOnline) {
- notifyObserversOfConnectionTypeChange(
- forceOnline ? CONNECTION_UNKNOWN : CONNECTION_NONE);
+ updateCurrentConnectionType(forceOnline ? CONNECTION_UNKNOWN : CONNECTION_NONE);
}
}
+ private void updateCurrentConnectionType(int newConnectionType) {
+ mCurrentConnectionType = newConnectionType;
+ notifyObserversOfConnectionTypeChange(newConnectionType);
+ }
+
/**
* Alerts all observers of a connection change.
*/
void notifyObserversOfConnectionTypeChange(int newConnectionType) {
- if (mNativeChangeNotifier != 0) {
- nativeNotifyConnectionTypeChanged(mNativeChangeNotifier, newConnectionType);
+ for (Integer nativeChangeNotifier : mNativeChangeNotifiers) {
+ nativeNotifyConnectionTypeChanged(nativeChangeNotifier, newConnectionType);
}
-
for (ConnectionTypeObserver observer : mConnectionTypeObservers) {
observer.onConnectionTypeChanged(newConnectionType);
}
@@ -173,8 +183,9 @@ public class NetworkChangeNotifier {
}
private void addConnectionTypeObserverInternal(ConnectionTypeObserver observer) {
- if (!mConnectionTypeObservers.contains(observer))
+ if (!mConnectionTypeObservers.contains(observer)) {
mConnectionTypeObservers.add(observer);
+ }
}
/**
diff --git a/net/android/java/src/org/chromium/net/NetworkChangeNotifierAutoDetect.java b/net/android/java/src/org/chromium/net/NetworkChangeNotifierAutoDetect.java
index 90aa753..8d953f2 100644
--- a/net/android/java/src/org/chromium/net/NetworkChangeNotifierAutoDetect.java
+++ b/net/android/java/src/org/chromium/net/NetworkChangeNotifierAutoDetect.java
@@ -25,18 +25,25 @@ public class NetworkChangeNotifierAutoDetect extends BroadcastReceiver
/** Queries the ConnectivityManager for information about the current connection. */
static class ConnectivityManagerDelegate {
- private ConnectivityManager mConnectivityManager;
+ private final ConnectivityManager mConnectivityManager;
ConnectivityManagerDelegate(Context context) {
- if (context != null) {
- mConnectivityManager = (ConnectivityManager)
- context.getSystemService(Context.CONNECTIVITY_SERVICE);
- }
+ mConnectivityManager =
+ (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
+ }
+
+ // For testing.
+ ConnectivityManagerDelegate() {
+ // All the methods below should be overridden.
+ mConnectivityManager = null;
}
boolean activeNetworkExists() {
- return mConnectivityManager != null &&
- mConnectivityManager.getActiveNetworkInfo() != null;
+ return mConnectivityManager.getActiveNetworkInfo() != null;
+ }
+
+ boolean isConnected() {
+ return mConnectivityManager.getActiveNetworkInfo().isConnected();
}
int getNetworkType() {
@@ -71,10 +78,10 @@ public class NetworkChangeNotifierAutoDetect extends BroadcastReceiver
mObserver = observer;
mContext = context;
mConnectivityManagerDelegate = new ConnectivityManagerDelegate(context);
- mConnectionType = currentConnectionType(context);
+ mConnectionType = getCurrentConnectionType();
if (ActivityStatus.getState() != ActivityStatus.PAUSED) {
- registerReceiver();
+ registerReceiver();
}
ActivityStatus.registerStateListener(this);
}
@@ -110,9 +117,10 @@ public class NetworkChangeNotifierAutoDetect extends BroadcastReceiver
}
}
- private int currentConnectionType(Context context) {
+ public int getCurrentConnectionType() {
// Track exactly what type of connection we have.
- if (!mConnectivityManagerDelegate.activeNetworkExists()) {
+ if (!mConnectivityManagerDelegate.activeNetworkExists() ||
+ !mConnectivityManagerDelegate.isConnected()) {
return NetworkChangeNotifier.CONNECTION_NONE;
}
@@ -155,11 +163,7 @@ public class NetworkChangeNotifierAutoDetect extends BroadcastReceiver
// BroadcastReceiver
@Override
public void onReceive(Context context, Intent intent) {
- boolean noConnection =
- intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
- int newConnectionType = noConnection ?
- NetworkChangeNotifier.CONNECTION_NONE : currentConnectionType(context);
-
+ int newConnectionType = getCurrentConnectionType();
if (newConnectionType != mConnectionType) {
mConnectionType = newConnectionType;
Log.d(TAG, "Network connectivity changed, type is: " + mConnectionType);
diff --git a/net/android/javatests/src/org/chromium/net/NetworkChangeNotifierTest.java b/net/android/javatests/src/org/chromium/net/NetworkChangeNotifierTest.java
index 9bc6332..0bea726 100644
--- a/net/android/javatests/src/org/chromium/net/NetworkChangeNotifierTest.java
+++ b/net/android/javatests/src/org/chromium/net/NetworkChangeNotifierTest.java
@@ -40,15 +40,16 @@ public class NetworkChangeNotifierTest extends InstrumentationTestCase {
private int mNetworkType;
private int mNetworkSubtype;
- MockConnectivityManagerDelegate() {
- super(null);
- }
-
@Override
boolean activeNetworkExists() {
return mActiveNetworkExists;
}
+ @Override
+ boolean isConnected() {
+ return getNetworkType() != NetworkChangeNotifier.CONNECTION_NONE;
+ }
+
void setActiveNetworkExists(boolean networkExists) {
mActiveNetworkExists = networkExists;
}
@@ -82,7 +83,7 @@ public class NetworkChangeNotifierTest extends InstrumentationTestCase {
public void testNetworkChangeNotifierJavaObservers() throws InterruptedException {
// Create a new notifier that doesn't have a native-side counterpart.
Context context = getInstrumentation().getTargetContext();
- NetworkChangeNotifier.createInstance(context, 0);
+ NetworkChangeNotifier.resetInstanceForTests(context);
NetworkChangeNotifier.setAutoDetectConnectivityState(true);
NetworkChangeNotifierAutoDetect receiver = NetworkChangeNotifier.getAutoDetectorForTest();
@@ -109,7 +110,6 @@ public class NetworkChangeNotifierTest extends InstrumentationTestCase {
connectivityDelegate.setActiveNetworkExists(false);
connectivityDelegate.setNetworkType(NetworkChangeNotifier.CONNECTION_NONE);
Intent noConnectivityIntent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
- noConnectivityIntent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
receiver.onReceive(getInstrumentation().getTargetContext(), noConnectivityIntent);
assertTrue(observer.hasReceivedNotification());
}
diff --git a/net/android/network_change_notifier_android.cc b/net/android/network_change_notifier_android.cc
index 6dce669..d4e1a5c 100644
--- a/net/android/network_change_notifier_android.cc
+++ b/net/android/network_change_notifier_android.cc
@@ -67,13 +67,10 @@ NetworkChangeNotifierAndroid::~NetworkChangeNotifierAndroid() {
NetworkChangeNotifier::ConnectionType
NetworkChangeNotifierAndroid::GetCurrentConnectionType() const {
- base::AutoLock auto_lock(connection_type_lock_);
- return connection_type_;
+ return delegate_->GetCurrentConnectionType();
}
-void NetworkChangeNotifierAndroid::OnConnectionTypeChanged(
- ConnectionType new_connection_type) {
- SetConnectionType(new_connection_type);
+void NetworkChangeNotifierAndroid::OnConnectionTypeChanged() {
NetworkChangeNotifier::NotifyObserversOfIPAddressChange();
NetworkChangeNotifier::NotifyObserversOfConnectionTypeChange();
}
@@ -87,7 +84,6 @@ NetworkChangeNotifierAndroid::NetworkChangeNotifierAndroid(
NetworkChangeNotifierDelegateAndroid* delegate)
: NetworkChangeNotifier(NetworkChangeCalculatorParamsAndroid()),
delegate_(delegate) {
- SetConnectionType(NetworkChangeNotifier::CONNECTION_UNKNOWN);
delegate_->AddObserver(this);
}
@@ -105,10 +101,4 @@ NetworkChangeNotifierAndroid::NetworkChangeCalculatorParamsAndroid() {
return params;
}
-void NetworkChangeNotifierAndroid::SetConnectionType(
- ConnectionType new_connection_type) {
- base::AutoLock auto_lock(connection_type_lock_);
- connection_type_ = new_connection_type;
-}
-
} // namespace net
diff --git a/net/android/network_change_notifier_android.h b/net/android/network_change_notifier_android.h
index 4f6180f..f167cfc 100644
--- a/net/android/network_change_notifier_android.h
+++ b/net/android/network_change_notifier_android.h
@@ -8,7 +8,6 @@
#include "base/android/jni_android.h"
#include "base/basictypes.h"
#include "base/compiler_specific.h"
-#include "base/synchronization/lock.h"
#include "net/android/network_change_notifier_delegate_android.h"
#include "net/base/network_change_notifier.h"
@@ -49,8 +48,7 @@ class NET_EXPORT_PRIVATE NetworkChangeNotifierAndroid
virtual ConnectionType GetCurrentConnectionType() const OVERRIDE;
// NetworkChangeNotifierDelegateAndroid::Observer:
- virtual void OnConnectionTypeChanged(
- ConnectionType new_connection_type) OVERRIDE;
+ virtual void OnConnectionTypeChanged() OVERRIDE;
static bool Register(JNIEnv* env);
@@ -61,13 +59,9 @@ class NET_EXPORT_PRIVATE NetworkChangeNotifierAndroid
explicit NetworkChangeNotifierAndroid(
NetworkChangeNotifierDelegateAndroid* delegate);
- void SetConnectionType(ConnectionType new_connection_type);
-
static NetworkChangeCalculatorParams NetworkChangeCalculatorParamsAndroid();
NetworkChangeNotifierDelegateAndroid* const delegate_;
- mutable base::Lock connection_type_lock_; // Protects the state below.
- ConnectionType connection_type_;
DISALLOW_COPY_AND_ASSIGN(NetworkChangeNotifierAndroid);
};
diff --git a/net/android/network_change_notifier_android_unittest.cc b/net/android/network_change_notifier_android_unittest.cc
index b66d647..7fb8e6b 100644
--- a/net/android/network_change_notifier_android_unittest.cc
+++ b/net/android/network_change_notifier_android_unittest.cc
@@ -18,37 +18,41 @@ namespace net {
namespace {
-// Template used to generate both the NetworkChangeNotifierDelegateAndroid and
-// NetworkChangeNotifier::ConnectionTypeObserver implementations which have the
-// same interface.
-template <typename BaseObserver>
-class ObserverImpl : public BaseObserver {
+class NetworkChangeNotifierDelegateAndroidObserver
+ : public NetworkChangeNotifierDelegateAndroid::Observer {
public:
- ObserverImpl()
- : times_connection_type_changed_(0),
- current_connection_(NetworkChangeNotifier::CONNECTION_UNKNOWN) {
+ NetworkChangeNotifierDelegateAndroidObserver() : notifications_count_(0) {}
+
+ // NetworkChangeNotifierDelegateAndroid::Observer:
+ virtual void OnConnectionTypeChanged() OVERRIDE {
+ notifications_count_++;
}
- // BaseObserver:
- virtual void OnConnectionTypeChanged(
- NetworkChangeNotifier::ConnectionType type) OVERRIDE {
- times_connection_type_changed_++;
- current_connection_ = type;
+ int notifications_count() const {
+ return notifications_count_;
}
- int times_connection_type_changed() const {
- return times_connection_type_changed_;
+ private:
+ int notifications_count_;
+};
+
+class NetworkChangeNotifierObserver
+ : public NetworkChangeNotifier::ConnectionTypeObserver {
+ public:
+ NetworkChangeNotifierObserver() : notifications_count_(0) {}
+
+ // NetworkChangeNotifier::Observer:
+ virtual void OnConnectionTypeChanged(
+ NetworkChangeNotifier::ConnectionType connection_type) OVERRIDE {
+ notifications_count_++;
}
- NetworkChangeNotifier::ConnectionType current_connection() const {
- return current_connection_;
+ int notifications_count() const {
+ return notifications_count_;
}
private:
- int times_connection_type_changed_;
- NetworkChangeNotifier::ConnectionType current_connection_;
-
- DISALLOW_COPY_AND_ASSIGN(ObserverImpl);
+ int notifications_count_;
};
} // namespace
@@ -60,44 +64,78 @@ class BaseNetworkChangeNotifierAndroidTest : public testing::Test {
virtual ~BaseNetworkChangeNotifierAndroidTest() {}
void RunTest(
- const base::Callback<int(void)>& times_connection_type_changed_callback,
+ const base::Callback<int(void)>& notifications_count_getter,
const base::Callback<ConnectionType(void)>& connection_type_getter) {
- EXPECT_EQ(0, times_connection_type_changed_callback.Run());
+ EXPECT_EQ(0, notifications_count_getter.Run());
EXPECT_EQ(NetworkChangeNotifier::CONNECTION_UNKNOWN,
connection_type_getter.Run());
- ForceConnectivityState(NetworkChangeNotifierDelegateAndroid::OFFLINE);
- EXPECT_EQ(1, times_connection_type_changed_callback.Run());
+ // Changing from online to offline should trigger a notification.
+ SetOffline();
+ EXPECT_EQ(1, notifications_count_getter.Run());
EXPECT_EQ(NetworkChangeNotifier::CONNECTION_NONE,
connection_type_getter.Run());
- ForceConnectivityState(NetworkChangeNotifierDelegateAndroid::OFFLINE);
- EXPECT_EQ(1, times_connection_type_changed_callback.Run());
+ // No notification should be triggered when the offline state hasn't
+ // changed.
+ SetOffline();
+ EXPECT_EQ(1, notifications_count_getter.Run());
EXPECT_EQ(NetworkChangeNotifier::CONNECTION_NONE,
connection_type_getter.Run());
- ForceConnectivityState(NetworkChangeNotifierDelegateAndroid::ONLINE);
- EXPECT_EQ(2, times_connection_type_changed_callback.Run());
+ // Going from offline to online should trigger a notification.
+ SetOnline();
+ EXPECT_EQ(2, notifications_count_getter.Run());
EXPECT_EQ(NetworkChangeNotifier::CONNECTION_UNKNOWN,
connection_type_getter.Run());
}
- void ForceConnectivityState(
- NetworkChangeNotifierDelegateAndroid::ConnectivityState state) {
- delegate_.ForceConnectivityState(state);
+ void SetOnline() {
+ delegate_.SetOnline();
// Note that this is needed because ObserverListThreadSafe uses PostTask().
MessageLoop::current()->RunUntilIdle();
}
+ void SetOffline() {
+ delegate_.SetOffline();
+ // See comment above.
+ MessageLoop::current()->RunUntilIdle();
+ }
+
NetworkChangeNotifierDelegateAndroid delegate_;
};
+// Tests that NetworkChangeNotifierDelegateAndroid is initialized with the
+// actual connection type rather than a hardcoded one (e.g.
+// CONNECTION_UNKNOWN). Initializing the connection type to CONNECTION_UNKNOWN
+// and relying on the first network change notification to set it correctly can
+// be problematic in case there is a long delay between the delegate's
+// construction and the notification.
+TEST_F(BaseNetworkChangeNotifierAndroidTest,
+ DelegateIsInitializedWithCurrentConnectionType) {
+ SetOffline();
+ ASSERT_EQ(NetworkChangeNotifier::CONNECTION_NONE,
+ delegate_.GetCurrentConnectionType());
+ // Instantiate another delegate to validate that it uses the actual
+ // connection type at construction.
+ scoped_ptr<NetworkChangeNotifierDelegateAndroid> other_delegate(
+ new NetworkChangeNotifierDelegateAndroid());
+ EXPECT_EQ(NetworkChangeNotifier::CONNECTION_NONE,
+ other_delegate->GetCurrentConnectionType());
+
+ // Toggle the global connectivity state and instantiate another delegate
+ // again.
+ SetOnline();
+ ASSERT_EQ(NetworkChangeNotifier::CONNECTION_UNKNOWN,
+ delegate_.GetCurrentConnectionType());
+ other_delegate.reset(new NetworkChangeNotifierDelegateAndroid());
+ EXPECT_EQ(NetworkChangeNotifier::CONNECTION_UNKNOWN,
+ other_delegate->GetCurrentConnectionType());
+}
+
class NetworkChangeNotifierDelegateAndroidTest
: public BaseNetworkChangeNotifierAndroidTest {
protected:
- typedef ObserverImpl<
- NetworkChangeNotifierDelegateAndroid::Observer> TestDelegateObserver;
-
NetworkChangeNotifierDelegateAndroidTest() {
delegate_.AddObserver(&delegate_observer_);
delegate_.AddObserver(&other_delegate_observer_);
@@ -108,8 +146,8 @@ class NetworkChangeNotifierDelegateAndroidTest
delegate_.RemoveObserver(&other_delegate_observer_);
}
- TestDelegateObserver delegate_observer_;
- TestDelegateObserver other_delegate_observer_;
+ NetworkChangeNotifierDelegateAndroidObserver delegate_observer_;
+ NetworkChangeNotifierDelegateAndroidObserver other_delegate_observer_;
};
// Tests that the NetworkChangeNotifierDelegateAndroid's observers are notified.
@@ -119,25 +157,20 @@ TEST_F(NetworkChangeNotifierDelegateAndroidTest, DelegateObserverNotified) {
// Test the logic with a single observer.
RunTest(
base::Bind(
- &TestDelegateObserver::times_connection_type_changed,
+ &NetworkChangeNotifierDelegateAndroidObserver::notifications_count,
base::Unretained(&delegate_observer_)),
base::Bind(
- &TestDelegateObserver::current_connection,
- base::Unretained(&delegate_observer_)));
+ &NetworkChangeNotifierDelegateAndroid::GetCurrentConnectionType,
+ base::Unretained(&delegate_)));
// Check that *all* the observers are notified. Both observers should have the
// same state.
- EXPECT_EQ(delegate_observer_.times_connection_type_changed(),
- other_delegate_observer_.times_connection_type_changed());
- EXPECT_EQ(delegate_observer_.current_connection(),
- other_delegate_observer_.current_connection());
+ EXPECT_EQ(delegate_observer_.notifications_count(),
+ other_delegate_observer_.notifications_count());
}
class NetworkChangeNotifierAndroidTest
: public BaseNetworkChangeNotifierAndroidTest {
protected:
- typedef ObserverImpl<
- NetworkChangeNotifier::ConnectionTypeObserver> TestConnectionTypeObserver;
-
NetworkChangeNotifierAndroidTest() : notifier_(&delegate_) {
NetworkChangeNotifier::AddConnectionTypeObserver(
&connection_type_observer_);
@@ -145,8 +178,8 @@ class NetworkChangeNotifierAndroidTest
&other_connection_type_observer_);
}
- TestConnectionTypeObserver connection_type_observer_;
- TestConnectionTypeObserver other_connection_type_observer_;
+ NetworkChangeNotifierObserver connection_type_observer_;
+ NetworkChangeNotifierObserver other_connection_type_observer_;
NetworkChangeNotifier::DisableForTest disable_for_test_;
NetworkChangeNotifierAndroid notifier_;
};
@@ -159,7 +192,7 @@ TEST_F(NetworkChangeNotifierAndroidTest,
NotificationsSentToNetworkChangeNotifierAndroid) {
RunTest(
base::Bind(
- &TestConnectionTypeObserver::times_connection_type_changed,
+ &NetworkChangeNotifierObserver::notifications_count,
base::Unretained(&connection_type_observer_)),
base::Bind(
&NetworkChangeNotifierAndroid::GetCurrentConnectionType,
@@ -172,16 +205,12 @@ TEST_F(NetworkChangeNotifierAndroidTest,
NotificationsSentToClientsOfNetworkChangeNotifier) {
RunTest(
base::Bind(
- &TestConnectionTypeObserver::times_connection_type_changed,
+ &NetworkChangeNotifierObserver::notifications_count,
base::Unretained(&connection_type_observer_)),
- base::Bind(
- &TestConnectionTypeObserver::current_connection,
- base::Unretained(&connection_type_observer_)));
+ base::Bind(&NetworkChangeNotifier::GetConnectionType));
// Check that *all* the observers are notified.
- EXPECT_EQ(connection_type_observer_.times_connection_type_changed(),
- other_connection_type_observer_.times_connection_type_changed());
- EXPECT_EQ(connection_type_observer_.current_connection(),
- other_connection_type_observer_.current_connection());
+ EXPECT_EQ(connection_type_observer_.notifications_count(),
+ other_connection_type_observer_.notifications_count());
}
} // namespace net
diff --git a/net/android/network_change_notifier_delegate_android.cc b/net/android/network_change_notifier_delegate_android.cc
index 91b0cb0..0031260 100644
--- a/net/android/network_change_notifier_delegate_android.cc
+++ b/net/android/network_change_notifier_delegate_android.cc
@@ -11,8 +11,10 @@ namespace net {
namespace {
-// Returns whether the provided connection type is known.
-bool CheckConnectionType(int connection_type) {
+// Converts a Java side connection type (integer) to
+// the native side NetworkChangeNotifier::ConnectionType.
+NetworkChangeNotifier::ConnectionType ConvertConnectionType(
+ jint connection_type) {
switch (connection_type) {
case NetworkChangeNotifier::CONNECTION_UNKNOWN:
case NetworkChangeNotifier::CONNECTION_ETHERNET:
@@ -21,29 +23,42 @@ bool CheckConnectionType(int connection_type) {
case NetworkChangeNotifier::CONNECTION_3G:
case NetworkChangeNotifier::CONNECTION_4G:
case NetworkChangeNotifier::CONNECTION_NONE:
- return true;
+ break;
default:
NOTREACHED() << "Unknown connection type received: " << connection_type;
- return false;
+ return NetworkChangeNotifier::CONNECTION_UNKNOWN;
}
+ return static_cast<NetworkChangeNotifier::ConnectionType>(connection_type);
}
} // namespace
NetworkChangeNotifierDelegateAndroid::NetworkChangeNotifierDelegateAndroid()
: observers_(new ObserverListThreadSafe<Observer>()) {
+ JNIEnv* env = base::android::AttachCurrentThread();
java_network_change_notifier_.Reset(
- Java_NetworkChangeNotifier_createInstance(
- base::android::AttachCurrentThread(),
- base::android::GetApplicationContext(),
- reinterpret_cast<jint>(this)));
+ Java_NetworkChangeNotifier_init(
+ env, base::android::GetApplicationContext()));
+ Java_NetworkChangeNotifier_addNativeObserver(
+ env, java_network_change_notifier_.obj(), reinterpret_cast<jint>(this));
+ SetCurrentConnectionType(
+ ConvertConnectionType(
+ Java_NetworkChangeNotifier_getCurrentConnectionType(
+ env, java_network_change_notifier_.obj())));
}
NetworkChangeNotifierDelegateAndroid::~NetworkChangeNotifierDelegateAndroid() {
DCHECK(thread_checker_.CalledOnValidThread());
observers_->AssertEmpty();
JNIEnv* env = base::android::AttachCurrentThread();
- Java_NetworkChangeNotifier_destroyInstance(env);
+ Java_NetworkChangeNotifier_removeNativeObserver(
+ env, java_network_change_notifier_.obj(), reinterpret_cast<jint>(this));
+}
+
+NetworkChangeNotifier::ConnectionType
+NetworkChangeNotifierDelegateAndroid::GetCurrentConnectionType() const {
+ base::AutoLock auto_lock(connection_type_lock_);
+ return connection_type_;
}
void NetworkChangeNotifierDelegateAndroid::NotifyConnectionTypeChanged(
@@ -51,16 +66,16 @@ void NetworkChangeNotifierDelegateAndroid::NotifyConnectionTypeChanged(
jobject obj,
jint new_connection_type) {
DCHECK(thread_checker_.CalledOnValidThread());
- connection_type_ = CheckConnectionType(new_connection_type) ?
- static_cast<ConnectionType>(new_connection_type) :
- NetworkChangeNotifier::CONNECTION_UNKNOWN;
- observers_->Notify(&Observer::OnConnectionTypeChanged, connection_type_);
+ const ConnectionType actual_connection_type = ConvertConnectionType(
+ new_connection_type);
+ SetCurrentConnectionType(actual_connection_type);
+ observers_->Notify(&Observer::OnConnectionTypeChanged);
}
jint NetworkChangeNotifierDelegateAndroid::GetConnectionType(JNIEnv*,
jobject) const {
DCHECK(thread_checker_.CalledOnValidThread());
- return connection_type_;
+ return GetCurrentConnectionType();
}
void NetworkChangeNotifierDelegateAndroid::AddObserver(
@@ -73,16 +88,25 @@ void NetworkChangeNotifierDelegateAndroid::RemoveObserver(
observers_->RemoveObserver(observer);
}
-void NetworkChangeNotifierDelegateAndroid::ForceConnectivityState(
- ConnectivityState state) {
- DCHECK(thread_checker_.CalledOnValidThread());
- JNIEnv* env = base::android::AttachCurrentThread();
- Java_NetworkChangeNotifier_forceConnectivityState(env, state == ONLINE);
-}
-
// static
bool NetworkChangeNotifierDelegateAndroid::Register(JNIEnv* env) {
return RegisterNativesImpl(env);
}
+void NetworkChangeNotifierDelegateAndroid::SetCurrentConnectionType(
+ ConnectionType new_connection_type) {
+ base::AutoLock auto_lock(connection_type_lock_);
+ connection_type_ = new_connection_type;
+}
+
+void NetworkChangeNotifierDelegateAndroid::SetOnline() {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ Java_NetworkChangeNotifier_forceConnectivityState(env, true);
+}
+
+void NetworkChangeNotifierDelegateAndroid::SetOffline() {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ Java_NetworkChangeNotifier_forceConnectivityState(env, false);
+}
+
} // namespace net
diff --git a/net/android/network_change_notifier_delegate_android.h b/net/android/network_change_notifier_delegate_android.h
index 9f5caa4..f93c30b 100644
--- a/net/android/network_change_notifier_delegate_android.h
+++ b/net/android/network_change_notifier_delegate_android.h
@@ -9,6 +9,7 @@
#include "base/basictypes.h"
#include "base/memory/ref_counted.h"
#include "base/observer_list_threadsafe.h"
+#include "base/synchronization/lock.h"
#include "base/threading/thread_checker.h"
#include "net/base/network_change_notifier.h"
@@ -21,10 +22,7 @@ namespace net {
// unless otherwise stated (e.g. AddObserver()/RemoveObserver()).
class NET_EXPORT_PRIVATE NetworkChangeNotifierDelegateAndroid {
public:
- enum ConnectivityState {
- OFFLINE,
- ONLINE,
- };
+ typedef NetworkChangeNotifier::ConnectionType ConnectionType;
// Observer interface implemented by NetworkChangeNotifierAndroid which
// subscribes to network change notifications fired by the delegate (and
@@ -34,8 +32,7 @@ class NET_EXPORT_PRIVATE NetworkChangeNotifierDelegateAndroid {
virtual ~Observer() {}
// Updates the current connection type.
- virtual void OnConnectionTypeChanged(
- NetworkChangeNotifier::ConnectionType new_connection_type) = 0;
+ virtual void OnConnectionTypeChanged() = 0;
};
NetworkChangeNotifierDelegateAndroid();
@@ -55,21 +52,26 @@ class NET_EXPORT_PRIVATE NetworkChangeNotifierDelegateAndroid {
void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
- // Exposed for testing.
- void ForceConnectivityState(ConnectivityState state);
+ // Can be called from any thread.
+ ConnectionType GetCurrentConnectionType() const;
// Initializes JNI bindings.
static bool Register(JNIEnv* env);
private:
- friend class NetworkChangeNotifierDelegateAndroidTest;
+ friend class BaseNetworkChangeNotifierAndroidTest;
- typedef NetworkChangeNotifier::ConnectionType ConnectionType;
+ void SetCurrentConnectionType(ConnectionType connection_type);
+
+ // Methods calling the Java side exposed for testing.
+ void SetOnline();
+ void SetOffline();
base::ThreadChecker thread_checker_;
scoped_refptr<ObserverListThreadSafe<Observer> > observers_;
scoped_refptr<base::SingleThreadTaskRunner> jni_task_runner_;
base::android::ScopedJavaGlobalRef<jobject> java_network_change_notifier_;
+ mutable base::Lock connection_type_lock_; // Protects the state below.
ConnectionType connection_type_;
DISALLOW_COPY_AND_ASSIGN(NetworkChangeNotifierDelegateAndroid);