[Connectivity] Adds platform interface to connectivity plugin (#2515)
diff --git a/packages/connectivity/connectivity_platform_interface/CHANGELOG.md b/packages/connectivity/connectivity_platform_interface/CHANGELOG.md
new file mode 100644
index 0000000..0d8803f
--- /dev/null
+++ b/packages/connectivity/connectivity_platform_interface/CHANGELOG.md
@@ -0,0 +1,3 @@
+## 1.0.0
+
+* Initial release.
diff --git a/packages/connectivity/connectivity_platform_interface/LICENSE b/packages/connectivity/connectivity_platform_interface/LICENSE
new file mode 100644
index 0000000..0c91662
--- /dev/null
+++ b/packages/connectivity/connectivity_platform_interface/LICENSE
@@ -0,0 +1,27 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * 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.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "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 COPYRIGHT
+// OWNER OR CONTRIBUTORS 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.
diff --git a/packages/connectivity/connectivity_platform_interface/README.md b/packages/connectivity/connectivity_platform_interface/README.md
new file mode 100644
index 0000000..ae3be49
--- /dev/null
+++ b/packages/connectivity/connectivity_platform_interface/README.md
@@ -0,0 +1,26 @@
+# connectivity_platform_interface
+
+A common platform interface for the [`connectivity`][1] plugin.
+
+This interface allows platform-specific implementations of the `connectivity`
+plugin, as well as the plugin itself, to ensure they are supporting the
+same interface.
+
+# Usage
+
+To implement a new platform-specific implementation of `connectivity`, extend
+[`ConnectivityPlatform`][2] with an implementation that performs the
+platform-specific behavior, and when you register your plugin, set the default
+`ConnectivityPlatform` by calling
+`ConnectivityPlatform.instance = MyPlatformConnectivity()`.
+
+# Note on breaking changes
+
+Strongly prefer non-breaking changes (such as adding a method to the interface)
+over breaking changes for this package.
+
+See https://flutter.dev/go/platform-interface-breaking-changes for a discussion
+on why a less-clean interface is preferable to a breaking change.
+
+[1]: ../connectivity
+[2]: lib/connectivity_platform_interface.dart
diff --git a/packages/connectivity/connectivity_platform_interface/lib/connectivity_platform_interface.dart b/packages/connectivity/connectivity_platform_interface/lib/connectivity_platform_interface.dart
new file mode 100644
index 0000000..b1beb30
--- /dev/null
+++ b/packages/connectivity/connectivity_platform_interface/lib/connectivity_platform_interface.dart
@@ -0,0 +1,72 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:plugin_platform_interface/plugin_platform_interface.dart';
+
+import 'method_channel_connectivity.dart';
+
+/// The interface that implementations of connectivity must implement.
+///
+/// Platform implementations should extend this class rather than implement it as `Connectivity`
+/// does not consider newly added methods to be breaking changes. Extending this class
+/// (using `extends`) ensures that the subclass will get the default implementation, while
+/// platform implementations that `implements` this interface will be broken by newly added
+/// [ConnectivityPlatform] methods.
+abstract class ConnectivityPlatform extends PlatformInterface {
+ /// Constructs a ConnectivityPlatform.
+ ConnectivityPlatform() : super(token: _token);
+
+ static final Object _token = Object();
+
+ static ConnectivityPlatform _instance = MethodChannelConnectivity();
+
+ /// The default instance of [ConnectivityPlatform] to use.
+ ///
+ /// Defaults to [MethodChannelConnectivity].
+ static ConnectivityPlatform get instance => _instance;
+
+ /// Platform-specific plugins should set this with their own platform-specific
+ /// class that extends [ConnectivityPlatform] when they register themselves.
+ // TODO(amirh): Extract common platform interface logic.
+ // https://github.com/flutter/flutter/issues/43368
+ static set instance(ConnectivityPlatform instance) {
+ PlatformInterface.verifyToken(instance, _token);
+ _instance = instance;
+ }
+
+ /// Checks the connection status of the device.
+ Future<String> checkConnectivity() {
+ throw UnimplementedError('checkConnectivity() has not been implemented.');
+ }
+
+ /// Obtains the wifi name (SSID) of the connected network
+ Future<String> getWifiName() {
+ throw UnimplementedError('getWifiName() has not been implemented.');
+ }
+
+ /// Obtains the wifi BSSID of the connected network.
+ Future<String> getWifiBSSID() {
+ throw UnimplementedError('getWifiBSSID() has not been implemented.');
+ }
+
+ /// Obtains the IP address of the connected wifi network
+ Future<String> getWifiIP() {
+ throw UnimplementedError('getWifiIP() has not been implemented.');
+ }
+
+ /// Request to authorize the location service (Only on iOS).
+ Future<String> requestLocationServiceAuthorization(
+ {bool requestAlwaysLocationUsage = false}) {
+ throw UnimplementedError(
+ 'requestLocationServiceAuthorization() has not been implemented.');
+ }
+
+ /// Get the current location service authorization (Only on iOS).
+ Future<String> getLocationServiceAuthorization() {
+ throw UnimplementedError(
+ 'getLocationServiceAuthorization() has not been implemented.');
+ }
+}
diff --git a/packages/connectivity/connectivity_platform_interface/lib/method_channel_connectivity.dart b/packages/connectivity/connectivity_platform_interface/lib/method_channel_connectivity.dart
new file mode 100644
index 0000000..0d35b02
--- /dev/null
+++ b/packages/connectivity/connectivity_platform_interface/lib/method_channel_connectivity.dart
@@ -0,0 +1,55 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:flutter/services.dart';
+import 'package:meta/meta.dart';
+
+import 'connectivity_platform_interface.dart';
+
+/// The method channel used to interact with the native platform.
+@visibleForTesting
+const MethodChannel method_channel =
+ MethodChannel('plugins.flutter.io/connectivity');
+
+/// An implementation of [ConnectivityPlatform] that uses method channels.
+class MethodChannelConnectivity extends ConnectivityPlatform {
+ @override
+ Future<String> checkConnectivity() async {
+ final String result = await method_channel.invokeMethod<String>('check');
+ return result;
+ }
+
+ @override
+ Future<String> getWifiName() async {
+ return method_channel.invokeMethod<String>('wifiName');
+ }
+
+ @override
+ Future<String> getWifiBSSID() async {
+ return await method_channel.invokeMethod<String>('wifiBSSID');
+ }
+
+ @override
+ Future<String> getWifiIP() async {
+ return await method_channel.invokeMethod<String>('wifiIPAddress');
+ }
+
+ @override
+ Future<String> requestLocationServiceAuthorization(
+ {bool requestAlwaysLocationUsage = false}) async {
+ final String result = await method_channel.invokeMethod<String>(
+ 'requestLocationServiceAuthorization',
+ <bool>[requestAlwaysLocationUsage]);
+ return result;
+ }
+
+ @override
+ Future<String> getLocationServiceAuthorization() async {
+ final String result = await method_channel
+ .invokeMethod<String>('getLocationServiceAuthorization');
+ return result;
+ }
+}
diff --git a/packages/connectivity/connectivity_platform_interface/pubspec.yaml b/packages/connectivity/connectivity_platform_interface/pubspec.yaml
new file mode 100644
index 0000000..f8f63ec
--- /dev/null
+++ b/packages/connectivity/connectivity_platform_interface/pubspec.yaml
@@ -0,0 +1,21 @@
+name: connectivity_platform_interface
+description: A common platform interface for the connectivity plugin.
+homepage: https://github.com/flutter/plugins/tree/master/packages/connectivity/connectivity_platform_interface
+# NOTE: We strongly prefer non-breaking changes, even at the expense of a
+# less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes
+version: 1.0.0
+
+dependencies:
+ flutter:
+ sdk: flutter
+ meta: ^1.0.5
+ plugin_platform_interface: ^1.0.1
+
+dev_dependencies:
+ flutter_test:
+ sdk: flutter
+ mockito: ^4.1.1
+
+environment:
+ sdk: ">=2.0.0-dev.28.0 <3.0.0"
+ flutter: ">=1.10.0 <2.0.0"
diff --git a/packages/connectivity/connectivity_platform_interface/test/method_channel_connectivity_test.dart b/packages/connectivity/connectivity_platform_interface/test/method_channel_connectivity_test.dart
new file mode 100644
index 0000000..d8d9d5b
--- /dev/null
+++ b/packages/connectivity/connectivity_platform_interface/test/method_channel_connectivity_test.dart
@@ -0,0 +1,130 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:mockito/mockito.dart';
+import 'package:flutter/services.dart';
+import 'package:flutter_test/flutter_test.dart';
+import 'package:plugin_platform_interface/plugin_platform_interface.dart';
+
+import 'package:connectivity_platform_interface/method_channel_connectivity.dart';
+import 'package:connectivity_platform_interface/connectivity_platform_interface.dart';
+
+void main() {
+ TestWidgetsFlutterBinding.ensureInitialized();
+
+ group('$ConnectivityPlatform', () {
+ test('$MethodChannelConnectivity() is the default instance', () {
+ expect(ConnectivityPlatform.instance,
+ isInstanceOf<MethodChannelConnectivity>());
+ });
+
+ test('Cannot be implemented with `implements`', () {
+ expect(() {
+ ConnectivityPlatform.instance = ImplementsConnectivityPlatform();
+ }, throwsA(isInstanceOf<AssertionError>()));
+ });
+
+ test('Can be mocked with `implements`', () {
+ final ConnectivityPlatformMock mock = ConnectivityPlatformMock();
+ ConnectivityPlatform.instance = mock;
+ });
+
+ test('Can be extended', () {
+ ConnectivityPlatform.instance = ExtendsConnectivityPlatform();
+ });
+ });
+
+ group('$MethodChannelConnectivity', () {
+ const MethodChannel channel =
+ MethodChannel('plugins.flutter.io/connectivity');
+ final List<MethodCall> log = <MethodCall>[];
+ channel.setMockMethodCallHandler((MethodCall methodCall) async {
+ log.add(methodCall);
+ });
+
+ final MethodChannelConnectivity connectivity = MethodChannelConnectivity();
+
+ tearDown(() {
+ log.clear();
+ });
+
+ test('checkConnectivity', () async {
+ await connectivity.checkConnectivity();
+ expect(
+ log,
+ <Matcher>[isMethodCall('check', arguments: null)],
+ );
+ });
+
+ test('getWifiName', () async {
+ await connectivity.getWifiName();
+ expect(
+ log,
+ <Matcher>[isMethodCall('wifiName', arguments: null)],
+ );
+ });
+
+ test('getWifiBSSID', () async {
+ await connectivity.getWifiBSSID();
+ expect(
+ log,
+ <Matcher>[isMethodCall('wifiBSSID', arguments: null)],
+ );
+ });
+
+ test('getWifiIP', () async {
+ await connectivity.getWifiIP();
+ expect(
+ log,
+ <Matcher>[isMethodCall('wifiIPAddress', arguments: null)],
+ );
+ });
+
+ test(
+ 'requestLocationServiceAuthorization requestLocationServiceAuthorization set to false (default)',
+ () async {
+ await connectivity.requestLocationServiceAuthorization();
+ expect(
+ log,
+ <Matcher>[
+ isMethodCall('requestLocationServiceAuthorization',
+ arguments: <bool>[false])
+ ],
+ );
+ });
+
+ test(
+ 'requestLocationServiceAuthorization requestLocationServiceAuthorization set to true',
+ () async {
+ await connectivity.requestLocationServiceAuthorization(
+ requestAlwaysLocationUsage: true);
+ expect(
+ log,
+ <Matcher>[
+ isMethodCall('requestLocationServiceAuthorization',
+ arguments: <bool>[true])
+ ],
+ );
+ });
+
+ test('getLocationServiceAuthorization', () async {
+ await connectivity.getLocationServiceAuthorization();
+ expect(
+ log,
+ <Matcher>[
+ isMethodCall('getLocationServiceAuthorization', arguments: null)
+ ],
+ );
+ });
+ });
+}
+
+class ConnectivityPlatformMock extends Mock
+ with MockPlatformInterfaceMixin
+ implements ConnectivityPlatform {}
+
+class ImplementsConnectivityPlatform extends Mock
+ implements ConnectivityPlatform {}
+
+class ExtendsConnectivityPlatform extends ConnectivityPlatform {}