From a18cf9329d331fe0574a232388a92fd01b82f918 Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Tue, 2 May 2023 12:25:55 -0500 Subject: [PATCH 1/7] import of connectivity_plus and massively reduced nm plugins --- lib/notification_manager.dart | 2 +- lib/third_party/connectivity_plus/LICENSE | 27 ++ .../connectivity_plus/LICENSE | 27 ++ .../connectivity_plus/README.md | 106 +++++ .../connectivity_plus/android/build.gradle | 41 ++ .../android/gradle.properties | 1 + .../gradle/wrapper/gradle-wrapper.properties | 5 + .../connectivity_plus/android/settings.gradle | 1 + .../android/src/main/AndroidManifest.xml | 4 + .../plus/connectivity/Connectivity.java | 83 ++++ .../ConnectivityBroadcastReceiver.java | 94 ++++ .../ConnectivityMethodChannelHandler.java | 37 ++ .../plus/connectivity/ConnectivityPlugin.java | 56 +++ .../connectivity_plus/ios/Assets/.gitkeep | 0 .../ios/Classes/ConnectivityPlusPlugin.h | 4 + .../ios/Classes/ConnectivityPlusPlugin.m | 15 + .../ios/Classes/ConnectivityProvider.swift | 21 + .../PathMonitorConnectivityProvider.swift | 60 +++ .../ReachabilityConnectivityProvider.swift | 59 +++ .../Classes/SwiftConnectivityPlusPlugin.swift | 89 ++++ .../ios/connectivity_plus.podspec | 24 ++ .../lib/connectivity_plus.dart | 55 +++ .../lib/src/connectivity_plus_linux.dart | 85 ++++ .../lib/src/connectivity_plus_web.dart | 27 ++ .../web/dart_html_connectivity_plugin.dart | 35 ++ ...k_information_api_connectivity_plugin.dart | 92 ++++ .../src/web/utils/connectivity_result.dart | 53 +++ .../macos/Classes/ConnectivityPlugin.swift | 90 ++++ .../macos/Classes/ConnectivityProvider.swift | 21 + .../PathMonitorConnectivityProvider.swift | 57 +++ .../ReachabilityConnectivityProvider.swift | 59 +++ .../macos/connectivity_plus.podspec | 22 + .../connectivity_plus/pubspec.yaml | 48 +++ .../connectivity_plus/windows/.gitignore | 17 + .../connectivity_plus/windows/CMakeLists.txt | 29 ++ .../windows/connectivity_plus_plugin.cpp | 171 ++++++++ .../connectivity_plus_windows_plugin.h | 23 + .../connectivity_plus/network_manager.h | 49 +++ .../windows/network_manager.cpp | 243 +++++++++++ .../.gitattributes | 25 ++ .../.gitignore | 46 ++ .../CHANGELOG.md | 94 ++++ .../LICENSE | 27 ++ .../README.md | 12 + .../connectivity_plus_platform_interface.dart | 51 +++ .../lib/method_channel_connectivity.dart | 43 ++ .../lib/src/enums.dart | 27 ++ .../lib/src/utils.dart | 22 + .../pubspec.yaml | 20 + lib/third_party/nm/LICENSE | 373 ++++++++++++++++ lib/third_party/nm/nm.dart | 1 + .../nm/src/network_manager_client.dart | 403 ++++++++++++++++++ 52 files changed, 3075 insertions(+), 1 deletion(-) create mode 100644 lib/third_party/connectivity_plus/LICENSE create mode 100644 lib/third_party/connectivity_plus/connectivity_plus/LICENSE create mode 100644 lib/third_party/connectivity_plus/connectivity_plus/README.md create mode 100644 lib/third_party/connectivity_plus/connectivity_plus/android/build.gradle create mode 100644 lib/third_party/connectivity_plus/connectivity_plus/android/gradle.properties create mode 100644 lib/third_party/connectivity_plus/connectivity_plus/android/gradle/wrapper/gradle-wrapper.properties create mode 100644 lib/third_party/connectivity_plus/connectivity_plus/android/settings.gradle create mode 100644 lib/third_party/connectivity_plus/connectivity_plus/android/src/main/AndroidManifest.xml create mode 100644 lib/third_party/connectivity_plus/connectivity_plus/android/src/main/java/dev/fluttercommunity/plus/connectivity/Connectivity.java create mode 100644 lib/third_party/connectivity_plus/connectivity_plus/android/src/main/java/dev/fluttercommunity/plus/connectivity/ConnectivityBroadcastReceiver.java create mode 100644 lib/third_party/connectivity_plus/connectivity_plus/android/src/main/java/dev/fluttercommunity/plus/connectivity/ConnectivityMethodChannelHandler.java create mode 100644 lib/third_party/connectivity_plus/connectivity_plus/android/src/main/java/dev/fluttercommunity/plus/connectivity/ConnectivityPlugin.java create mode 100644 lib/third_party/connectivity_plus/connectivity_plus/ios/Assets/.gitkeep create mode 100644 lib/third_party/connectivity_plus/connectivity_plus/ios/Classes/ConnectivityPlusPlugin.h create mode 100644 lib/third_party/connectivity_plus/connectivity_plus/ios/Classes/ConnectivityPlusPlugin.m create mode 100644 lib/third_party/connectivity_plus/connectivity_plus/ios/Classes/ConnectivityProvider.swift create mode 100644 lib/third_party/connectivity_plus/connectivity_plus/ios/Classes/PathMonitorConnectivityProvider.swift create mode 100644 lib/third_party/connectivity_plus/connectivity_plus/ios/Classes/ReachabilityConnectivityProvider.swift create mode 100644 lib/third_party/connectivity_plus/connectivity_plus/ios/Classes/SwiftConnectivityPlusPlugin.swift create mode 100644 lib/third_party/connectivity_plus/connectivity_plus/ios/connectivity_plus.podspec create mode 100644 lib/third_party/connectivity_plus/connectivity_plus/lib/connectivity_plus.dart create mode 100644 lib/third_party/connectivity_plus/connectivity_plus/lib/src/connectivity_plus_linux.dart create mode 100644 lib/third_party/connectivity_plus/connectivity_plus/lib/src/connectivity_plus_web.dart create mode 100644 lib/third_party/connectivity_plus/connectivity_plus/lib/src/web/dart_html_connectivity_plugin.dart create mode 100644 lib/third_party/connectivity_plus/connectivity_plus/lib/src/web/network_information_api_connectivity_plugin.dart create mode 100644 lib/third_party/connectivity_plus/connectivity_plus/lib/src/web/utils/connectivity_result.dart create mode 100644 lib/third_party/connectivity_plus/connectivity_plus/macos/Classes/ConnectivityPlugin.swift create mode 100644 lib/third_party/connectivity_plus/connectivity_plus/macos/Classes/ConnectivityProvider.swift create mode 100644 lib/third_party/connectivity_plus/connectivity_plus/macos/Classes/PathMonitorConnectivityProvider.swift create mode 100644 lib/third_party/connectivity_plus/connectivity_plus/macos/Classes/ReachabilityConnectivityProvider.swift create mode 100644 lib/third_party/connectivity_plus/connectivity_plus/macos/connectivity_plus.podspec create mode 100644 lib/third_party/connectivity_plus/connectivity_plus/pubspec.yaml create mode 100644 lib/third_party/connectivity_plus/connectivity_plus/windows/.gitignore create mode 100644 lib/third_party/connectivity_plus/connectivity_plus/windows/CMakeLists.txt create mode 100644 lib/third_party/connectivity_plus/connectivity_plus/windows/connectivity_plus_plugin.cpp create mode 100644 lib/third_party/connectivity_plus/connectivity_plus/windows/include/connectivity_plus/connectivity_plus_windows_plugin.h create mode 100644 lib/third_party/connectivity_plus/connectivity_plus/windows/include/connectivity_plus/network_manager.h create mode 100644 lib/third_party/connectivity_plus/connectivity_plus/windows/network_manager.cpp create mode 100644 lib/third_party/connectivity_plus/connectivity_plus_platform_interface/.gitattributes create mode 100644 lib/third_party/connectivity_plus/connectivity_plus_platform_interface/.gitignore create mode 100644 lib/third_party/connectivity_plus/connectivity_plus_platform_interface/CHANGELOG.md create mode 100644 lib/third_party/connectivity_plus/connectivity_plus_platform_interface/LICENSE create mode 100644 lib/third_party/connectivity_plus/connectivity_plus_platform_interface/README.md create mode 100644 lib/third_party/connectivity_plus/connectivity_plus_platform_interface/lib/connectivity_plus_platform_interface.dart create mode 100644 lib/third_party/connectivity_plus/connectivity_plus_platform_interface/lib/method_channel_connectivity.dart create mode 100644 lib/third_party/connectivity_plus/connectivity_plus_platform_interface/lib/src/enums.dart create mode 100644 lib/third_party/connectivity_plus/connectivity_plus_platform_interface/lib/src/utils.dart create mode 100644 lib/third_party/connectivity_plus/connectivity_plus_platform_interface/pubspec.yaml create mode 100644 lib/third_party/nm/LICENSE create mode 100644 lib/third_party/nm/nm.dart create mode 100644 lib/third_party/nm/src/network_manager_client.dart diff --git a/lib/notification_manager.dart b/lib/notification_manager.dart index 00042bcc..448204d2 100644 --- a/lib/notification_manager.dart +++ b/lib/notification_manager.dart @@ -14,7 +14,7 @@ import 'package:flutter_local_notifications_linux/src/model/icon.dart'; import 'package:path/path.dart' as path; -import 'config.dart'; +import '../../config.dart'; // NotificationsManager provides a wrapper around platform specific notifications logic. abstract class NotificationsManager { diff --git a/lib/third_party/connectivity_plus/LICENSE b/lib/third_party/connectivity_plus/LICENSE new file mode 100644 index 00000000..18c6ba27 --- /dev/null +++ b/lib/third_party/connectivity_plus/LICENSE @@ -0,0 +1,27 @@ +Copyright 2017 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. \ No newline at end of file diff --git a/lib/third_party/connectivity_plus/connectivity_plus/LICENSE b/lib/third_party/connectivity_plus/connectivity_plus/LICENSE new file mode 100644 index 00000000..7b995420 --- /dev/null +++ b/lib/third_party/connectivity_plus/connectivity_plus/LICENSE @@ -0,0 +1,27 @@ +Copyright 2017 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/lib/third_party/connectivity_plus/connectivity_plus/README.md b/lib/third_party/connectivity_plus/connectivity_plus/README.md new file mode 100644 index 00000000..8e5b2956 --- /dev/null +++ b/lib/third_party/connectivity_plus/connectivity_plus/README.md @@ -0,0 +1,106 @@ +# connectivity_plus + +[![Flutter Community: connectivity_plus](https://fluttercommunity.dev/_github/header/connectivity_plus)](https://github.com/fluttercommunity/community) + +[![pub package](https://img.shields.io/pub/v/connectivity_plus.svg)](https://pub.dev/packages/connectivity_plus) +[![pub points](https://img.shields.io/pub/points/connectivity_plus?color=2E8B57&label=pub%20points)](https://pub.dev/packages/connectivity_plus/score) +[![connectivity_plus](https://github.com/fluttercommunity/plus_plugins/actions/workflows/connectivity_plus.yaml/badge.svg)](https://github.com/fluttercommunity/plus_plugins/actions/workflows/connectivity_plus.yaml) + +

+

build
+

+ +This plugin allows Flutter apps to discover network connectivity and configure +themselves accordingly. It can distinguish between cellular vs WiFi connection. + +> **Note** +> +> On Android, this does not guarantee connection to Internet. For instance, the app might have wifi access but it might be a VPN or a hotel WiFi > with no access. + +## Platform Support + +| Android | iOS | MacOS | Web | Linux | Windows | +| :-----: | :-: | :---: | :-: | :---: | :-----: | +| ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | + +## Usage + +Sample usage to check current status: + +```dart +import 'package:connectivity_plus/connectivity_plus.dart'; + +final connectivityResult = await (Connectivity().checkConnectivity()); +if (connectivityResult == ConnectivityResult.mobile) { + // I am connected to a mobile network. +} else if (connectivityResult == ConnectivityResult.wifi) { + // I am connected to a wifi network. +} else if (connectivityResult == ConnectivityResult.ethernet) { + // I am connected to a ethernet network. +} else if (connectivityResult == ConnectivityResult.vpn) { + // I am connected to a vpn network. + // Note for iOS and macOS: + // There is no separate network interface type for [vpn]. + // It returns [other] on any device (also simulator) +} else if (connectivityResult == ConnectivityResult.bluetooth) { + // I am connected to a bluetooth. +} else if (connectivityResult == ConnectivityResult.other) { + // I am connected to a network which is not in the above mentioned networks. +} else if (connectivityResult == ConnectivityResult.none) { + // I am not connected to any network. +} +``` + +> **Note** +> +> You should not be using the current network status for deciding whether you can reliably make a network connection. Always guard your app code against timeouts and errors that might come from the network layer. + +You can also listen for network state changes by subscribing to the stream +exposed by connectivity plugin: + +```dart +import 'package:connectivity_plus/connectivity_plus.dart'; + +@override +initState() { + super.initState(); + + subscription = Connectivity().onConnectivityChanged.listen((ConnectivityResult result) { + // Got a new connectivity status! + }); +} + +// Be sure to cancel subscription after you are done +@override +dispose() { + subscription.cancel(); + super.dispose(); +} +``` + +> **Note** +> +> Connectivity changes are no longer communicated to Android apps in the background starting with Android O (8.0). _You should always check for connectivity status when your app is resumed._ The broadcast is only useful when your application is in the foreground. + +## Limitations on the web platform + +In order to retrieve information about the quality/speed of a browser's connection, the web implementation of the `connectivity` plugin uses the browser's [**NetworkInformation** Web API](https://developer.mozilla.org/en-US/docs/Web/API/NetworkInformation), which as of this writing (June 2020) is still "experimental", and not available in all browsers: + +![Data on support for the netinfo feature across the major browsers from caniuse.com](https://caniuse.bitsofco.de/image/netinfo.png) + +On desktop browsers, this API only returns a very broad set of connectivity statuses (One of `'slow-2g', '2g', '3g', or '4g'`), and may _not_ provide a Stream of changes. Firefox still hasn't enabled this feature by default. + +**Fallback to `navigator.onLine`** + +For those browsers where the NetworkInformation Web API is not available, the plugin falls back to the [**NavigatorOnLine** Web API](https://developer.mozilla.org/en-US/docs/Web/API/NavigatorOnLine), which is more broadly supported: + +![Data on support for the online-status feature across the major browsers from caniuse.com](https://caniuse.bitsofco.de/image/online-status.png) + +The NavigatorOnLine API is [provided by `dart:html`](https://api.dart.dev/stable/2.7.2/dart-html/Navigator/onLine.html), and only supports a boolean connectivity status (either online or offline), with no network speed information. In those cases the plugin will return either `wifi` (when the browser is online) or `none` (when it's not). + +Other than the approximate "downlink" speed, where available, and due to security and privacy concerns, **no Web browser will provide** any specific information about the actual network your users' device is connected to, like **the SSID on a Wi-Fi, or the MAC address of their device.** + +## Learn more + +- [API Documentation](https://pub.dev/documentation/connectivity_plus/latest/connectivity_plus/connectivity_plus-library.html) +- [Plugin documentation website](https://plus.fluttercommunity.dev/docs/connectivity_plus/overview) diff --git a/lib/third_party/connectivity_plus/connectivity_plus/android/build.gradle b/lib/third_party/connectivity_plus/connectivity_plus/android/build.gradle new file mode 100644 index 00000000..e04630a8 --- /dev/null +++ b/lib/third_party/connectivity_plus/connectivity_plus/android/build.gradle @@ -0,0 +1,41 @@ +group 'io.flutter.plugins.connectivity' +version '1.0-SNAPSHOT' + +buildscript { + repositories { + google() + mavenCentral() + } + + dependencies { + classpath 'com.android.tools.build:gradle:7.4.2' + } +} + +rootProject.allprojects { + repositories { + google() + mavenCentral() + } +} + +apply plugin: 'com.android.library' + +android { + compileSdkVersion 31 + + namespace 'dev.fluttercommunity.plus.connectivity' + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + defaultConfig { + minSdkVersion 16 + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + lintOptions { + disable 'InvalidPackage' + } +} diff --git a/lib/third_party/connectivity_plus/connectivity_plus/android/gradle.properties b/lib/third_party/connectivity_plus/connectivity_plus/android/gradle.properties new file mode 100644 index 00000000..8bd86f68 --- /dev/null +++ b/lib/third_party/connectivity_plus/connectivity_plus/android/gradle.properties @@ -0,0 +1 @@ +org.gradle.jvmargs=-Xmx1536M diff --git a/lib/third_party/connectivity_plus/connectivity_plus/android/gradle/wrapper/gradle-wrapper.properties b/lib/third_party/connectivity_plus/connectivity_plus/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..62dbe3c1 --- /dev/null +++ b/lib/third_party/connectivity_plus/connectivity_plus/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-bin.zip +distributionPath=wrapper/dists +zipStorePath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME diff --git a/lib/third_party/connectivity_plus/connectivity_plus/android/settings.gradle b/lib/third_party/connectivity_plus/connectivity_plus/android/settings.gradle new file mode 100644 index 00000000..4fbed475 --- /dev/null +++ b/lib/third_party/connectivity_plus/connectivity_plus/android/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'connectivity' diff --git a/lib/third_party/connectivity_plus/connectivity_plus/android/src/main/AndroidManifest.xml b/lib/third_party/connectivity_plus/connectivity_plus/android/src/main/AndroidManifest.xml new file mode 100644 index 00000000..6435d2cb --- /dev/null +++ b/lib/third_party/connectivity_plus/connectivity_plus/android/src/main/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + diff --git a/lib/third_party/connectivity_plus/connectivity_plus/android/src/main/java/dev/fluttercommunity/plus/connectivity/Connectivity.java b/lib/third_party/connectivity_plus/connectivity_plus/android/src/main/java/dev/fluttercommunity/plus/connectivity/Connectivity.java new file mode 100644 index 00000000..02a316bc --- /dev/null +++ b/lib/third_party/connectivity_plus/connectivity_plus/android/src/main/java/dev/fluttercommunity/plus/connectivity/Connectivity.java @@ -0,0 +1,83 @@ +// Copyright 2019 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. + +package dev.fluttercommunity.plus.connectivity; + +import android.net.ConnectivityManager; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.os.Build; + +/** Reports connectivity related information such as connectivity type and wifi information. */ +public class Connectivity { + static final String CONNECTIVITY_NONE = "none"; + static final String CONNECTIVITY_WIFI = "wifi"; + static final String CONNECTIVITY_MOBILE = "mobile"; + static final String CONNECTIVITY_ETHERNET = "ethernet"; + static final String CONNECTIVITY_BLUETOOTH = "bluetooth"; + static final String CONNECTIVITY_VPN = "vpn"; + private final ConnectivityManager connectivityManager; + + public Connectivity(ConnectivityManager connectivityManager) { + this.connectivityManager = connectivityManager; + } + + String getNetworkType() { + if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + Network network = connectivityManager.getActiveNetwork(); + NetworkCapabilities capabilities = connectivityManager.getNetworkCapabilities(network); + if (capabilities == null) { + return CONNECTIVITY_NONE; + } + if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) { + return CONNECTIVITY_WIFI; + } + if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)) { + return CONNECTIVITY_ETHERNET; + } + if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN)) { + return CONNECTIVITY_VPN; + } + if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) { + return CONNECTIVITY_MOBILE; + } + if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH)) { + return CONNECTIVITY_BLUETOOTH; + } + } + + return getNetworkTypeLegacy(); + } + + @SuppressWarnings("deprecation") + private String getNetworkTypeLegacy() { + // handle type for Android versions less than Android 6 + android.net.NetworkInfo info = connectivityManager.getActiveNetworkInfo(); + if (info == null || !info.isConnected()) { + return CONNECTIVITY_NONE; + } + int type = info.getType(); + switch (type) { + case ConnectivityManager.TYPE_BLUETOOTH: + return CONNECTIVITY_BLUETOOTH; + case ConnectivityManager.TYPE_ETHERNET: + return CONNECTIVITY_ETHERNET; + case ConnectivityManager.TYPE_WIFI: + case ConnectivityManager.TYPE_WIMAX: + return CONNECTIVITY_WIFI; + case ConnectivityManager.TYPE_VPN: + return CONNECTIVITY_VPN; + case ConnectivityManager.TYPE_MOBILE: + case ConnectivityManager.TYPE_MOBILE_DUN: + case ConnectivityManager.TYPE_MOBILE_HIPRI: + return CONNECTIVITY_MOBILE; + default: + return CONNECTIVITY_NONE; + } + } + + public ConnectivityManager getConnectivityManager() { + return connectivityManager; + } +} diff --git a/lib/third_party/connectivity_plus/connectivity_plus/android/src/main/java/dev/fluttercommunity/plus/connectivity/ConnectivityBroadcastReceiver.java b/lib/third_party/connectivity_plus/connectivity_plus/android/src/main/java/dev/fluttercommunity/plus/connectivity/ConnectivityBroadcastReceiver.java new file mode 100644 index 00000000..22ecacd7 --- /dev/null +++ b/lib/third_party/connectivity_plus/connectivity_plus/android/src/main/java/dev/fluttercommunity/plus/connectivity/ConnectivityBroadcastReceiver.java @@ -0,0 +1,94 @@ +// Copyright 2019 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. + +package dev.fluttercommunity.plus.connectivity; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.net.ConnectivityManager; +import android.net.Network; +import android.os.Build; +import android.os.Handler; +import android.os.Looper; +import io.flutter.plugin.common.EventChannel; + +/** + * The ConnectivityBroadcastReceiver receives the connectivity updates and send them to the UIThread + * through an {@link EventChannel.EventSink} + * + *

Use {@link + * io.flutter.plugin.common.EventChannel#setStreamHandler(io.flutter.plugin.common.EventChannel.StreamHandler)} + * to set up the receiver. + */ +public class ConnectivityBroadcastReceiver extends BroadcastReceiver + implements EventChannel.StreamHandler { + private final Context context; + private final Connectivity connectivity; + private EventChannel.EventSink events; + private final Handler mainHandler = new Handler(Looper.getMainLooper()); + private ConnectivityManager.NetworkCallback networkCallback; + public static final String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE"; + + public ConnectivityBroadcastReceiver(Context context, Connectivity connectivity) { + this.context = context; + this.connectivity = connectivity; + } + + @Override + public void onListen(Object arguments, EventChannel.EventSink events) { + this.events = events; + if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + networkCallback = + new ConnectivityManager.NetworkCallback() { + @Override + public void onAvailable(Network network) { + sendEvent(); + } + + @Override + public void onLost(Network network) { + sendEvent(Connectivity.CONNECTIVITY_NONE); + } + }; + connectivity.getConnectivityManager().registerDefaultNetworkCallback(networkCallback); + } else { + context.registerReceiver(this, new IntentFilter(CONNECTIVITY_ACTION)); + } + } + + @Override + public void onCancel(Object arguments) { + if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + if (networkCallback != null) { + connectivity.getConnectivityManager().unregisterNetworkCallback(networkCallback); + networkCallback = null; + } + } else { + try { + context.unregisterReceiver(this); + } catch (Exception e) { + //listen never called, ignore the error + } + } + } + + @Override + public void onReceive(Context context, Intent intent) { + if (events != null) { + events.success(connectivity.getNetworkType()); + } + } + + private void sendEvent() { + Runnable runnable = () -> events.success(connectivity.getNetworkType()); + mainHandler.post(runnable); + } + + private void sendEvent(final String networkType) { + Runnable runnable = () -> events.success(networkType); + mainHandler.post(runnable); + } +} diff --git a/lib/third_party/connectivity_plus/connectivity_plus/android/src/main/java/dev/fluttercommunity/plus/connectivity/ConnectivityMethodChannelHandler.java b/lib/third_party/connectivity_plus/connectivity_plus/android/src/main/java/dev/fluttercommunity/plus/connectivity/ConnectivityMethodChannelHandler.java new file mode 100644 index 00000000..ad12f66d --- /dev/null +++ b/lib/third_party/connectivity_plus/connectivity_plus/android/src/main/java/dev/fluttercommunity/plus/connectivity/ConnectivityMethodChannelHandler.java @@ -0,0 +1,37 @@ +// Copyright 2019 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. + +package dev.fluttercommunity.plus.connectivity; + +import androidx.annotation.NonNull; +import io.flutter.plugin.common.MethodCall; +import io.flutter.plugin.common.MethodChannel; + +/** + * The handler receives {@link MethodCall}s from the UIThread, gets the related information from + * a @{@link Connectivity}, and then send the result back to the UIThread through the {@link + * MethodChannel.Result}. + */ +class ConnectivityMethodChannelHandler implements MethodChannel.MethodCallHandler { + + private final Connectivity connectivity; + + /** + * Construct the ConnectivityMethodChannelHandler with a {@code connectivity}. The {@code + * connectivity} must not be null. + */ + ConnectivityMethodChannelHandler(Connectivity connectivity) { + assert (connectivity != null); + this.connectivity = connectivity; + } + + @Override + public void onMethodCall(MethodCall call, @NonNull MethodChannel.Result result) { + if ("check".equals(call.method)) { + result.success(connectivity.getNetworkType()); + } else { + result.notImplemented(); + } + } +} diff --git a/lib/third_party/connectivity_plus/connectivity_plus/android/src/main/java/dev/fluttercommunity/plus/connectivity/ConnectivityPlugin.java b/lib/third_party/connectivity_plus/connectivity_plus/android/src/main/java/dev/fluttercommunity/plus/connectivity/ConnectivityPlugin.java new file mode 100644 index 00000000..666cfb83 --- /dev/null +++ b/lib/third_party/connectivity_plus/connectivity_plus/android/src/main/java/dev/fluttercommunity/plus/connectivity/ConnectivityPlugin.java @@ -0,0 +1,56 @@ +// Copyright 2017 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. + +package dev.fluttercommunity.plus.connectivity; + +import android.content.Context; +import android.net.ConnectivityManager; +import androidx.annotation.NonNull; +import io.flutter.embedding.engine.plugins.FlutterPlugin; +import io.flutter.plugin.common.BinaryMessenger; +import io.flutter.plugin.common.EventChannel; +import io.flutter.plugin.common.MethodChannel; + +/** ConnectivityPlugin */ +public class ConnectivityPlugin implements FlutterPlugin { + + private MethodChannel methodChannel; + private EventChannel eventChannel; + private ConnectivityBroadcastReceiver receiver; + + @Override + public void onAttachedToEngine(FlutterPluginBinding binding) { + setupChannels(binding.getBinaryMessenger(), binding.getApplicationContext()); + } + + @Override + public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) { + teardownChannels(); + } + + private void setupChannels(BinaryMessenger messenger, Context context) { + methodChannel = new MethodChannel(messenger, "dev.fluttercommunity.plus/connectivity"); + eventChannel = new EventChannel(messenger, "dev.fluttercommunity.plus/connectivity_status"); + ConnectivityManager connectivityManager = + (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + + Connectivity connectivity = new Connectivity(connectivityManager); + + ConnectivityMethodChannelHandler methodChannelHandler = + new ConnectivityMethodChannelHandler(connectivity); + receiver = new ConnectivityBroadcastReceiver(context, connectivity); + + methodChannel.setMethodCallHandler(methodChannelHandler); + eventChannel.setStreamHandler(receiver); + } + + private void teardownChannels() { + methodChannel.setMethodCallHandler(null); + eventChannel.setStreamHandler(null); + receiver.onCancel(null); + methodChannel = null; + eventChannel = null; + receiver = null; + } +} diff --git a/lib/third_party/connectivity_plus/connectivity_plus/ios/Assets/.gitkeep b/lib/third_party/connectivity_plus/connectivity_plus/ios/Assets/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/lib/third_party/connectivity_plus/connectivity_plus/ios/Classes/ConnectivityPlusPlugin.h b/lib/third_party/connectivity_plus/connectivity_plus/ios/Classes/ConnectivityPlusPlugin.h new file mode 100644 index 00000000..e5d0ccbd --- /dev/null +++ b/lib/third_party/connectivity_plus/connectivity_plus/ios/Classes/ConnectivityPlusPlugin.h @@ -0,0 +1,4 @@ +#import + +@interface ConnectivityPlusPlugin : NSObject +@end diff --git a/lib/third_party/connectivity_plus/connectivity_plus/ios/Classes/ConnectivityPlusPlugin.m b/lib/third_party/connectivity_plus/connectivity_plus/ios/Classes/ConnectivityPlusPlugin.m new file mode 100644 index 00000000..43af3800 --- /dev/null +++ b/lib/third_party/connectivity_plus/connectivity_plus/ios/Classes/ConnectivityPlusPlugin.m @@ -0,0 +1,15 @@ +#import "ConnectivityPlusPlugin.h" +#if __has_include() +#import +#else +// Support project import fallback if the generated compatibility header +// is not copied when this plugin is created as a library. +// https://forums.swift.org/t/swift-static-libraries-dont-copy-generated-objective-c-header/19816 +#import "connectivity_plus-Swift.h" +#endif + +@implementation ConnectivityPlusPlugin ++ (void)registerWithRegistrar:(NSObject *)registrar { + [SwiftConnectivityPlusPlugin registerWithRegistrar:registrar]; +} +@end diff --git a/lib/third_party/connectivity_plus/connectivity_plus/ios/Classes/ConnectivityProvider.swift b/lib/third_party/connectivity_plus/connectivity_plus/ios/Classes/ConnectivityProvider.swift new file mode 100644 index 00000000..38156822 --- /dev/null +++ b/lib/third_party/connectivity_plus/connectivity_plus/ios/Classes/ConnectivityProvider.swift @@ -0,0 +1,21 @@ +import Foundation + +public enum ConnectivityType { + case none + case wiredEthernet + case wifi + case cellular + case other +} + +public protocol ConnectivityProvider: NSObjectProtocol { + typealias ConnectivityUpdateHandler = (ConnectivityType) -> Void + + var currentConnectivityType: ConnectivityType { get } + + var connectivityUpdateHandler: ConnectivityUpdateHandler? { get set } + + func start() + + func stop() +} diff --git a/lib/third_party/connectivity_plus/connectivity_plus/ios/Classes/PathMonitorConnectivityProvider.swift b/lib/third_party/connectivity_plus/connectivity_plus/ios/Classes/PathMonitorConnectivityProvider.swift new file mode 100644 index 00000000..5447780d --- /dev/null +++ b/lib/third_party/connectivity_plus/connectivity_plus/ios/Classes/PathMonitorConnectivityProvider.swift @@ -0,0 +1,60 @@ +import Foundation +import Network + +@available(iOS 12, *) +public class PathMonitorConnectivityProvider: NSObject, ConnectivityProvider { + + private let queue = DispatchQueue.global(qos: .background) + + private var _pathMonitor: NWPathMonitor? + + public var currentConnectivityType: ConnectivityType { + let path = ensurePathMonitor().currentPath + // .satisfied means that the network is available + if path.status == .satisfied { + if path.usesInterfaceType(.wifi) { + return .wifi + } else if path.usesInterfaceType(.cellular) { + return .cellular + } else if path.usesInterfaceType(.wiredEthernet) { + // .wiredEthernet is available in simulator + // but for consistency it is probably correct to report .wifi + return .wifi + } else if path.usesInterfaceType(.other) { + return .other + } + } + return .none + } + + public var connectivityUpdateHandler: ConnectivityUpdateHandler? + + override init() { + super.init() + _ = ensurePathMonitor() + } + + public func start() { + _ = ensurePathMonitor() + } + + public func stop() { + _pathMonitor?.cancel() + _pathMonitor = nil + } + + @discardableResult + private func ensurePathMonitor() -> NWPathMonitor { + if (_pathMonitor == nil) { + let pathMonitor = NWPathMonitor() + pathMonitor.start(queue: queue) + pathMonitor.pathUpdateHandler = pathUpdateHandler + _pathMonitor = pathMonitor + } + return _pathMonitor! + } + + private func pathUpdateHandler(path: NWPath) { + connectivityUpdateHandler?(currentConnectivityType) + } +} diff --git a/lib/third_party/connectivity_plus/connectivity_plus/ios/Classes/ReachabilityConnectivityProvider.swift b/lib/third_party/connectivity_plus/connectivity_plus/ios/Classes/ReachabilityConnectivityProvider.swift new file mode 100644 index 00000000..4398a12e --- /dev/null +++ b/lib/third_party/connectivity_plus/connectivity_plus/ios/Classes/ReachabilityConnectivityProvider.swift @@ -0,0 +1,59 @@ +import Foundation +import Reachability + +public class ReachabilityConnectivityProvider: NSObject, ConnectivityProvider { + private var _reachability: Reachability? + + public var currentConnectivityType: ConnectivityType { + let reachability = ensureReachability() + switch reachability.connection { + case .wifi: + return .wifi + case .cellular: + return .cellular + default: + return .none + } + } + + public var connectivityUpdateHandler: ConnectivityUpdateHandler? + + override init() { + super.init() + _ = ensureReachability() + } + + public func start() { + let reachability = ensureReachability() + + NotificationCenter.default.addObserver( + self, + selector: #selector(reachabilityChanged), + name: .reachabilityChanged, + object: reachability) + + try? reachability.startNotifier() + } + + public func stop() { + NotificationCenter.default.removeObserver( + self, + name: .reachabilityChanged, + object: _reachability) + + _reachability?.stopNotifier() + _reachability = nil + } + + private func ensureReachability() -> Reachability { + if (_reachability == nil) { + let reachability = try? Reachability() + _reachability = reachability + } + return _reachability! + } + + @objc private func reachabilityChanged(notification: NSNotification) { + connectivityUpdateHandler?(currentConnectivityType) + } +} diff --git a/lib/third_party/connectivity_plus/connectivity_plus/ios/Classes/SwiftConnectivityPlusPlugin.swift b/lib/third_party/connectivity_plus/connectivity_plus/ios/Classes/SwiftConnectivityPlusPlugin.swift new file mode 100644 index 00000000..c969b4e5 --- /dev/null +++ b/lib/third_party/connectivity_plus/connectivity_plus/ios/Classes/SwiftConnectivityPlusPlugin.swift @@ -0,0 +1,89 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source is governed by a BSD-style license that can +// be found in the LICENSE file. + +import Flutter + +public class SwiftConnectivityPlusPlugin: NSObject, FlutterPlugin, FlutterStreamHandler { + private let connectivityProvider: ConnectivityProvider + private var eventSink: FlutterEventSink? + + init(connectivityProvider: ConnectivityProvider) { + self.connectivityProvider = connectivityProvider + super.init() + self.connectivityProvider.connectivityUpdateHandler = connectivityUpdateHandler + } + + public static func register(with registrar: FlutterPluginRegistrar) { + let channel = FlutterMethodChannel( + name: "dev.fluttercommunity.plus/connectivity", + binaryMessenger: registrar.messenger()) + + let streamChannel = FlutterEventChannel( + name: "dev.fluttercommunity.plus/connectivity_status", + binaryMessenger: registrar.messenger()) + + let connectivityProvider: ConnectivityProvider + if #available(iOS 12, *) { + connectivityProvider = PathMonitorConnectivityProvider() + } else { + connectivityProvider = ReachabilityConnectivityProvider() + } + + let instance = SwiftConnectivityPlusPlugin(connectivityProvider: connectivityProvider) + streamChannel.setStreamHandler(instance) + + registrar.addMethodCallDelegate(instance, channel: channel) + } + + public func detachFromEngine(for registrar: FlutterPluginRegistrar) { + eventSink = nil + connectivityProvider.stop() + } + + public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { + switch call.method { + case "check": + result(statusFrom(connectivityType: connectivityProvider.currentConnectivityType)) + default: + result(FlutterMethodNotImplemented) + } + } + + private func statusFrom(connectivityType: ConnectivityType) -> String { + switch connectivityType { + case .wifi: + return "wifi" + case .cellular: + return "mobile" + case .wiredEthernet: + return "ethernet" + case .other: + return "other" + case .none: + return "none" + } + } + + public func onListen( + withArguments _: Any?, + eventSink events: @escaping FlutterEventSink + ) -> FlutterError? { + eventSink = events + connectivityProvider.start() + connectivityUpdateHandler(connectivityType: connectivityProvider.currentConnectivityType) + return nil + } + + private func connectivityUpdateHandler(connectivityType: ConnectivityType) { + DispatchQueue.main.async { + self.eventSink?(self.statusFrom(connectivityType: connectivityType)) + } + } + + public func onCancel(withArguments _: Any?) -> FlutterError? { + connectivityProvider.stop() + eventSink = nil + return nil + } +} diff --git a/lib/third_party/connectivity_plus/connectivity_plus/ios/connectivity_plus.podspec b/lib/third_party/connectivity_plus/connectivity_plus/ios/connectivity_plus.podspec new file mode 100644 index 00000000..f591b337 --- /dev/null +++ b/lib/third_party/connectivity_plus/connectivity_plus/ios/connectivity_plus.podspec @@ -0,0 +1,24 @@ +# +# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html +# +Pod::Spec.new do |s| + s.name = 'connectivity_plus' + s.version = '0.0.1' + s.summary = 'Flutter Connectivity' + s.description = <<-DESC +This plugin allows Flutter apps to discover network connectivity and configure themselves accordingly. +Downloaded by pub (not CocoaPods). + DESC + s.homepage = 'https://plus.fluttercommunity.dev/' + s.license = { :type => 'BSD', :file => '../LICENSE' } + s.author = { 'Flutter Community Team' => 'authors@fluttercommunity.dev' } + s.source = { :http => 'https://github.com/fluttercommunity/plus_plugins' } + s.documentation_url = 'https://pub.dev/packages/connectivity_plus' + s.source_files = 'Classes/**/*' + s.public_header_files = 'Classes/**/*.h' + s.dependency 'Flutter' + s.dependency 'ReachabilitySwift' + s.platform = :ios, '9.0' + s.swift_version = '5.0' + s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'VALID_ARCHS[sdk=iphonesimulator*]' => 'x86_64' } +end diff --git a/lib/third_party/connectivity_plus/connectivity_plus/lib/connectivity_plus.dart b/lib/third_party/connectivity_plus/connectivity_plus/lib/connectivity_plus.dart new file mode 100644 index 00000000..38cf3515 --- /dev/null +++ b/lib/third_party/connectivity_plus/connectivity_plus/lib/connectivity_plus.dart @@ -0,0 +1,55 @@ +// Copyright 2017 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:connectivity_plus_platform_interface/connectivity_plus_platform_interface.dart'; + +// Export enums from the platform_interface so plugin users can use them directly. +export 'package:connectivity_plus_platform_interface/connectivity_plus_platform_interface.dart' + show ConnectivityResult; + +export 'src/connectivity_plus_linux.dart' + if (dart.library.html) 'src/connectivity_plus_web.dart'; + +/// Discover network connectivity configurations: Distinguish between WI-FI and cellular, check WI-FI status and more. +class Connectivity { + /// Constructs a singleton instance of [Connectivity]. + /// + /// [Connectivity] is designed to work as a singleton. + // When a second instance is created, the first instance will not be able to listen to the + // EventChannel because it is overridden. Forcing the class to be a singleton class can prevent + // misuse of creating a second instance from a programmer. + factory Connectivity() { + _singleton ??= Connectivity._(); + return _singleton!; + } + + Connectivity._(); + + static Connectivity? _singleton; + + static ConnectivityPlatform get _platform { + return ConnectivityPlatform.instance; + } + + /// Fires whenever the connectivity state changes. + /// + /// On iOS, the connectivity status might not update when WiFi + /// status changes, this is a known issue that only affects simulators. + /// For details see https://github.com/fluttercommunity/plus_plugins/issues/479. + Stream get onConnectivityChanged { + return _platform.onConnectivityChanged; + } + + /// Checks the connection status of the device. + /// + /// Do not use the result of this function to decide whether you can reliably + /// make a network request. It only gives you the radio status. + /// + /// Instead listen for connectivity changes via [onConnectivityChanged] stream. + Future checkConnectivity() { + return _platform.checkConnectivity(); + } +} diff --git a/lib/third_party/connectivity_plus/connectivity_plus/lib/src/connectivity_plus_linux.dart b/lib/third_party/connectivity_plus/connectivity_plus/lib/src/connectivity_plus_linux.dart new file mode 100644 index 00000000..bca6cdfe --- /dev/null +++ b/lib/third_party/connectivity_plus/connectivity_plus/lib/src/connectivity_plus_linux.dart @@ -0,0 +1,85 @@ +import 'dart:async'; + +import 'package:connectivity_plus_platform_interface/connectivity_plus_platform_interface.dart'; +import 'package:meta/meta.dart'; +import 'package:cwtch/third_party/nm/nm.dart'; + +// Used internally +// ignore_for_file: public_member_api_docs + +@visibleForTesting +typedef NetworkManagerClientFactory = NetworkManagerClient Function(); + +/// The Linux implementation of ConnectivityPlatform. +class ConnectivityPlusLinuxPlugin extends ConnectivityPlatform { + /// Register this dart class as the platform implementation for linux + static void registerWith() { + ConnectivityPlatform.instance = ConnectivityPlusLinuxPlugin(); + } + + /// Checks the connection status of the device. + @override + Future checkConnectivity() async { + final client = createClient(); + await client.connect(); + final connectivity = _getConnectivity(client); + await client.close(); + return connectivity; + } + + NetworkManagerClient? _client; + StreamController? _controller; + + /// Returns a Stream of ConnectivityResults changes. + @override + Stream get onConnectivityChanged { + _controller ??= StreamController.broadcast( + onListen: _startListenConnectivity, + onCancel: _stopListenConnectivity, + ); + return _controller!.stream; + } + + ConnectivityResult _getConnectivity(NetworkManagerClient client) { + if (client.connectivity != NetworkManagerConnectivityState.full) { + return ConnectivityResult.none; + } + if (client.primaryConnectionType.contains('wireless')) { + return ConnectivityResult.wifi; + } + if (client.primaryConnectionType.contains('ethernet')) { + return ConnectivityResult.ethernet; + } + if (client.primaryConnectionType.contains('vpn')) { + return ConnectivityResult.vpn; + } + if (client.primaryConnectionType.contains('bluetooth')) { + return ConnectivityResult.bluetooth; + } + return ConnectivityResult.mobile; + } + + Future _startListenConnectivity() async { + _client ??= createClient(); + await _client!.connect(); + _addConnectivity(_client!); + _client!.propertiesChanged.listen((properties) { + if (properties.contains('Connectivity')) { + _addConnectivity(_client!); + } + }); + } + + void _addConnectivity(NetworkManagerClient client) { + _controller!.add(_getConnectivity(client)); + } + + Future _stopListenConnectivity() async { + await _client?.close(); + _client = null; + } + + @visibleForTesting + // ignore: prefer_function_declarations_over_variables + NetworkManagerClientFactory createClient = () => NetworkManagerClient(); +} diff --git a/lib/third_party/connectivity_plus/connectivity_plus/lib/src/connectivity_plus_web.dart b/lib/third_party/connectivity_plus/connectivity_plus/lib/src/connectivity_plus_web.dart new file mode 100644 index 00000000..28c1db1d --- /dev/null +++ b/lib/third_party/connectivity_plus/connectivity_plus/lib/src/connectivity_plus_web.dart @@ -0,0 +1,27 @@ +import 'package:connectivity_plus_platform_interface/connectivity_plus_platform_interface.dart'; +import 'package:flutter_web_plugins/flutter_web_plugins.dart'; + +import 'web/network_information_api_connectivity_plugin.dart'; +import 'web/dart_html_connectivity_plugin.dart'; + +/// The web implementation of the ConnectivityPlatform of the Connectivity plugin. +class ConnectivityPlusWebPlugin extends ConnectivityPlatform { + /// Factory method that initializes the connectivity plugin platform with an instance + /// of the plugin for the web. + static void registerWith(Registrar registrar) { + // Since the `NetworkInformationApi` is currently an experimental API and + // does not provide a reliable way to check a connectivity change + // from an onnline state to an offline state, + // its implementation is disabled for now. + // See also: https://developer.mozilla.org/en-US/docs/Web/API/Network_Information_API + // + // TODO: use `NetworkInformationApiConnectivityPlugin.isSupported()` when it becomes a stable DOM API. + const isSupported = false; + + if (isSupported) { + ConnectivityPlatform.instance = NetworkInformationApiConnectivityPlugin(); + } else { + ConnectivityPlatform.instance = DartHtmlConnectivityPlugin(); + } + } +} diff --git a/lib/third_party/connectivity_plus/connectivity_plus/lib/src/web/dart_html_connectivity_plugin.dart b/lib/third_party/connectivity_plus/connectivity_plus/lib/src/web/dart_html_connectivity_plugin.dart new file mode 100644 index 00000000..d5c0c68b --- /dev/null +++ b/lib/third_party/connectivity_plus/connectivity_plus/lib/src/web/dart_html_connectivity_plugin.dart @@ -0,0 +1,35 @@ +import 'dart:async'; +import 'dart:html' as html show window; + +import 'package:connectivity_plus_platform_interface/connectivity_plus_platform_interface.dart'; + +import '../connectivity_plus_web.dart'; + +/// The web implementation of the ConnectivityPlatform of the Connectivity plugin. +class DartHtmlConnectivityPlugin extends ConnectivityPlusWebPlugin { + /// Checks the connection status of the device. + @override + Future checkConnectivity() async { + return (html.window.navigator.onLine ?? false) + ? ConnectivityResult.wifi + : ConnectivityResult.none; + } + + StreamController? _connectivityResult; + + /// Returns a Stream of ConnectivityResults changes. + @override + Stream get onConnectivityChanged { + if (_connectivityResult == null) { + _connectivityResult = StreamController.broadcast(); + // Fallback to dart:html window.onOnline / window.onOffline + html.window.onOnline.listen((event) { + _connectivityResult!.add(ConnectivityResult.wifi); + }); + html.window.onOffline.listen((event) { + _connectivityResult!.add(ConnectivityResult.none); + }); + } + return _connectivityResult!.stream; + } +} diff --git a/lib/third_party/connectivity_plus/connectivity_plus/lib/src/web/network_information_api_connectivity_plugin.dart b/lib/third_party/connectivity_plus/connectivity_plus/lib/src/web/network_information_api_connectivity_plugin.dart new file mode 100644 index 00000000..bc822a76 --- /dev/null +++ b/lib/third_party/connectivity_plus/connectivity_plus/lib/src/web/network_information_api_connectivity_plugin.dart @@ -0,0 +1,92 @@ +import 'dart:async'; +import 'dart:html' as html show window, NetworkInformation; +import 'dart:js_util'; + +import 'package:connectivity_plus/src/web/utils/connectivity_result.dart'; +import 'package:connectivity_plus_platform_interface/connectivity_plus_platform_interface.dart'; +import 'package:flutter/foundation.dart'; +import 'package:js/js.dart'; + +import '../connectivity_plus_web.dart'; + +/// The web implementation of the ConnectivityPlatform of the Connectivity plugin. +class NetworkInformationApiConnectivityPlugin + extends ConnectivityPlusWebPlugin { + final html.NetworkInformation _networkInformation; + + /// A check to determine if this version of the plugin can be used. + static bool isSupported() => html.window.navigator.connection != null; + + /// The constructor of the plugin. + NetworkInformationApiConnectivityPlugin() + : this.withConnection(html.window.navigator.connection!); + + /// Creates the plugin, with an override of the NetworkInformation object. + @visibleForTesting + NetworkInformationApiConnectivityPlugin.withConnection( + html.NetworkInformation connection) + : _networkInformation = connection; + + /// Checks the connection status of the device. + @override + Future checkConnectivity() async { + return networkInformationToConnectivityResult(_networkInformation); + } + + StreamController? _connectivityResultStreamController; + late Stream _connectivityResultStream; + + /// Returns a Stream of ConnectivityResults changes. + @override + Stream get onConnectivityChanged { + // use fallback implementation if [_connectionSupported] is not availible + if (_connectionSupported == null) { + return _webPseudoStream(); + } + if (_connectivityResultStreamController == null) { + _connectivityResultStreamController = + StreamController(); + setProperty(_networkInformation, 'onchange', allowInterop((_) { + _connectivityResultStreamController! + .add(networkInformationToConnectivityResult(_networkInformation)); + })); + // ignore: todo + // TODO: Implement the above with _networkInformation.onChange: + // _networkInformation.onChange.listen((_) { + // _connectivityResult + // .add(networkInformationToConnectivityResult(_networkInformation)); + // }); + // Once we can detect when to *cancel* a subscription to the _networkInformation + // onChange Stream upon hot restart. + // https://github.com/dart-lang/sdk/issues/42679 + _connectivityResultStream = + _connectivityResultStreamController!.stream.asBroadcastStream(); + } + return _connectivityResultStream; + } + + /// stores the last fallback network state + ConnectivityResult? _lastFallbackState; + + /// periodically checks the current network state + Stream _webPseudoStream() { + final StreamController webStream = + StreamController.broadcast(); + Timer.periodic( + const Duration(milliseconds: 250), + (timer) async { + final result = await checkConnectivity(); + if (result != _lastFallbackState) { + webStream.add(result); + } + }, + ); + return webStream.stream; + } +} + +/// accesses the JS-native `navigator.connection` +/// +/// ensures `navigator.connection.onchange` is availible +@JS("navigator.connection") +external get _connectionSupported; diff --git a/lib/third_party/connectivity_plus/connectivity_plus/lib/src/web/utils/connectivity_result.dart b/lib/third_party/connectivity_plus/connectivity_plus/lib/src/web/utils/connectivity_result.dart new file mode 100644 index 00000000..004cba81 --- /dev/null +++ b/lib/third_party/connectivity_plus/connectivity_plus/lib/src/web/utils/connectivity_result.dart @@ -0,0 +1,53 @@ +import 'dart:html' as html show NetworkInformation; + +import 'package:connectivity_plus_platform_interface/connectivity_plus_platform_interface.dart'; + +/// Converts an incoming NetworkInformation object into the correct ConnectivityResult. +ConnectivityResult networkInformationToConnectivityResult( + html.NetworkInformation info, +) { + if (info.downlink == 0 && info.rtt == 0) { + return ConnectivityResult.none; + } + if (info.type != null) { + return _typeToConnectivityResult(info.type!); + } + if (info.effectiveType != null) { + return _effectiveTypeToConnectivityResult(info.effectiveType!); + } + return ConnectivityResult.none; +} + +ConnectivityResult _effectiveTypeToConnectivityResult(String effectiveType) { + // Possible values: + /*'2g'|'3g'|'4g'|'slow-2g'*/ + switch (effectiveType) { + case 'slow-2g': + case '2g': + case '3g': + case '4g': + return ConnectivityResult.mobile; + default: + return ConnectivityResult.wifi; + } +} + +ConnectivityResult _typeToConnectivityResult(String type) { + // Possible values: + /*'bluetooth'|'cellular'|'ethernet'|'mixed'|'none'|'other'|'unknown'|'wifi'|'wimax'*/ + switch (type) { + case 'none': + return ConnectivityResult.none; + case 'bluetooth': + return ConnectivityResult.bluetooth; + case 'cellular': + case 'mixed': + case 'other': + case 'unknown': + return ConnectivityResult.mobile; + case 'ethernet': + return ConnectivityResult.ethernet; + default: + return ConnectivityResult.wifi; + } +} diff --git a/lib/third_party/connectivity_plus/connectivity_plus/macos/Classes/ConnectivityPlugin.swift b/lib/third_party/connectivity_plus/connectivity_plus/macos/Classes/ConnectivityPlugin.swift new file mode 100644 index 00000000..8be217e9 --- /dev/null +++ b/lib/third_party/connectivity_plus/connectivity_plus/macos/Classes/ConnectivityPlugin.swift @@ -0,0 +1,90 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source is governed by a BSD-style license that can +// be found in the LICENSE file. + +import Cocoa +import FlutterMacOS + +public class ConnectivityPlugin: NSObject, FlutterPlugin, FlutterStreamHandler { + private let connectivityProvider: ConnectivityProvider + private var eventSink: FlutterEventSink? + + init(connectivityProvider: ConnectivityProvider) { + self.connectivityProvider = connectivityProvider + super.init() + self.connectivityProvider.connectivityUpdateHandler = connectivityUpdateHandler + } + + public static func register(with registrar: FlutterPluginRegistrar) { + let channel = FlutterMethodChannel( + name: "dev.fluttercommunity.plus/connectivity", + binaryMessenger: registrar.messenger) + + let streamChannel = FlutterEventChannel( + name: "dev.fluttercommunity.plus/connectivity_status", + binaryMessenger: registrar.messenger) + + let connectivityProvider: ConnectivityProvider + if #available(macOS 10.14, *) { + connectivityProvider = PathMonitorConnectivityProvider() + } else { + connectivityProvider = ReachabilityConnectivityProvider() + } + + let instance = ConnectivityPlugin(connectivityProvider: connectivityProvider) + streamChannel.setStreamHandler(instance) + + registrar.addMethodCallDelegate(instance, channel: channel) + } + + public func detachFromEngine(for registrar: FlutterPluginRegistrar) { + eventSink = nil + connectivityProvider.stop() + } + + public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { + switch call.method { + case "check": + result(statusFrom(connectivityType: connectivityProvider.currentConnectivityType)) + default: + result(FlutterMethodNotImplemented) + } + } + + private func statusFrom(connectivityType: ConnectivityType) -> String { + switch connectivityType { + case .wifi: + return "wifi" + case .cellular: + return "mobile" + case .wiredEthernet: + return "ethernet" + case .other: + return "other" + case .none: + return "none" + } + } + + public func onListen( + withArguments _: Any?, + eventSink events: @escaping FlutterEventSink + ) -> FlutterError? { + eventSink = events + connectivityProvider.start() + connectivityUpdateHandler(connectivityType: connectivityProvider.currentConnectivityType) + return nil + } + + private func connectivityUpdateHandler(connectivityType: ConnectivityType) { + DispatchQueue.main.async { + self.eventSink?(self.statusFrom(connectivityType: connectivityType)) + } + } + + public func onCancel(withArguments _: Any?) -> FlutterError? { + connectivityProvider.stop() + eventSink = nil + return nil + } +} diff --git a/lib/third_party/connectivity_plus/connectivity_plus/macos/Classes/ConnectivityProvider.swift b/lib/third_party/connectivity_plus/connectivity_plus/macos/Classes/ConnectivityProvider.swift new file mode 100644 index 00000000..38156822 --- /dev/null +++ b/lib/third_party/connectivity_plus/connectivity_plus/macos/Classes/ConnectivityProvider.swift @@ -0,0 +1,21 @@ +import Foundation + +public enum ConnectivityType { + case none + case wiredEthernet + case wifi + case cellular + case other +} + +public protocol ConnectivityProvider: NSObjectProtocol { + typealias ConnectivityUpdateHandler = (ConnectivityType) -> Void + + var currentConnectivityType: ConnectivityType { get } + + var connectivityUpdateHandler: ConnectivityUpdateHandler? { get set } + + func start() + + func stop() +} diff --git a/lib/third_party/connectivity_plus/connectivity_plus/macos/Classes/PathMonitorConnectivityProvider.swift b/lib/third_party/connectivity_plus/connectivity_plus/macos/Classes/PathMonitorConnectivityProvider.swift new file mode 100644 index 00000000..5b86a0d8 --- /dev/null +++ b/lib/third_party/connectivity_plus/connectivity_plus/macos/Classes/PathMonitorConnectivityProvider.swift @@ -0,0 +1,57 @@ +import Foundation +import Network + +@available(macOS 10.14, *) +public class PathMonitorConnectivityProvider: NSObject, ConnectivityProvider { + + private let queue = DispatchQueue.global(qos: .background) + + private var _pathMonitor: NWPathMonitor? + + public var currentConnectivityType: ConnectivityType { + let path = ensurePathMonitor().currentPath + // .satisfied means that the network is available + if path.status == .satisfied { + if path.usesInterfaceType(.wifi) { + return .wifi + } else if path.usesInterfaceType(.cellular) { + return .cellular + } else if path.usesInterfaceType(.wiredEthernet) { + return .wiredEthernet + } else if path.usesInterfaceType(.other) { + return .other + } + } + return .none + } + + public var connectivityUpdateHandler: ConnectivityUpdateHandler? + + override init() { + super.init() + _ = ensurePathMonitor() + } + + public func start() { + _ = ensurePathMonitor() + } + + public func stop() { + _pathMonitor?.cancel() + _pathMonitor = nil + } + + private func ensurePathMonitor() -> NWPathMonitor { + if (_pathMonitor == nil) { + let pathMonitor = NWPathMonitor() + pathMonitor.start(queue: queue) + pathMonitor.pathUpdateHandler = pathUpdateHandler + _pathMonitor = pathMonitor + } + return _pathMonitor! + } + + private func pathUpdateHandler(path: NWPath) { + connectivityUpdateHandler?(currentConnectivityType) + } +} diff --git a/lib/third_party/connectivity_plus/connectivity_plus/macos/Classes/ReachabilityConnectivityProvider.swift b/lib/third_party/connectivity_plus/connectivity_plus/macos/Classes/ReachabilityConnectivityProvider.swift new file mode 100644 index 00000000..4398a12e --- /dev/null +++ b/lib/third_party/connectivity_plus/connectivity_plus/macos/Classes/ReachabilityConnectivityProvider.swift @@ -0,0 +1,59 @@ +import Foundation +import Reachability + +public class ReachabilityConnectivityProvider: NSObject, ConnectivityProvider { + private var _reachability: Reachability? + + public var currentConnectivityType: ConnectivityType { + let reachability = ensureReachability() + switch reachability.connection { + case .wifi: + return .wifi + case .cellular: + return .cellular + default: + return .none + } + } + + public var connectivityUpdateHandler: ConnectivityUpdateHandler? + + override init() { + super.init() + _ = ensureReachability() + } + + public func start() { + let reachability = ensureReachability() + + NotificationCenter.default.addObserver( + self, + selector: #selector(reachabilityChanged), + name: .reachabilityChanged, + object: reachability) + + try? reachability.startNotifier() + } + + public func stop() { + NotificationCenter.default.removeObserver( + self, + name: .reachabilityChanged, + object: _reachability) + + _reachability?.stopNotifier() + _reachability = nil + } + + private func ensureReachability() -> Reachability { + if (_reachability == nil) { + let reachability = try? Reachability() + _reachability = reachability + } + return _reachability! + } + + @objc private func reachabilityChanged(notification: NSNotification) { + connectivityUpdateHandler?(currentConnectivityType) + } +} diff --git a/lib/third_party/connectivity_plus/connectivity_plus/macos/connectivity_plus.podspec b/lib/third_party/connectivity_plus/connectivity_plus/macos/connectivity_plus.podspec new file mode 100644 index 00000000..4d155d2c --- /dev/null +++ b/lib/third_party/connectivity_plus/connectivity_plus/macos/connectivity_plus.podspec @@ -0,0 +1,22 @@ +# +# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html +# +Pod::Spec.new do |s| + s.name = 'connectivity_plus' + s.version = '0.0.1' + s.summary = 'Flutter plugin for checking connectivity' + s.description = <<-DESC + Desktop implementation of the connectivity plugin + DESC + s.homepage = 'https://plus.fluttercommunity.dev/' + s.license = { :type => 'BSD', :file => '../LICENSE' } + s.author = { 'Flutter Community Team' => 'authors@fluttercommunity.dev' } + s.source = { :http => 'https://github.com/fluttercommunity/plus_plugins' } + s.documentation_url = 'https://pub.dev/packages/connectivity_plus' + s.source_files = 'Classes/**/*' + s.dependency 'FlutterMacOS' + s.dependency 'ReachabilitySwift' + + s.platform = :osx + s.osx.deployment_target = '10.11' +end diff --git a/lib/third_party/connectivity_plus/connectivity_plus/pubspec.yaml b/lib/third_party/connectivity_plus/connectivity_plus/pubspec.yaml new file mode 100644 index 00000000..5d9218ab --- /dev/null +++ b/lib/third_party/connectivity_plus/connectivity_plus/pubspec.yaml @@ -0,0 +1,48 @@ +name: connectivity_plus +description: Flutter plugin for discovering the state of the network (WiFi & mobile/cellular) connectivity on Android and iOS. +version: 3.0.6 +homepage: https://plus.fluttercommunity.dev/ +repository: https://github.com/fluttercommunity/plus_plugins/tree/main/packages/ +issue_tracker: https://github.com/fluttercommunity/plus_plugins/labels/connectivity_plus + +environment: + sdk: ">=2.12.0 <3.0.0" + flutter: ">=2.11.0" + +flutter: + plugin: + platforms: + android: + package: dev.fluttercommunity.plus.connectivity + pluginClass: ConnectivityPlugin + ios: + pluginClass: ConnectivityPlusPlugin + linux: + dartPluginClass: ConnectivityPlusLinuxPlugin + macos: + pluginClass: ConnectivityPlugin + web: + pluginClass: ConnectivityPlusWebPlugin + fileName: src/connectivity_plus_web.dart + windows: + pluginClass: ConnectivityPlusWindowsPlugin + +dependencies: + flutter: + sdk: flutter + flutter_web_plugins: + sdk: flutter + connectivity_plus_platform_interface: + path: ./../connectivity_plus_platform_interface + js: ^0.6.3 + meta: ^1.8.0 + +dev_dependencies: + flutter_test: + sdk: flutter + build_runner: ^2.1.11 + dbus: ^0.7.5 + flutter_lints: ^2.0.1 + mockito: ^5.2.0 + plugin_platform_interface: ^2.1.2 + test: ^1.21.1 diff --git a/lib/third_party/connectivity_plus/connectivity_plus/windows/.gitignore b/lib/third_party/connectivity_plus/connectivity_plus/windows/.gitignore new file mode 100644 index 00000000..b3eb2be1 --- /dev/null +++ b/lib/third_party/connectivity_plus/connectivity_plus/windows/.gitignore @@ -0,0 +1,17 @@ +flutter/ + +# Visual Studio user-specific files. +*.suo +*.user +*.userosscache +*.sln.docstates + +# Visual Studio build-related files. +x64/ +x86/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ diff --git a/lib/third_party/connectivity_plus/connectivity_plus/windows/CMakeLists.txt b/lib/third_party/connectivity_plus/connectivity_plus/windows/CMakeLists.txt new file mode 100644 index 00000000..ac315ccd --- /dev/null +++ b/lib/third_party/connectivity_plus/connectivity_plus/windows/CMakeLists.txt @@ -0,0 +1,29 @@ +cmake_minimum_required(VERSION 3.15) +set(PROJECT_NAME "connectivity_plus") +project(${PROJECT_NAME} LANGUAGES CXX) + +# This value is used when generating builds using this plugin, so it must +# not be changed +set(PLUGIN_NAME "connectivity_plus_plugin") + +add_library(${PLUGIN_NAME} SHARED + "connectivity_plus_plugin.cpp" + "network_manager.cpp" +) +apply_standard_settings(${PLUGIN_NAME}) +set_target_properties(${PLUGIN_NAME} PROPERTIES + CXX_VISIBILITY_PRESET hidden) +target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL) +target_include_directories(${PLUGIN_NAME} INTERFACE + "${CMAKE_CURRENT_SOURCE_DIR}/include") +target_link_libraries(${PLUGIN_NAME} PRIVATE + flutter + flutter_wrapper_plugin + iphlpapi +) + +# List of absolute paths to libraries that should be bundled with the plugin +set(connectivity_plus_bundled_libraries + "" + PARENT_SCOPE +) diff --git a/lib/third_party/connectivity_plus/connectivity_plus/windows/connectivity_plus_plugin.cpp b/lib/third_party/connectivity_plus/connectivity_plus/windows/connectivity_plus_plugin.cpp new file mode 100644 index 00000000..40742035 --- /dev/null +++ b/lib/third_party/connectivity_plus/connectivity_plus/windows/connectivity_plus_plugin.cpp @@ -0,0 +1,171 @@ +// clang-format off +#include "include/connectivity_plus/network_manager.h" +// clang-format on +#include "include/connectivity_plus/connectivity_plus_windows_plugin.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace { + +typedef flutter::EventChannel FlEventChannel; +typedef flutter::EventSink FlEventSink; +typedef flutter::MethodCall FlMethodCall; +typedef flutter::MethodResult FlMethodResult; +typedef flutter::MethodChannel FlMethodChannel; +typedef flutter::StreamHandler FlStreamHandler; +typedef flutter::StreamHandlerError + FlStreamHandlerError; + +class ConnectivityPlusWindowsPlugin : public flutter::Plugin { +public: + ConnectivityPlusWindowsPlugin(); + virtual ~ConnectivityPlusWindowsPlugin(); + + std::shared_ptr GetManager() const; + + static void RegisterWithRegistrar(flutter::PluginRegistrarWindows *registrar); + +private: + void HandleMethodCall(const FlMethodCall &method_call, + std::unique_ptr result); + + std::shared_ptr manager; +}; + +class ConnectivityStreamHandler : public FlStreamHandler { +public: + ConnectivityStreamHandler(std::shared_ptr manager); + virtual ~ConnectivityStreamHandler(); + +protected: + void AddConnectivityEvent(); + + std::unique_ptr + OnListenInternal(const flutter::EncodableValue *arguments, + std::unique_ptr &&sink) override; + + std::unique_ptr + OnCancelInternal(const flutter::EncodableValue *arguments) override; + +private: + std::shared_ptr manager; + std::unique_ptr sink; +}; + +ConnectivityPlusWindowsPlugin::ConnectivityPlusWindowsPlugin() { + manager = std::make_shared(); + manager->Init(); +} + +ConnectivityPlusWindowsPlugin::~ConnectivityPlusWindowsPlugin() { + manager->Cleanup(); +} + +std::shared_ptr +ConnectivityPlusWindowsPlugin::GetManager() const { + return manager; +} + +void ConnectivityPlusWindowsPlugin::RegisterWithRegistrar( + flutter::PluginRegistrarWindows *registrar) { + auto plugin = std::make_unique(); + + auto methodChannel = + std::make_unique>( + registrar->messenger(), "dev.fluttercommunity.plus/connectivity", + &flutter::StandardMethodCodec::GetInstance()); + + methodChannel->SetMethodCallHandler( + [plugin_pointer = plugin.get()](const auto &call, auto result) { + plugin_pointer->HandleMethodCall(call, std::move(result)); + }); + + auto eventChannel = std::make_unique( + registrar->messenger(), "dev.fluttercommunity.plus/connectivity_status", + &flutter::StandardMethodCodec::GetInstance()); + + eventChannel->SetStreamHandler( + std::make_unique(plugin->GetManager())); + + registrar->AddPlugin(std::move(plugin)); +} + +static std::string ConnectivityToString(ConnectivityType connectivityType) { + switch (connectivityType) { + case ConnectivityType::WiFi: + return "wifi"; + case ConnectivityType::Ethernet: + return "ethernet"; + case ConnectivityType::None: + default: + return "none"; + } +} + +void ConnectivityPlusWindowsPlugin::HandleMethodCall( + const flutter::MethodCall &method_call, + std::unique_ptr> result) { + if (method_call.method_name().compare("check") == 0) { + std::string connectivity = + ConnectivityToString(manager->GetConnectivityType()); + result->Success(flutter::EncodableValue(connectivity)); + } else { + result->NotImplemented(); + } +} + +ConnectivityStreamHandler::ConnectivityStreamHandler( + std::shared_ptr manager) + : manager(manager) {} + +ConnectivityStreamHandler::~ConnectivityStreamHandler() {} + +void ConnectivityStreamHandler::AddConnectivityEvent() { + std::string connectivity = + ConnectivityToString(manager->GetConnectivityType()); + sink->Success(flutter::EncodableValue(connectivity)); +} + +std::unique_ptr +ConnectivityStreamHandler::OnListenInternal( + const flutter::EncodableValue *arguments, + std::unique_ptr &&events) { + sink = std::move(events); + + auto callback = + std::bind(&ConnectivityStreamHandler::AddConnectivityEvent, this); + + if (!manager->StartListen(callback)) { + return std::make_unique( + std::to_string(manager->GetError()), "NetworkManager::StartListen", + nullptr); + } + + AddConnectivityEvent(); + return nullptr; +} + +std::unique_ptr +ConnectivityStreamHandler::OnCancelInternal( + const flutter::EncodableValue *arguments) { + manager->StopListen(); + sink.reset(); + return nullptr; +} + +} // namespace + +void ConnectivityPlusWindowsPluginRegisterWithRegistrar( + FlutterDesktopPluginRegistrarRef registrar) { + ConnectivityPlusWindowsPlugin::RegisterWithRegistrar( + flutter::PluginRegistrarManager::GetInstance() + ->GetRegistrar(registrar)); +} diff --git a/lib/third_party/connectivity_plus/connectivity_plus/windows/include/connectivity_plus/connectivity_plus_windows_plugin.h b/lib/third_party/connectivity_plus/connectivity_plus/windows/include/connectivity_plus/connectivity_plus_windows_plugin.h new file mode 100644 index 00000000..17af4474 --- /dev/null +++ b/lib/third_party/connectivity_plus/connectivity_plus/windows/include/connectivity_plus/connectivity_plus_windows_plugin.h @@ -0,0 +1,23 @@ +#ifndef FLUTTER_PLUGIN_CONNECTIVITY_WINDOWS_PLUS_PLUGIN_H_ +#define FLUTTER_PLUGIN_CONNECTIVITY_WINDOWS_PLUS_PLUGIN_H_ + +#include + +#ifdef FLUTTER_PLUGIN_IMPL +#define FLUTTER_PLUGIN_EXPORT __declspec(dllexport) +#else +#define FLUTTER_PLUGIN_EXPORT __declspec(dllimport) +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + +FLUTTER_PLUGIN_EXPORT void ConnectivityPlusWindowsPluginRegisterWithRegistrar( + FlutterDesktopPluginRegistrarRef registrar); + +#if defined(__cplusplus) +} // extern "C" +#endif + +#endif // FLUTTER_PLUGIN_CONNECTIVITY_PLUS_WINDOWS_PLUGIN_H_ diff --git a/lib/third_party/connectivity_plus/connectivity_plus/windows/include/connectivity_plus/network_manager.h b/lib/third_party/connectivity_plus/connectivity_plus/windows/include/connectivity_plus/network_manager.h new file mode 100644 index 00000000..51a7e9b3 --- /dev/null +++ b/lib/third_party/connectivity_plus/connectivity_plus/windows/include/connectivity_plus/network_manager.h @@ -0,0 +1,49 @@ +#ifndef NETWORK_MANAGER_H +#define NETWORK_MANAGER_H + +// clang-format off +#include +// clang-format on +#include + +#include +#include + +enum class ConnectivityType { None, Ethernet, WiFi }; + +class NetworkListener; +struct IConnectionPoint; +struct IConnectionPointContainer; +struct INetworkListManager; +struct IUnknown; + +typedef std::function NetworkCallback; + +class NetworkManager { +public: + NetworkManager(); + ~NetworkManager(); + + bool Init(); + void Cleanup(); + + ConnectivityType GetConnectivityType() const; + + bool StartListen(NetworkCallback pCallback); + void StopListen(); + + bool HasError() const; + int GetError() const; + +private: + std::vector GetConnectedAdapterIds() const; + + DWORD dwCookie = 0; + IUnknown *pUnknown = NULL; + INetworkListManager *pNetworkListManager = NULL; + IConnectionPointContainer *pCPContainer = NULL; + IConnectionPoint *pConnectPoint = NULL; + NetworkListener *pListener = NULL; +}; + +#endif // NETWORK_MANAGER_H diff --git a/lib/third_party/connectivity_plus/connectivity_plus/windows/network_manager.cpp b/lib/third_party/connectivity_plus/connectivity_plus/windows/network_manager.cpp new file mode 100644 index 00000000..e009c7ed --- /dev/null +++ b/lib/third_party/connectivity_plus/connectivity_plus/windows/network_manager.cpp @@ -0,0 +1,243 @@ +// based on +// https://github.com/PurpleI2P/i2pd/blob/master/Win32/Win32NetState.cpp + +/* + * Copyright (c) 2013-2020, The PurpleI2P Project + * + * This file is part of Purple i2pd project and licensed under BSD3 + * + * See full license text in LICENSE file at top of project tree + */ + +#include "include/connectivity_plus/network_manager.h" + +#include +#include +#include + +#include +#include + +class NetworkListener final : public INetworkEvents { +public: + NetworkListener(NetworkCallback pCb) : pCallback(pCb) {} + + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) { + AddRef(); + + HRESULT hr = S_OK; + if (IsEqualIID(riid, IID_IUnknown)) { + *ppvObject = (IUnknown *)this; + } else if (IsEqualIID(riid, IID_INetworkEvents)) { + *ppvObject = (INetworkEvents *)this; + } else { + hr = E_NOINTERFACE; + } + return hr; + } + + ULONG STDMETHODCALLTYPE AddRef() { return InterlockedIncrement(&lRef); } + + ULONG STDMETHODCALLTYPE Release() { + LONG lAddend = InterlockedDecrement(&lRef); + if (lRef == 0) { + delete this; + } + return lAddend; + } + + HRESULT STDMETHODCALLTYPE NetworkAdded(GUID networkId) { return S_OK; } + + HRESULT STDMETHODCALLTYPE + NetworkConnectivityChanged(GUID networkId, NLM_CONNECTIVITY newConnectivity) { + Callback(); + return S_OK; + } + + HRESULT STDMETHODCALLTYPE NetworkDeleted(GUID networkId) { return S_OK; } + + HRESULT STDMETHODCALLTYPE + NetworkPropertyChanged(GUID networkId, NLM_NETWORK_PROPERTY_CHANGE flags) { + if (flags & NLM_NETWORK_PROPERTY_CHANGE_CONNECTION) { + Callback(); + } + return S_OK; + } + + void Callback() { + assert(pCallback); + pCallback(); + } + +private: + volatile LONG lRef = 1; + NetworkCallback pCallback = nullptr; +}; + +NetworkManager::NetworkManager() {} + +NetworkManager::~NetworkManager() { + StopListen(); + Cleanup(); +} + +bool NetworkManager::Init() { + CoInitialize(NULL); + + HRESULT hr = CoCreateInstance(CLSID_NetworkListManager, NULL, CLSCTX_ALL, + IID_IUnknown, (void **)&pUnknown); + if (SUCCEEDED(hr)) { + hr = pUnknown->QueryInterface(IID_INetworkListManager, + (void **)&pNetworkListManager); + } + return SUCCEEDED(hr); +} + +void NetworkManager::Cleanup() { + if (pNetworkListManager) { + pNetworkListManager->Release(); + pNetworkListManager = NULL; + } + + if (pUnknown) { + pUnknown->Release(); + pUnknown = NULL; + } + + CoUninitialize(); +} + +std::vector NetworkManager::GetConnectedAdapterIds() const { + std::vector adapterIds; + + IEnumNetworkConnections *connections = NULL; + HRESULT hr = pNetworkListManager->GetNetworkConnections(&connections); + if (hr == S_OK) { + while (true) { + INetworkConnection *connection = NULL; + hr = connections->Next(1, &connection, NULL); + if (hr != S_OK) { + break; + } + + VARIANT_BOOL isConnected = VARIANT_FALSE; + hr = connection->get_IsConnectedToInternet(&isConnected); + if (hr == S_OK && isConnected == VARIANT_TRUE) { + GUID guid; + hr = connection->GetAdapterId(&guid); + if (hr == S_OK) { + adapterIds.push_back(std::move(guid)); + } + } + connection->Release(); + } + connections->Release(); + } + + return adapterIds; +} + +ConnectivityType NetworkManager::GetConnectivityType() const { + ULONG bufferSize = 15 * 1024; + ULONG flags = GAA_FLAG_SKIP_UNICAST | GAA_FLAG_SKIP_ANYCAST | + GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | + GAA_FLAG_SKIP_FRIENDLY_NAME; + std::vector buffer(bufferSize); + PIP_ADAPTER_ADDRESSES addresses = + reinterpret_cast(&buffer.front()); + DWORD rc = GetAdaptersAddresses(AF_UNSPEC, flags, 0, addresses, &bufferSize); + if (rc == ERROR_BUFFER_OVERFLOW) { + buffer.resize(bufferSize); + addresses = reinterpret_cast(&buffer.front()); + rc = GetAdaptersAddresses(AF_UNSPEC, flags, 0, addresses, &bufferSize); + } + + if (rc != NO_ERROR) { + return ConnectivityType::None; + } + + std::vector adapterIds = GetConnectedAdapterIds(); + if (adapterIds.empty()) { + return ConnectivityType::None; + } + + std::set connectivities; + for (; addresses != NULL; addresses = addresses->Next) { + NET_LUID luid; + rc = ConvertInterfaceIndexToLuid(addresses->IfIndex, &luid); + if (rc != NO_ERROR) { + continue; + } + + GUID guid; + rc = ConvertInterfaceLuidToGuid(&luid, &guid); + if (rc != NO_ERROR) { + continue; + } + + if (std::find(adapterIds.begin(), adapterIds.end(), guid) != + adapterIds.end()) { + switch (addresses->IfType) { + case IF_TYPE_ETHERNET_CSMACD: + connectivities.insert(ConnectivityType::Ethernet); + break; + default: + connectivities.insert(ConnectivityType::WiFi); + break; + } + } + } + + if (connectivities.find(ConnectivityType::WiFi) != connectivities.end()) { + return ConnectivityType::WiFi; + } + + if (connectivities.find(ConnectivityType::Ethernet) != connectivities.end()) { + return ConnectivityType::Ethernet; + } + + return ConnectivityType::None; +} + +bool NetworkManager::StartListen(NetworkCallback pCallback) { + if (!pCallback || pListener) { + return false; + } + + HRESULT hr = pNetworkListManager->QueryInterface( + IID_IConnectionPointContainer, (void **)&pCPContainer); + if (SUCCEEDED(hr)) { + hr = pCPContainer->FindConnectionPoint(IID_INetworkEvents, &pConnectPoint); + if (SUCCEEDED(hr)) { + pListener = new NetworkListener(pCallback); + hr = pConnectPoint->Advise((IUnknown *)pListener, &dwCookie); + if (SUCCEEDED(hr)) { + return true; + } + } + } + return false; +} + +void NetworkManager::StopListen() { + if (pConnectPoint) { + pConnectPoint->Unadvise(dwCookie); + pConnectPoint->Release(); + pConnectPoint = NULL; + dwCookie = 0; + } + + if (pCPContainer) { + pCPContainer->Release(); + pCPContainer = NULL; + } + + if (pListener) { + pListener->Release(); + pListener = NULL; + } +} + +bool NetworkManager::HasError() const { return GetLastError() != 0; } + +int NetworkManager::GetError() const { return GetLastError(); } diff --git a/lib/third_party/connectivity_plus/connectivity_plus_platform_interface/.gitattributes b/lib/third_party/connectivity_plus/connectivity_plus_platform_interface/.gitattributes new file mode 100644 index 00000000..31fda4bf --- /dev/null +++ b/lib/third_party/connectivity_plus/connectivity_plus_platform_interface/.gitattributes @@ -0,0 +1,25 @@ +# Auto detect text files and perform LF normalization +* text=auto + +# Always perform LF normalization on these files +*.dart text +*.gradle text +*.html text +*.java text +*.json text +*.md text +*.py text +*.sh text +*.txt text +*.xml text +*.yaml text + +# Make sure that these Windows files always have CRLF line endings in checkout +*.bat text eol=crlf +*.ps1 text eol=crlf + +# Never perform LF normalization on these files +*.ico binary +*.jar binary +*.png binary +*.zip binary diff --git a/lib/third_party/connectivity_plus/connectivity_plus_platform_interface/.gitignore b/lib/third_party/connectivity_plus/connectivity_plus_platform_interface/.gitignore new file mode 100644 index 00000000..bfb8a70b --- /dev/null +++ b/lib/third_party/connectivity_plus/connectivity_plus_platform_interface/.gitignore @@ -0,0 +1,46 @@ +.DS_Store +.atom/ +.idea/ +.vscode/ + +.packages +.pub/ +.dart_tool/ +pubspec.lock +flutter_export_environment.sh + +examples/all_plugins/pubspec.yaml + +Podfile +Podfile.lock +Pods/ +.symlinks/ +**/Flutter/App.framework/ +**/Flutter/ephemeral/ +**/Flutter/Flutter.framework/ +**/Flutter/Generated.xcconfig +**/Flutter/flutter_assets/ + +ServiceDefinitions.json +xcuserdata/ +**/DerivedData/ + +local.properties +keystore.properties +.gradle/ +gradlew +gradlew.bat +gradle-wrapper.jar +.flutter-plugins-dependencies +*.iml + +GeneratedPluginRegistrant.h +GeneratedPluginRegistrant.m +GeneratedPluginRegistrant.java +GeneratedPluginRegistrant.swift +build/ +.flutter-plugins + +.project +.classpath +.settings diff --git a/lib/third_party/connectivity_plus/connectivity_plus_platform_interface/CHANGELOG.md b/lib/third_party/connectivity_plus/connectivity_plus_platform_interface/CHANGELOG.md new file mode 100644 index 00000000..c4ae2750 --- /dev/null +++ b/lib/third_party/connectivity_plus/connectivity_plus_platform_interface/CHANGELOG.md @@ -0,0 +1,94 @@ +## 1.2.4 + + - **FIX**: Do not return ConnectivityResult.none on iOS and MacOS with VPN (#1335). + +## 1.2.3 + + - **FIX**: Increase min Flutter version to fix dartPluginClass registration (#1275). + +## 1.2.2 + +- Add missing VPN enum + +## 1.2.1 + +- Update flutter_lints to 2.0.1 +- Update plugin_platform_interface to 2.1.2 +- Fix analyzer issues + +## 1.2.0 + +- Add bluetooth as connectivity result + +## 1.1.1 + +- Dependencies update + +## 1.1.0 + +- Add ethernet as connectivity result + +## 1.0.2 + +- Update connectivity plus + +## 1.0.1 + +- Improve documentation + +## 1.0.0 + +- Migrated to null safety + +## 0.4.1 + +- Address pub score + +## 0.4.0 + +- Removed members that were moved to network_info_plus + +## 0.3.0 + +- Renamed method channel + +## 0.2.0 + +- Transfer to plus-plugins monorepo + +## 0.1.7 + +- Transfer package to Flutter Community under new name `connectivity_plus_platform_interface`. + +## 0.1.6 + +- Update lower bound of dart dependency to 2.1.0. + +## 0.1.5 + +- Remove dart:io Platform checks from the MethodChannel implementation. This is + tripping the analysis of other versions of the plugin. + +## 0.1.4 + +- Bump the minimum Flutter version to 1.12.13+hotfix.5. + +## 0.1.3 + +- Make the pedantic dev_dependency explicit. + +## 0.1.2 + +- Bring ConnectivityResult and LocationAuthorizationStatus enums from the core package. +- Use the above Enums as return values for ConnectivityPlatformInterface methods. +- Modify the MethodChannel implementation so it returns the right types. +- Bring all utility methods, asserts and other logic that is only needed on the MethodChannel implementation from the core package. +- Bring MethodChannel unit tests from core package. + +## 0.1.1 + +- Fix README.md link. + +## 0.1.0 + +- Initial release. diff --git a/lib/third_party/connectivity_plus/connectivity_plus_platform_interface/LICENSE b/lib/third_party/connectivity_plus/connectivity_plus_platform_interface/LICENSE new file mode 100644 index 00000000..687fb496 --- /dev/null +++ b/lib/third_party/connectivity_plus/connectivity_plus_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/lib/third_party/connectivity_plus/connectivity_plus_platform_interface/README.md b/lib/third_party/connectivity_plus/connectivity_plus_platform_interface/README.md new file mode 100644 index 00000000..dfdb11d1 --- /dev/null +++ b/lib/third_party/connectivity_plus/connectivity_plus_platform_interface/README.md @@ -0,0 +1,12 @@ +# Connectivity Plus Platform Interface + +[![Flutter Community: connectivity_plus_platform_interface](https://fluttercommunity.dev/_github/header/connectivity_plus_platform_interface)](https://github.com/fluttercommunity/community) + +[![pub package](https://img.shields.io/pub/v/connectivity_plus_platform_interface.svg)](https://pub.dev/packages/connectivity_plus_platform_interface) + +A common platform interface for [`connectivity_plus`](https://pub.dev/packages/connectivity_plus). + +## Usage + +This package is already included as part of the `connectivity_plus` package dependency, and will +be included when using `connectivity_plus` as normal. diff --git a/lib/third_party/connectivity_plus/connectivity_plus_platform_interface/lib/connectivity_plus_platform_interface.dart b/lib/third_party/connectivity_plus/connectivity_plus_platform_interface/lib/connectivity_plus_platform_interface.dart new file mode 100644 index 00000000..76d98666 --- /dev/null +++ b/lib/third_party/connectivity_plus/connectivity_plus_platform_interface/lib/connectivity_plus_platform_interface.dart @@ -0,0 +1,51 @@ +// 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'; +import 'src/enums.dart'; + +export 'src/enums.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. + static set instance(ConnectivityPlatform instance) { + PlatformInterface.verifyToken(instance, _token); + _instance = instance; + } + + /// Checks the connection status of the device. + Future checkConnectivity() { + throw UnimplementedError('checkConnectivity() has not been implemented.'); + } + + /// Returns a Stream of ConnectivityResults changes. + Stream get onConnectivityChanged { + throw UnimplementedError( + 'get onConnectivityChanged has not been implemented.'); + } +} diff --git a/lib/third_party/connectivity_plus/connectivity_plus_platform_interface/lib/method_channel_connectivity.dart b/lib/third_party/connectivity_plus/connectivity_plus_platform_interface/lib/method_channel_connectivity.dart new file mode 100644 index 00000000..1c053d91 --- /dev/null +++ b/lib/third_party/connectivity_plus/connectivity_plus_platform_interface/lib/method_channel_connectivity.dart @@ -0,0 +1,43 @@ +// 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:connectivity_plus_platform_interface/connectivity_plus_platform_interface.dart'; +import 'package:flutter/services.dart'; +import 'package:meta/meta.dart'; + +import 'src/utils.dart'; + +/// An implementation of [ConnectivityPlatform] that uses method channels. +class MethodChannelConnectivity extends ConnectivityPlatform { + /// The method channel used to interact with the native platform. + @visibleForTesting + MethodChannel methodChannel = + const MethodChannel('dev.fluttercommunity.plus/connectivity'); + + /// The event channel used to receive ConnectivityResult changes from the native platform. + @visibleForTesting + EventChannel eventChannel = + const EventChannel('dev.fluttercommunity.plus/connectivity_status'); + + Stream? _onConnectivityChanged; + + /// Fires whenever the connectivity state changes. + @override + Stream get onConnectivityChanged { + _onConnectivityChanged ??= eventChannel + .receiveBroadcastStream() + .map((dynamic result) => result.toString()) + .map(parseConnectivityResult); + return _onConnectivityChanged!; + } + + @override + Future checkConnectivity() { + return methodChannel + .invokeMethod('check') + .then((value) => parseConnectivityResult(value ?? '')); + } +} diff --git a/lib/third_party/connectivity_plus/connectivity_plus_platform_interface/lib/src/enums.dart b/lib/third_party/connectivity_plus/connectivity_plus_platform_interface/lib/src/enums.dart new file mode 100644 index 00000000..7f586995 --- /dev/null +++ b/lib/third_party/connectivity_plus/connectivity_plus_platform_interface/lib/src/enums.dart @@ -0,0 +1,27 @@ +/// Connection status check result. +enum ConnectivityResult { + /// Bluetooth: Device connected via bluetooth + bluetooth, + + /// WiFi: Device connected via Wi-Fi + wifi, + + /// Ethernet: Device connected to ethernet network + ethernet, + + /// Mobile: Device connected to cellular network + mobile, + + /// None: Device not connected to any network + none, + + /// VPN: Device connected to a VPN + /// + /// Note for iOS and macOS: + /// There is no separate network interface type for [vpn]. + /// It returns [other] on any device (also simulator). + vpn, + + /// Other: Device is connected to an unknown network + other +} diff --git a/lib/third_party/connectivity_plus/connectivity_plus_platform_interface/lib/src/utils.dart b/lib/third_party/connectivity_plus/connectivity_plus_platform_interface/lib/src/utils.dart new file mode 100644 index 00000000..4032537d --- /dev/null +++ b/lib/third_party/connectivity_plus/connectivity_plus_platform_interface/lib/src/utils.dart @@ -0,0 +1,22 @@ +import 'package:connectivity_plus_platform_interface/connectivity_plus_platform_interface.dart'; + +/// Convert a String to a ConnectivityResult value. +ConnectivityResult parseConnectivityResult(String state) { + switch (state) { + case 'bluetooth': + return ConnectivityResult.bluetooth; + case 'wifi': + return ConnectivityResult.wifi; + case 'ethernet': + return ConnectivityResult.ethernet; + case 'mobile': + return ConnectivityResult.mobile; + case 'vpn': + return ConnectivityResult.vpn; + case 'other': + return ConnectivityResult.other; + case 'none': + default: + return ConnectivityResult.none; + } +} diff --git a/lib/third_party/connectivity_plus/connectivity_plus_platform_interface/pubspec.yaml b/lib/third_party/connectivity_plus/connectivity_plus_platform_interface/pubspec.yaml new file mode 100644 index 00000000..8c4c5efa --- /dev/null +++ b/lib/third_party/connectivity_plus/connectivity_plus_platform_interface/pubspec.yaml @@ -0,0 +1,20 @@ +name: connectivity_plus_platform_interface +description: A common platform interface for the connectivity_plus plugin. +version: 1.2.4 +homepage: https://plus.fluttercommunity.dev/ +repository: https://github.com/fluttercommunity/plus_plugins/tree/main/packages/ + +environment: + sdk: ">=2.12.0 <3.0.0" + flutter: ">=2.11.0" + +dependencies: + flutter: + sdk: flutter + meta: ^1.7.0 + plugin_platform_interface: ^2.1.2 + +dev_dependencies: + flutter_test: + sdk: flutter + flutter_lints: ^2.0.1 diff --git a/lib/third_party/nm/LICENSE b/lib/third_party/nm/LICENSE new file mode 100644 index 00000000..14e2f777 --- /dev/null +++ b/lib/third_party/nm/LICENSE @@ -0,0 +1,373 @@ +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/lib/third_party/nm/nm.dart b/lib/third_party/nm/nm.dart new file mode 100644 index 00000000..7d74ec95 --- /dev/null +++ b/lib/third_party/nm/nm.dart @@ -0,0 +1 @@ +export 'src/network_manager_client.dart'; diff --git a/lib/third_party/nm/src/network_manager_client.dart b/lib/third_party/nm/src/network_manager_client.dart new file mode 100644 index 00000000..d9b9ff19 --- /dev/null +++ b/lib/third_party/nm/src/network_manager_client.dart @@ -0,0 +1,403 @@ +import 'dart:async'; + +import 'package:dbus/dbus.dart'; + +/// D-Bus interface names +const _managerInterfaceName = 'org.freedesktop.NetworkManager'; + +/// Overall networking states. +enum NetworkManagerState { + unknown, + asleep, + disconnected, + disconnecting, + connecting, + connectedLocal, + connectedSite, + connectedGlobal, +} + +NetworkManagerState _decodeState(int value) { + switch (value) { + case 10: + return NetworkManagerState.asleep; + case 20: + return NetworkManagerState.disconnected; + case 30: + return NetworkManagerState.disconnecting; + case 40: + return NetworkManagerState.connecting; + case 50: + return NetworkManagerState.connectedLocal; + case 60: + return NetworkManagerState.connectedSite; + case 70: + return NetworkManagerState.connectedGlobal; + default: + return NetworkManagerState.unknown; + } +} + +/// Internet connectivity states. +enum NetworkManagerConnectivityState { unknown, none, portal, limited, full } + +NetworkManagerConnectivityState _decodeConnectivityState(int value) { + switch (value) { + case 1: + return NetworkManagerConnectivityState.none; + case 2: + return NetworkManagerConnectivityState.portal; + case 3: + return NetworkManagerConnectivityState.limited; + case 4: + return NetworkManagerConnectivityState.full; + default: + return NetworkManagerConnectivityState.unknown; + } +} + +class _NetworkManagerInterface { + final Map properties; + final propertiesChangedStreamController = + StreamController>.broadcast(); + + /// Stream of property names as their values change. + Stream> get propertiesChanged => + propertiesChangedStreamController.stream; + + _NetworkManagerInterface(this.properties); + + void updateProperties(Map changedProperties) { + properties.addAll(changedProperties); + propertiesChangedStreamController.add(changedProperties.keys.toList()); + } +} + +class _NetworkManagerObject extends DBusRemoteObject { + final interfaces = {}; + + void updateInterfaces( + Map> interfacesAndProperties) { + interfacesAndProperties.forEach((interfaceName, properties) { + interfaces[interfaceName] = _NetworkManagerInterface(properties); + }); + } + + /// Returns true if removing [interfaceNames] would remove all interfaces on this object. + bool wouldRemoveAllInterfaces(List interfaceNames) { + for (var interface in interfaces.keys) { + if (!interfaceNames.contains(interface)) { + return false; + } + } + return true; + } + + void removeInterfaces(List interfaceNames) { + for (var interfaceName in interfaceNames) { + interfaces.remove(interfaceName); + } + } + + void updateProperties( + String interfaceName, Map changedProperties) { + var interface = interfaces[interfaceName]; + if (interface != null) { + interface.updateProperties(changedProperties); + } + } + + /// Gets a cached property. + DBusValue? getCachedProperty(String interfaceName, String name) { + var interface = interfaces[interfaceName]; + if (interface == null) { + return null; + } + return interface.properties[name]; + } + + /// Gets a cached boolean property, or returns null if not present or not the correct type. + bool? getBooleanProperty(String interface, String name) { + var value = getCachedProperty(interface, name); + if (value == null) { + return null; + } + if (value.signature != DBusSignature('b')) { + return null; + } + return (value as DBusBoolean).value; + } + + /// Gets a cached unsigned 8 bit integer property, or returns null if not present or not the correct type. + int? getByteProperty(String interface, String name) { + var value = getCachedProperty(interface, name); + if (value == null) { + return null; + } + if (value.signature != DBusSignature('y')) { + return null; + } + return (value as DBusByte).value; + } + + /// Gets a cached signed 32 bit integer property, or returns null if not present or not the correct type. + int? getInt32Property(String interface, String name) { + var value = getCachedProperty(interface, name); + if (value == null) { + return null; + } + if (value.signature != DBusSignature('i')) { + return null; + } + return (value as DBusInt32).value; + } + + /// Gets a cached unsigned 32 bit integer property, or returns null if not present or not the correct type. + int? getUint32Property(String interface, String name) { + var value = getCachedProperty(interface, name); + if (value == null) { + return null; + } + if (value.signature != DBusSignature('u')) { + return null; + } + return (value as DBusUint32).value; + } + + /// Gets a cached signed 64 bit integer property, or returns null if not present or not the correct type. + int? getInt64Property(String interface, String name) { + var value = getCachedProperty(interface, name); + if (value == null) { + return null; + } + if (value.signature != DBusSignature('x')) { + return null; + } + return (value as DBusInt64).value; + } + + /// Gets a cached unsigned 64 bit integer property, or returns null if not present or not the correct type. + int? getUint64Property(String interface, String name) { + var value = getCachedProperty(interface, name); + if (value == null) { + return null; + } + if (value.signature != DBusSignature('t')) { + return null; + } + return (value as DBusUint64).value; + } + + /// Gets a cached string property, or returns null if not present or not the correct type. + String? getStringProperty(String interface, String name) { + var value = getCachedProperty(interface, name); + if (value == null) { + return null; + } + if (value.signature != DBusSignature('s')) { + return null; + } + return (value as DBusString).value; + } + + /// Gets a cached string array property, or returns null if not present or not the correct type. + List? getStringArrayProperty(String interface, String name) { + var value = getCachedProperty(interface, name); + if (value == null) { + return null; + } + if (value.signature != DBusSignature('as')) { + return null; + } + return (value as DBusArray) + .children + .map((e) => (e as DBusString).value) + .toList(); + } + + /// Gets a cached object path property, or returns null if not present or not the correct type. + DBusObjectPath? getObjectPathProperty(String interface, String name) { + var value = getCachedProperty(interface, name); + if (value == null) { + return null; + } + if (value.signature != DBusSignature('o')) { + return null; + } + return (value as DBusObjectPath); + } + + /// Gets a cached object path array property, or returns null if not present or not the correct type. + List? getObjectPathArrayProperty( + String interface, String name) { + var value = getCachedProperty(interface, name); + if (value == null) { + return null; + } + if (value.signature != DBusSignature('ao')) { + return null; + } + return (value as DBusArray) + .children + .map((e) => (e as DBusObjectPath)) + .toList(); + } + + /// Gets a cached list of data property, or returns null if not present or not the correct type. + List>? getDataListProperty( + String interface, String name) { + var value = getCachedProperty(interface, name); + if (value == null) { + return null; + } + if (value.signature != DBusSignature('aa{sv}')) { + return null; + } + Map convertData(DBusValue value) { + return (value as DBusDict).children.map((key, value) => MapEntry( + (key as DBusString).value, + (value as DBusVariant).value.toNative(), + )); + } + + return (value as DBusArray) + .children + .map((value) => convertData(value)) + .toList(); + } + + _NetworkManagerObject(DBusClient client, DBusObjectPath path, + Map> interfacesAndProperties) + : super(client, name: 'org.freedesktop.NetworkManager', path: path) { + updateInterfaces(interfacesAndProperties); + } +} + +/// A client that connects to NetworkManager. +class NetworkManagerClient { + + /// The bus this client is connected to. + final DBusClient _bus; + final bool _closeBus; + + /// The root D-Bus NetworkManager object at path '/org/freedesktop'. + late final DBusRemoteObjectManager _root; + + // Objects exported on the bus. + final _objects = {}; + + // Subscription to object manager signals. + StreamSubscription? _objectManagerSubscription; + + /// Creates a new NetworkManager client connected to the system D-Bus. + NetworkManagerClient({DBusClient? bus}) + : _bus = bus ?? DBusClient.system(), + _closeBus = bus == null { + _root = DBusRemoteObjectManager( + _bus, + name: 'org.freedesktop.NetworkManager', + path: DBusObjectPath('/org/freedesktop'), + ); + } + + /// Stream of property names as their values change. + Stream> get propertiesChanged => + _manager?.interfaces[_managerInterfaceName] + ?.propertiesChangedStreamController.stream ?? + Stream>.empty(); + + /// Connects to the NetworkManager D-Bus objects. + /// Must be called before accessing methods and properties. + Future connect() async { + // Already connected + if (_objectManagerSubscription != null) { + return; + } + + // Subscribe to changes + _objectManagerSubscription = _root.signals.listen((signal) { + if (signal is DBusObjectManagerInterfacesAddedSignal) { + var object = _objects[signal.changedPath]; + if (object != null) { + object.updateInterfaces(signal.interfacesAndProperties); + } else { + object = _NetworkManagerObject( + _bus, signal.changedPath, signal.interfacesAndProperties); + _objects[signal.changedPath] = object; + } + } else if (signal is DBusObjectManagerInterfacesRemovedSignal) { + var object = _objects[signal.changedPath]; + if (object != null) { + // If all the interface are removed, then this object has been removed. + // Keep the previous values around for the client to use. + if (object.wouldRemoveAllInterfaces(signal.interfaces)) { + _objects.remove(signal.changedPath); + } else { + object.removeInterfaces(signal.interfaces); + } + } + } else if (signal is DBusPropertiesChangedSignal) { + var object = _objects[signal.path]; + if (object != null) { + object.updateProperties( + signal.propertiesInterface, signal.changedProperties); + } + } + }); + + // Find all the objects exported. + var objects = await _root.getManagedObjects(); + objects.forEach((objectPath, interfacesAndProperties) { + _objects[objectPath] = + _NetworkManagerObject(_bus, objectPath, interfacesAndProperties); + }); + } + + /// The type of connection being used to access the network. + String get primaryConnectionType { + return _manager?.getStringProperty( + _managerInterfaceName, + 'PrimaryConnectionType', + ) ?? + ''; + } + + /// True is NetworkManager is still starting up. + bool get startup { + return _manager?.getBooleanProperty(_managerInterfaceName, 'Startup') ?? + false; + } + + /// The version of NetworkManager running. + String get version { + return _manager?.getStringProperty(_managerInterfaceName, 'Version') ?? ''; + } + + /// The result of the last connectivity check. + NetworkManagerConnectivityState get connectivity { + var value = + _manager?.getUint32Property(_managerInterfaceName, 'Connectivity') ?? 0; + return _decodeConnectivityState(value); + } + + /// The overall networking state. + NetworkManagerState get state { + var value = + _manager?.getUint32Property(_managerInterfaceName, 'State') ?? 0; + return _decodeState(value); + } + + _NetworkManagerObject? get _manager => + _objects[DBusObjectPath('/org/freedesktop/NetworkManager')]; + + /// Terminates all active connections. If a client remains unclosed, the Dart process may not terminate. + Future close() async { + if (_objectManagerSubscription != null) { + await _objectManagerSubscription!.cancel(); + _objectManagerSubscription = null; + } + if (_closeBus) { + await _bus.close(); + } + } +} \ No newline at end of file From 25aa6bd9f427f27363b2b542919c70e2112c2cb6 Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Tue, 2 May 2023 12:29:41 -0500 Subject: [PATCH 2/7] add connectivity_plus listener to restart ACN/tor when network comes back up --- lib/main.dart | 21 ++++++++ macos/Flutter/GeneratedPluginRegistrant.swift | 2 + pubspec.lock | 53 +++++++++++++------ pubspec.yaml | 5 ++ .../flutter/generated_plugin_registrant.cc | 3 ++ windows/flutter/generated_plugins.cmake | 1 + 6 files changed, 70 insertions(+), 15 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 449b4026..9515f33a 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,3 +1,4 @@ +import 'dart:async'; import 'dart:convert'; import 'package:cwtch/config.dart'; import 'package:cwtch/notification_manager.dart'; @@ -29,6 +30,8 @@ import 'views/splashView.dart'; import 'dart:io' show Platform, exit; import 'themes/opaque.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:connectivity_plus/connectivity_plus.dart'; + import 'package:intl/intl.dart' as intl; @@ -53,6 +56,8 @@ class Flwtch extends StatefulWidget { FlwtchState createState() => FlwtchState(); } +enum ConnectivityState { assumed_online, confirmed_offline, confirmed_online } + class FlwtchState extends State with WindowListener { final TextStyle biggerFont = const TextStyle(fontSize: 18); late Cwtch cwtch; @@ -60,6 +65,8 @@ class FlwtchState extends State with WindowListener { final MethodChannel notificationClickChannel = MethodChannel('im.cwtch.flwtch/notificationClickHandler'); final MethodChannel shutdownMethodChannel = MethodChannel('im.cwtch.flwtch/shutdownClickHandler'); final MethodChannel shutdownLinuxMethodChannel = MethodChannel('im.cwtch.linux.shutdown'); + late StreamSubscription connectivityStream; + ConnectivityState connectivityState = ConnectivityState.assumed_online; final GlobalKey navKey = GlobalKey(); @@ -99,6 +106,19 @@ class FlwtchState extends State with WindowListener { new CwtchNotifier(profs, globalSettings, globalErrorHandler, globalTorStatus, newDesktopNotificationsManager(_notificationSelectConvo), globalAppState, globalServersList, this); cwtch = CwtchFfi(cwtchNotifier); } + connectivityStream = Connectivity().onConnectivityChanged.listen((ConnectivityResult result) { + // Got a new connectivity status! + if (result == ConnectivityResult.none) { + connectivityState = ConnectivityState.confirmed_offline; + } else { + // were we offline? + if (connectivityState == ConnectivityState.confirmed_offline) { + EnvironmentConfig.debugLog("Network appears to have come back online, restarting Tor"); + cwtch.ResetTor(); + } + connectivityState = ConnectivityState.confirmed_online; + } + }); print("initState: invoking cwtch.Start()"); cwtch.Start(); print("initState: done!"); @@ -275,6 +295,7 @@ class FlwtchState extends State with WindowListener { cwtch.Shutdown(); windowManager.removeListener(this); cwtch.dispose(); + connectivityStream.cancel(); super.dispose(); } } diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index dcf1815c..3dbcbd23 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,6 +5,7 @@ import FlutterMacOS import Foundation +import connectivity_plus import flutter_local_notifications import package_info_plus_macos import path_provider_foundation @@ -13,6 +14,7 @@ import url_launcher_macos import window_manager func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + ConnectivityPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlugin")) FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin")) FLTPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlusPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) diff --git a/pubspec.lock b/pubspec.lock index 2dd65711..7eb708ce 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,18 +5,18 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: "4897882604d919befd350648c7f91926a9d5de99e67b455bf0917cc2362f4bb8" + sha256: "4826f97faae3af9761f26c52e56b2aa5ffd18d2c1721d984ad85137721c25f43" url: "https://pub.dev" source: hosted - version: "47.0.0" + version: "31.0.0" analyzer: dependency: transitive description: name: analyzer - sha256: "690e335554a8385bc9d787117d9eb52c0c03ee207a607e593de3c9d71b1cfe80" + sha256: "7337610c3f9cd13e6b7c6bb0f410644091cf63c9a1436e73352a70f3286abb03" url: "https://pub.dev" source: hosted - version: "4.7.0" + version: "2.8.0" archive: dependency: transitive description: @@ -77,18 +77,18 @@ packages: dependency: transitive description: name: build_resolvers - sha256: "687cf90a3951affac1bd5f9ecb5e3e90b60487f3d9cdc359bb310f8876bb02a6" + sha256: "4666aef1d045c5ca15ebba63e400bd4e4fbd9f0dd06e791b51ab210da78a27f7" url: "https://pub.dev" source: hosted - version: "2.0.10" + version: "2.0.6" build_runner: dependency: "direct dev" description: name: build_runner - sha256: b0a8a7b8a76c493e85f1b84bffa0588859a06197863dba8c9036b15581fd9727 + sha256: "56942f8114731d1e79942cd981cfef29501937ff1bccf4dbdce0273f31f13640" url: "https://pub.dev" source: hosted - version: "2.3.3" + version: "2.2.0" build_runner_core: dependency: transitive description: @@ -161,6 +161,21 @@ packages: url: "https://pub.dev" source: hosted version: "1.17.0" + connectivity_plus: + dependency: "direct main" + description: + path: "lib/third_party/connectivity_plus/connectivity_plus" + relative: true + source: path + version: "3.0.6" + connectivity_plus_platform_interface: + dependency: transitive + description: + name: connectivity_plus_platform_interface + sha256: cf1d1c28f4416f8c654d7dc3cd638ec586076255d407cef3ddbdaf178272a71a + url: "https://pub.dev" + source: hosted + version: "1.2.4" console: dependency: transitive description: @@ -197,12 +212,12 @@ packages: dependency: transitive description: name: dart_style - sha256: "7a03456c3490394c8e7665890333e91ae8a49be43542b616e414449ac358acd4" + sha256: "6e8086e1d3c2f6bc15056ee248c4ddc48c2bc71287c0961bf801a08633ed4333" url: "https://pub.dev" source: hosted - version: "2.2.4" + version: "2.2.1" dbus: - dependency: transitive + dependency: "direct main" description: name: dbus sha256: "253bfaa3d340778d8bc755e89c3af38e85ef95e65fd5d5670aa3167f8d4f6577" @@ -335,10 +350,10 @@ packages: dependency: transitive description: name: frontend_server_client - sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" + sha256: "4f4a162323c86ffc1245765cfe138872b8f069deb42f7dbb36115fa27f31469b" url: "https://pub.dev" source: hosted - version: "3.2.0" + version: "2.1.3" fuchsia_remote_debug_protocol: dependency: transitive description: flutter @@ -501,6 +516,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.0" + nm: + dependency: transitive + description: + name: nm + sha256: "2c9aae4127bdc8993206464fcc063611e0e36e72018696cd9631023a31b24254" + url: "https://pub.dev" + source: hosted + version: "0.5.0" package_config: dependency: transitive description: @@ -734,10 +757,10 @@ packages: dependency: transitive description: name: source_gen - sha256: "2d79738b6bbf38a43920e2b8d189e9a3ce6cc201f4b8fc76be5e4fe377b1c38d" + sha256: "00f8b6b586f724a8c769c96f1d517511a41661c0aede644544d8d86a1ab11142" url: "https://pub.dev" source: hosted - version: "1.2.6" + version: "1.2.2" source_span: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 6a230d00..71cca820 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -46,6 +46,11 @@ dependencies: win_toast: ^0.0.2 flutter_local_notifications: ^9.6.1 desktop_notifications: ^0.6.3 + # network management plugins + dbus: ^0.7.0 + connectivity_plus: + path: lib/third_party/connectivity_plus/connectivity_plus + # misc plugins qr_flutter: ^4.0.0 dev_dependencies: diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index c253d427..b4b9a696 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -6,12 +6,15 @@ #include "generated_plugin_registrant.h" +#include #include #include #include #include void RegisterPlugins(flutter::PluginRegistry* registry) { + ConnectivityPlusWindowsPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("ConnectivityPlusWindowsPlugin")); ScreenRetrieverPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("ScreenRetrieverPlugin")); UrlLauncherWindowsRegisterWithRegistrar( diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index 22680c99..427d1281 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -3,6 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST + connectivity_plus screen_retriever url_launcher_windows win_toast From ecde4414805f173cc334759fa0f7b682d5bb6b87 Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Tue, 2 May 2023 12:35:41 -0500 Subject: [PATCH 3/7] lcg bump --- LIBCWTCH-GO.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LIBCWTCH-GO.version b/LIBCWTCH-GO.version index cdb3ccd8..9259fe11 100644 --- a/LIBCWTCH-GO.version +++ b/LIBCWTCH-GO.version @@ -1 +1 @@ -2023-05-09-13-30-v0.0.3-24-g5b2f3cf \ No newline at end of file +2023-05-09-13-30-v0.0.3-24-g5b2f3cf From f9965906833186f653ea54059354dafbd1e287d5 Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Wed, 3 May 2023 09:52:17 -0500 Subject: [PATCH 4/7] fix version downgrades; remove internet specificity; update licenses --- .../gradle/wrapper/gradle-wrapper.properties | 2 + lib/licenses.dart | 410 ++++++++++++++++++ .../connectivity_plus/README.md | 2 + .../gradle/wrapper/gradle-wrapper.properties | 2 +- .../plus/connectivity/Connectivity.java | 25 +- .../lib/src/connectivity_plus_linux.dart | 13 +- .../src/web/utils/connectivity_result.dart | 5 +- .../CHANGELOG.md | 94 ---- .../lib/src/enums.dart | 9 - .../lib/src/utils.dart | 7 +- pubspec.lock | 35 +- pubspec.yaml | 3 +- 12 files changed, 435 insertions(+), 172 deletions(-) delete mode 100644 lib/third_party/connectivity_plus/connectivity_plus_platform_interface/CHANGELOG.md diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index a5210939..42a7a584 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,7 @@ #Mon Jun 20 10:33:21 PDT 2022 distributionBase=GRADLE_USER_HOME +# third party plugin connectivity_plus should match, so when updating, also update +# lib/third_party/connectivity_plus/connectivity_plus/android/gradle/wrapper/gradle-wrapper.properties distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip distributionPath=wrapper/dists zipStorePath=wrapper/dists diff --git a/lib/licenses.dart b/lib/licenses.dart index c1cc96e0..6c0e9903 100644 --- a/lib/licenses.dart +++ b/lib/licenses.dart @@ -139,6 +139,416 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.'''); + yield LicenseEntryWithLineBreaks(["connectivity_plus", "connectivity_plus_platform_interface"], ''' + Copyright 2017 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.'''); + + yield LicenseEntryWithLineBreaks(["connectivity_plus"], ''' + * Copyright (c) 2013-2020, The PurpleI2P Project + * + * This file is part of Purple i2pd project and licensed under BSD3 + * + * See full license text in LICENSE file at top of project tree'''); + + yield LicenseEntryWithLineBreaks(["nm"], '''Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0.'''); + yield LicenseEntryWithLineBreaks(["Roboto fonts"], ''' Apache License diff --git a/lib/third_party/connectivity_plus/connectivity_plus/README.md b/lib/third_party/connectivity_plus/connectivity_plus/README.md index 8e5b2956..ffdfb29b 100644 --- a/lib/third_party/connectivity_plus/connectivity_plus/README.md +++ b/lib/third_party/connectivity_plus/connectivity_plus/README.md @@ -1,5 +1,7 @@ # connectivity_plus +- Open Privacy has updated this package to use local and stripped down version of `nm` package + [![Flutter Community: connectivity_plus](https://fluttercommunity.dev/_github/header/connectivity_plus)](https://github.com/fluttercommunity/community) [![pub package](https://img.shields.io/pub/v/connectivity_plus.svg)](https://pub.dev/packages/connectivity_plus) diff --git a/lib/third_party/connectivity_plus/connectivity_plus/android/gradle/wrapper/gradle-wrapper.properties b/lib/third_party/connectivity_plus/connectivity_plus/android/gradle/wrapper/gradle-wrapper.properties index 62dbe3c1..477dc87d 100644 --- a/lib/third_party/connectivity_plus/connectivity_plus/android/gradle/wrapper/gradle-wrapper.properties +++ b/lib/third_party/connectivity_plus/connectivity_plus/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip distributionPath=wrapper/dists zipStorePath=wrapper/dists zipStoreBase=GRADLE_USER_HOME diff --git a/lib/third_party/connectivity_plus/connectivity_plus/android/src/main/java/dev/fluttercommunity/plus/connectivity/Connectivity.java b/lib/third_party/connectivity_plus/connectivity_plus/android/src/main/java/dev/fluttercommunity/plus/connectivity/Connectivity.java index 02a316bc..7ae7d009 100644 --- a/lib/third_party/connectivity_plus/connectivity_plus/android/src/main/java/dev/fluttercommunity/plus/connectivity/Connectivity.java +++ b/lib/third_party/connectivity_plus/connectivity_plus/android/src/main/java/dev/fluttercommunity/plus/connectivity/Connectivity.java @@ -12,11 +12,7 @@ import android.os.Build; /** Reports connectivity related information such as connectivity type and wifi information. */ public class Connectivity { static final String CONNECTIVITY_NONE = "none"; - static final String CONNECTIVITY_WIFI = "wifi"; static final String CONNECTIVITY_MOBILE = "mobile"; - static final String CONNECTIVITY_ETHERNET = "ethernet"; - static final String CONNECTIVITY_BLUETOOTH = "bluetooth"; - static final String CONNECTIVITY_VPN = "vpn"; private final ConnectivityManager connectivityManager; public Connectivity(ConnectivityManager connectivityManager) { @@ -30,21 +26,8 @@ public class Connectivity { if (capabilities == null) { return CONNECTIVITY_NONE; } - if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) { - return CONNECTIVITY_WIFI; - } - if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)) { - return CONNECTIVITY_ETHERNET; - } - if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN)) { - return CONNECTIVITY_VPN; - } - if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) { - return CONNECTIVITY_MOBILE; - } - if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH)) { - return CONNECTIVITY_BLUETOOTH; - } + // Cwtch UI only needs to know if online or offline, not type + return CONNECTIVITY_MOBILE; } return getNetworkTypeLegacy(); @@ -60,14 +43,10 @@ public class Connectivity { int type = info.getType(); switch (type) { case ConnectivityManager.TYPE_BLUETOOTH: - return CONNECTIVITY_BLUETOOTH; case ConnectivityManager.TYPE_ETHERNET: - return CONNECTIVITY_ETHERNET; case ConnectivityManager.TYPE_WIFI: case ConnectivityManager.TYPE_WIMAX: - return CONNECTIVITY_WIFI; case ConnectivityManager.TYPE_VPN: - return CONNECTIVITY_VPN; case ConnectivityManager.TYPE_MOBILE: case ConnectivityManager.TYPE_MOBILE_DUN: case ConnectivityManager.TYPE_MOBILE_HIPRI: diff --git a/lib/third_party/connectivity_plus/connectivity_plus/lib/src/connectivity_plus_linux.dart b/lib/third_party/connectivity_plus/connectivity_plus/lib/src/connectivity_plus_linux.dart index bca6cdfe..e2625137 100644 --- a/lib/third_party/connectivity_plus/connectivity_plus/lib/src/connectivity_plus_linux.dart +++ b/lib/third_party/connectivity_plus/connectivity_plus/lib/src/connectivity_plus_linux.dart @@ -44,18 +44,7 @@ class ConnectivityPlusLinuxPlugin extends ConnectivityPlatform { if (client.connectivity != NetworkManagerConnectivityState.full) { return ConnectivityResult.none; } - if (client.primaryConnectionType.contains('wireless')) { - return ConnectivityResult.wifi; - } - if (client.primaryConnectionType.contains('ethernet')) { - return ConnectivityResult.ethernet; - } - if (client.primaryConnectionType.contains('vpn')) { - return ConnectivityResult.vpn; - } - if (client.primaryConnectionType.contains('bluetooth')) { - return ConnectivityResult.bluetooth; - } + // Open privacy update: we only need online/offline, so deleting type specificity return ConnectivityResult.mobile; } diff --git a/lib/third_party/connectivity_plus/connectivity_plus/lib/src/web/utils/connectivity_result.dart b/lib/third_party/connectivity_plus/connectivity_plus/lib/src/web/utils/connectivity_result.dart index 004cba81..1b64b69c 100644 --- a/lib/third_party/connectivity_plus/connectivity_plus/lib/src/web/utils/connectivity_result.dart +++ b/lib/third_party/connectivity_plus/connectivity_plus/lib/src/web/utils/connectivity_result.dart @@ -39,15 +39,12 @@ ConnectivityResult _typeToConnectivityResult(String type) { case 'none': return ConnectivityResult.none; case 'bluetooth': - return ConnectivityResult.bluetooth; case 'cellular': case 'mixed': case 'other': case 'unknown': - return ConnectivityResult.mobile; case 'ethernet': - return ConnectivityResult.ethernet; default: - return ConnectivityResult.wifi; + return ConnectivityResult.mobile; } } diff --git a/lib/third_party/connectivity_plus/connectivity_plus_platform_interface/CHANGELOG.md b/lib/third_party/connectivity_plus/connectivity_plus_platform_interface/CHANGELOG.md deleted file mode 100644 index c4ae2750..00000000 --- a/lib/third_party/connectivity_plus/connectivity_plus_platform_interface/CHANGELOG.md +++ /dev/null @@ -1,94 +0,0 @@ -## 1.2.4 - - - **FIX**: Do not return ConnectivityResult.none on iOS and MacOS with VPN (#1335). - -## 1.2.3 - - - **FIX**: Increase min Flutter version to fix dartPluginClass registration (#1275). - -## 1.2.2 - -- Add missing VPN enum - -## 1.2.1 - -- Update flutter_lints to 2.0.1 -- Update plugin_platform_interface to 2.1.2 -- Fix analyzer issues - -## 1.2.0 - -- Add bluetooth as connectivity result - -## 1.1.1 - -- Dependencies update - -## 1.1.0 - -- Add ethernet as connectivity result - -## 1.0.2 - -- Update connectivity plus - -## 1.0.1 - -- Improve documentation - -## 1.0.0 - -- Migrated to null safety - -## 0.4.1 - -- Address pub score - -## 0.4.0 - -- Removed members that were moved to network_info_plus - -## 0.3.0 - -- Renamed method channel - -## 0.2.0 - -- Transfer to plus-plugins monorepo - -## 0.1.7 - -- Transfer package to Flutter Community under new name `connectivity_plus_platform_interface`. - -## 0.1.6 - -- Update lower bound of dart dependency to 2.1.0. - -## 0.1.5 - -- Remove dart:io Platform checks from the MethodChannel implementation. This is - tripping the analysis of other versions of the plugin. - -## 0.1.4 - -- Bump the minimum Flutter version to 1.12.13+hotfix.5. - -## 0.1.3 - -- Make the pedantic dev_dependency explicit. - -## 0.1.2 - -- Bring ConnectivityResult and LocationAuthorizationStatus enums from the core package. -- Use the above Enums as return values for ConnectivityPlatformInterface methods. -- Modify the MethodChannel implementation so it returns the right types. -- Bring all utility methods, asserts and other logic that is only needed on the MethodChannel implementation from the core package. -- Bring MethodChannel unit tests from core package. - -## 0.1.1 - -- Fix README.md link. - -## 0.1.0 - -- Initial release. diff --git a/lib/third_party/connectivity_plus/connectivity_plus_platform_interface/lib/src/enums.dart b/lib/third_party/connectivity_plus/connectivity_plus_platform_interface/lib/src/enums.dart index 7f586995..53410c07 100644 --- a/lib/third_party/connectivity_plus/connectivity_plus_platform_interface/lib/src/enums.dart +++ b/lib/third_party/connectivity_plus/connectivity_plus_platform_interface/lib/src/enums.dart @@ -1,7 +1,5 @@ /// Connection status check result. enum ConnectivityResult { - /// Bluetooth: Device connected via bluetooth - bluetooth, /// WiFi: Device connected via Wi-Fi wifi, @@ -15,13 +13,6 @@ enum ConnectivityResult { /// None: Device not connected to any network none, - /// VPN: Device connected to a VPN - /// - /// Note for iOS and macOS: - /// There is no separate network interface type for [vpn]. - /// It returns [other] on any device (also simulator). - vpn, - /// Other: Device is connected to an unknown network other } diff --git a/lib/third_party/connectivity_plus/connectivity_plus_platform_interface/lib/src/utils.dart b/lib/third_party/connectivity_plus/connectivity_plus_platform_interface/lib/src/utils.dart index 4032537d..ecb11d23 100644 --- a/lib/third_party/connectivity_plus/connectivity_plus_platform_interface/lib/src/utils.dart +++ b/lib/third_party/connectivity_plus/connectivity_plus_platform_interface/lib/src/utils.dart @@ -4,17 +4,12 @@ import 'package:connectivity_plus_platform_interface/connectivity_plus_platform_ ConnectivityResult parseConnectivityResult(String state) { switch (state) { case 'bluetooth': - return ConnectivityResult.bluetooth; case 'wifi': - return ConnectivityResult.wifi; case 'ethernet': - return ConnectivityResult.ethernet; case 'mobile': - return ConnectivityResult.mobile; case 'vpn': - return ConnectivityResult.vpn; case 'other': - return ConnectivityResult.other; + return ConnectivityResult.mobile; case 'none': default: return ConnectivityResult.none; diff --git a/pubspec.lock b/pubspec.lock index 7eb708ce..fd020d1b 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,18 +5,18 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: "4826f97faae3af9761f26c52e56b2aa5ffd18d2c1721d984ad85137721c25f43" + sha256: "4897882604d919befd350648c7f91926a9d5de99e67b455bf0917cc2362f4bb8" url: "https://pub.dev" source: hosted - version: "31.0.0" + version: "47.0.0" analyzer: dependency: transitive description: name: analyzer - sha256: "7337610c3f9cd13e6b7c6bb0f410644091cf63c9a1436e73352a70f3286abb03" + sha256: "690e335554a8385bc9d787117d9eb52c0c03ee207a607e593de3c9d71b1cfe80" url: "https://pub.dev" source: hosted - version: "2.8.0" + version: "4.7.0" archive: dependency: transitive description: @@ -77,10 +77,10 @@ packages: dependency: transitive description: name: build_resolvers - sha256: "4666aef1d045c5ca15ebba63e400bd4e4fbd9f0dd06e791b51ab210da78a27f7" + sha256: "687cf90a3951affac1bd5f9ecb5e3e90b60487f3d9cdc359bb310f8876bb02a6" url: "https://pub.dev" source: hosted - version: "2.0.6" + version: "2.0.10" build_runner: dependency: "direct dev" description: @@ -171,10 +171,9 @@ packages: connectivity_plus_platform_interface: dependency: transitive description: - name: connectivity_plus_platform_interface - sha256: cf1d1c28f4416f8c654d7dc3cd638ec586076255d407cef3ddbdaf178272a71a - url: "https://pub.dev" - source: hosted + path: "lib/third_party/connectivity_plus/connectivity_plus_platform_interface" + relative: true + source: path version: "1.2.4" console: dependency: transitive @@ -212,10 +211,10 @@ packages: dependency: transitive description: name: dart_style - sha256: "6e8086e1d3c2f6bc15056ee248c4ddc48c2bc71287c0961bf801a08633ed4333" + sha256: "7a03456c3490394c8e7665890333e91ae8a49be43542b616e414449ac358acd4" url: "https://pub.dev" source: hosted - version: "2.2.1" + version: "2.2.4" dbus: dependency: "direct main" description: @@ -516,14 +515,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.0" - nm: - dependency: transitive - description: - name: nm - sha256: "2c9aae4127bdc8993206464fcc063611e0e36e72018696cd9631023a31b24254" - url: "https://pub.dev" - source: hosted - version: "0.5.0" package_config: dependency: transitive description: @@ -757,10 +748,10 @@ packages: dependency: transitive description: name: source_gen - sha256: "00f8b6b586f724a8c769c96f1d517511a41661c0aede644544d8d86a1ab11142" + sha256: "2d79738b6bbf38a43920e2b8d189e9a3ce6cc201f4b8fc76be5e4fe377b1c38d" url: "https://pub.dev" source: hosted - version: "1.2.2" + version: "1.2.6" source_span: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 71cca820..aa609ea0 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -47,7 +47,8 @@ dependencies: flutter_local_notifications: ^9.6.1 desktop_notifications: ^0.6.3 # network management plugins - dbus: ^0.7.0 + # dbus >=0.7.5 depends on ffi ^2.0.0 and cwtch depends on ffi ^1.2.1, dbus >=0.7.5 is forbidden. + dbus: 0.7.4 connectivity_plus: path: lib/third_party/connectivity_plus/connectivity_plus # misc plugins From 4acb6c74c317131484734833d2d0359ceca9061d Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Wed, 3 May 2023 10:58:31 -0500 Subject: [PATCH 5/7] handle connectivity fails (like nm being unavail on build server) more gracefully --- lib/main.dart | 75 ++++++++++++++----- .../nm/src/network_manager_client.dart | 12 +++ pubspec.yaml | 1 + 3 files changed, 70 insertions(+), 18 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 9515f33a..4f3ac855 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -65,7 +65,7 @@ class FlwtchState extends State with WindowListener { final MethodChannel notificationClickChannel = MethodChannel('im.cwtch.flwtch/notificationClickHandler'); final MethodChannel shutdownMethodChannel = MethodChannel('im.cwtch.flwtch/shutdownClickHandler'); final MethodChannel shutdownLinuxMethodChannel = MethodChannel('im.cwtch.linux.shutdown'); - late StreamSubscription connectivityStream; + late StreamSubscription? connectivityStream; ConnectivityState connectivityState = ConnectivityState.assumed_online; final GlobalKey navKey = GlobalKey(); @@ -95,35 +95,74 @@ class FlwtchState extends State with WindowListener { shutdownLinuxMethodChannel.setMethodCallHandler(shutdownDirect); print("initState: creating cwtchnotifier, ffi"); if (Platform.isAndroid) { - var cwtchNotifier = new CwtchNotifier(profs, globalSettings, globalErrorHandler, globalTorStatus, NullNotificationsManager(), globalAppState, globalServersList, this); + var cwtchNotifier = new CwtchNotifier( + profs, + globalSettings, + globalErrorHandler, + globalTorStatus, + NullNotificationsManager(), + globalAppState, + globalServersList, + this); cwtch = CwtchGomobile(cwtchNotifier); } else if (Platform.isLinux) { var cwtchNotifier = - new CwtchNotifier(profs, globalSettings, globalErrorHandler, globalTorStatus, newDesktopNotificationsManager(_notificationSelectConvo), globalAppState, globalServersList, this); + new CwtchNotifier( + profs, + globalSettings, + globalErrorHandler, + globalTorStatus, + newDesktopNotificationsManager(_notificationSelectConvo), + globalAppState, + globalServersList, + this); cwtch = CwtchFfi(cwtchNotifier); } else { var cwtchNotifier = - new CwtchNotifier(profs, globalSettings, globalErrorHandler, globalTorStatus, newDesktopNotificationsManager(_notificationSelectConvo), globalAppState, globalServersList, this); + new CwtchNotifier( + profs, + globalSettings, + globalErrorHandler, + globalTorStatus, + newDesktopNotificationsManager(_notificationSelectConvo), + globalAppState, + globalServersList, + this); cwtch = CwtchFfi(cwtchNotifier); } - connectivityStream = Connectivity().onConnectivityChanged.listen((ConnectivityResult result) { - // Got a new connectivity status! - if (result == ConnectivityResult.none) { - connectivityState = ConnectivityState.confirmed_offline; - } else { - // were we offline? - if (connectivityState == ConnectivityState.confirmed_offline) { - EnvironmentConfig.debugLog("Network appears to have come back online, restarting Tor"); - cwtch.ResetTor(); - } - connectivityState = ConnectivityState.confirmed_online; - } - }); + startConnectivityListener(); print("initState: invoking cwtch.Start()"); cwtch.Start(); print("initState: done!"); } + // connectivity listening is an optional enhancement feature that tries to listen for OS events about the network + // and if it detects coming back online, restarts the ACN/tor + // gracefully fails and NOPs, as it's not a required functionality + startConnectivityListener() async { + try { + connectivityStream = await Connectivity().onConnectivityChanged.listen((ConnectivityResult result) { + // Got a new connectivity status! + if (result == ConnectivityResult.none) { + connectivityState = ConnectivityState.confirmed_offline; + } else { + // were we offline? + if (connectivityState == ConnectivityState.confirmed_offline) { + EnvironmentConfig.debugLog("Network appears to have come back online, restarting Tor"); + cwtch.ResetTor(); + } + connectivityState = ConnectivityState.confirmed_online; + } + }, onError: (Object error) { + print("Error listening to connectivity for network state: {$error}"); + return null; + }, cancelOnError: true); + } catch (e) { + print("Warning: Unable to open connectivity for listening to network state: {$e}"); + connectivityStream = null; + } + } + ChangeNotifierProvider getTorStatusProvider() => ChangeNotifierProvider.value(value: globalTorStatus); ChangeNotifierProvider getErrorHandlerProvider() => ChangeNotifierProvider.value(value: globalErrorHandler); ChangeNotifierProvider getSettingsProvider() => ChangeNotifierProvider.value(value: globalSettings); @@ -295,7 +334,7 @@ class FlwtchState extends State with WindowListener { cwtch.Shutdown(); windowManager.removeListener(this); cwtch.dispose(); - connectivityStream.cancel(); + connectivityStream?.cancel(); super.dispose(); } } diff --git a/lib/third_party/nm/src/network_manager_client.dart b/lib/third_party/nm/src/network_manager_client.dart index d9b9ff19..222c94bf 100644 --- a/lib/third_party/nm/src/network_manager_client.dart +++ b/lib/third_party/nm/src/network_manager_client.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:io'; import 'package:dbus/dbus.dart'; @@ -314,6 +315,17 @@ class NetworkManagerClient { return; } + // Big old grody Hack + // DBus/nm doesnt seem to offer a way to deter ine if dbus is available on system + // worse the first connections get triggered in dbus_client onListen an isn't a catahable exception so crashes the app + // this is a hacky way to force an exception on thread if dbus isn't available and bail with out crashing + try { + await _root.client.getNameOwner(_root.name); + } on SocketException catch (e) { + print("nm dbus connect/emit test threw exception, dbus likely unavailable on system, aborting connect: $e"); + return; + } + // Subscribe to changes _objectManagerSubscription = _root.signals.listen((signal) { if (signal is DBusObjectManagerInterfacesAddedSignal) { diff --git a/pubspec.yaml b/pubspec.yaml index aa609ea0..bdcf7027 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -32,6 +32,7 @@ dependencies: # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.0 + # Todo: upgrade to 2.x, allow other package upgrades (dbus) ffi: ^1.2.1 path_provider: ^2.0.0 crypto: ^3.0.2 From c2e61f7cf7a59dc0d6337144d55b15f2637f91c0 Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Sat, 6 May 2023 22:16:09 -0500 Subject: [PATCH 6/7] build third_party/connectivity_plus for android --- .../connectivity_plus/android/build.gradle | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/third_party/connectivity_plus/connectivity_plus/android/build.gradle b/lib/third_party/connectivity_plus/connectivity_plus/android/build.gradle index e04630a8..448c6e91 100644 --- a/lib/third_party/connectivity_plus/connectivity_plus/android/build.gradle +++ b/lib/third_party/connectivity_plus/connectivity_plus/android/build.gradle @@ -8,7 +8,8 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:7.4.2' + classpath 'com.android.tools.build:gradle:4.1.0' + } } @@ -21,10 +22,12 @@ rootProject.allprojects { apply plugin: 'com.android.library' + android { compileSdkVersion 31 - namespace 'dev.fluttercommunity.plus.connectivity' + // as third_party include, don't need seperate namespace + //namespace 'dev.fluttercommunity.plus.connectivity' compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 @@ -33,9 +36,12 @@ android { defaultConfig { minSdkVersion 16 - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + targetSdkVersion 31 + //testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } lintOptions { disable 'InvalidPackage' + abortOnError false } + } From 9e879d560f307e26ea7a40796fb64d8b4eae7a05 Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Fri, 12 May 2023 11:39:45 -0700 Subject: [PATCH 7/7] remove connecticity plus web code, platform we do not need --- lib/notification_manager.dart | 2 +- .../lib/connectivity_plus.dart | 3 +- .../lib/src/connectivity_plus_web.dart | 27 ------ .../web/dart_html_connectivity_plugin.dart | 35 ------- ...k_information_api_connectivity_plugin.dart | 92 ------------------- .../src/web/utils/connectivity_result.dart | 50 ---------- .../connectivity_plus/pubspec.yaml | 3 - 7 files changed, 2 insertions(+), 210 deletions(-) delete mode 100644 lib/third_party/connectivity_plus/connectivity_plus/lib/src/connectivity_plus_web.dart delete mode 100644 lib/third_party/connectivity_plus/connectivity_plus/lib/src/web/dart_html_connectivity_plugin.dart delete mode 100644 lib/third_party/connectivity_plus/connectivity_plus/lib/src/web/network_information_api_connectivity_plugin.dart delete mode 100644 lib/third_party/connectivity_plus/connectivity_plus/lib/src/web/utils/connectivity_result.dart diff --git a/lib/notification_manager.dart b/lib/notification_manager.dart index 448204d2..00042bcc 100644 --- a/lib/notification_manager.dart +++ b/lib/notification_manager.dart @@ -14,7 +14,7 @@ import 'package:flutter_local_notifications_linux/src/model/icon.dart'; import 'package:path/path.dart' as path; -import '../../config.dart'; +import 'config.dart'; // NotificationsManager provides a wrapper around platform specific notifications logic. abstract class NotificationsManager { diff --git a/lib/third_party/connectivity_plus/connectivity_plus/lib/connectivity_plus.dart b/lib/third_party/connectivity_plus/connectivity_plus/lib/connectivity_plus.dart index 38cf3515..dfba08c3 100644 --- a/lib/third_party/connectivity_plus/connectivity_plus/lib/connectivity_plus.dart +++ b/lib/third_party/connectivity_plus/connectivity_plus/lib/connectivity_plus.dart @@ -10,8 +10,7 @@ import 'package:connectivity_plus_platform_interface/connectivity_plus_platform_ export 'package:connectivity_plus_platform_interface/connectivity_plus_platform_interface.dart' show ConnectivityResult; -export 'src/connectivity_plus_linux.dart' - if (dart.library.html) 'src/connectivity_plus_web.dart'; +export 'src/connectivity_plus_linux.dart'; /// Discover network connectivity configurations: Distinguish between WI-FI and cellular, check WI-FI status and more. class Connectivity { diff --git a/lib/third_party/connectivity_plus/connectivity_plus/lib/src/connectivity_plus_web.dart b/lib/third_party/connectivity_plus/connectivity_plus/lib/src/connectivity_plus_web.dart deleted file mode 100644 index 28c1db1d..00000000 --- a/lib/third_party/connectivity_plus/connectivity_plus/lib/src/connectivity_plus_web.dart +++ /dev/null @@ -1,27 +0,0 @@ -import 'package:connectivity_plus_platform_interface/connectivity_plus_platform_interface.dart'; -import 'package:flutter_web_plugins/flutter_web_plugins.dart'; - -import 'web/network_information_api_connectivity_plugin.dart'; -import 'web/dart_html_connectivity_plugin.dart'; - -/// The web implementation of the ConnectivityPlatform of the Connectivity plugin. -class ConnectivityPlusWebPlugin extends ConnectivityPlatform { - /// Factory method that initializes the connectivity plugin platform with an instance - /// of the plugin for the web. - static void registerWith(Registrar registrar) { - // Since the `NetworkInformationApi` is currently an experimental API and - // does not provide a reliable way to check a connectivity change - // from an onnline state to an offline state, - // its implementation is disabled for now. - // See also: https://developer.mozilla.org/en-US/docs/Web/API/Network_Information_API - // - // TODO: use `NetworkInformationApiConnectivityPlugin.isSupported()` when it becomes a stable DOM API. - const isSupported = false; - - if (isSupported) { - ConnectivityPlatform.instance = NetworkInformationApiConnectivityPlugin(); - } else { - ConnectivityPlatform.instance = DartHtmlConnectivityPlugin(); - } - } -} diff --git a/lib/third_party/connectivity_plus/connectivity_plus/lib/src/web/dart_html_connectivity_plugin.dart b/lib/third_party/connectivity_plus/connectivity_plus/lib/src/web/dart_html_connectivity_plugin.dart deleted file mode 100644 index d5c0c68b..00000000 --- a/lib/third_party/connectivity_plus/connectivity_plus/lib/src/web/dart_html_connectivity_plugin.dart +++ /dev/null @@ -1,35 +0,0 @@ -import 'dart:async'; -import 'dart:html' as html show window; - -import 'package:connectivity_plus_platform_interface/connectivity_plus_platform_interface.dart'; - -import '../connectivity_plus_web.dart'; - -/// The web implementation of the ConnectivityPlatform of the Connectivity plugin. -class DartHtmlConnectivityPlugin extends ConnectivityPlusWebPlugin { - /// Checks the connection status of the device. - @override - Future checkConnectivity() async { - return (html.window.navigator.onLine ?? false) - ? ConnectivityResult.wifi - : ConnectivityResult.none; - } - - StreamController? _connectivityResult; - - /// Returns a Stream of ConnectivityResults changes. - @override - Stream get onConnectivityChanged { - if (_connectivityResult == null) { - _connectivityResult = StreamController.broadcast(); - // Fallback to dart:html window.onOnline / window.onOffline - html.window.onOnline.listen((event) { - _connectivityResult!.add(ConnectivityResult.wifi); - }); - html.window.onOffline.listen((event) { - _connectivityResult!.add(ConnectivityResult.none); - }); - } - return _connectivityResult!.stream; - } -} diff --git a/lib/third_party/connectivity_plus/connectivity_plus/lib/src/web/network_information_api_connectivity_plugin.dart b/lib/third_party/connectivity_plus/connectivity_plus/lib/src/web/network_information_api_connectivity_plugin.dart deleted file mode 100644 index bc822a76..00000000 --- a/lib/third_party/connectivity_plus/connectivity_plus/lib/src/web/network_information_api_connectivity_plugin.dart +++ /dev/null @@ -1,92 +0,0 @@ -import 'dart:async'; -import 'dart:html' as html show window, NetworkInformation; -import 'dart:js_util'; - -import 'package:connectivity_plus/src/web/utils/connectivity_result.dart'; -import 'package:connectivity_plus_platform_interface/connectivity_plus_platform_interface.dart'; -import 'package:flutter/foundation.dart'; -import 'package:js/js.dart'; - -import '../connectivity_plus_web.dart'; - -/// The web implementation of the ConnectivityPlatform of the Connectivity plugin. -class NetworkInformationApiConnectivityPlugin - extends ConnectivityPlusWebPlugin { - final html.NetworkInformation _networkInformation; - - /// A check to determine if this version of the plugin can be used. - static bool isSupported() => html.window.navigator.connection != null; - - /// The constructor of the plugin. - NetworkInformationApiConnectivityPlugin() - : this.withConnection(html.window.navigator.connection!); - - /// Creates the plugin, with an override of the NetworkInformation object. - @visibleForTesting - NetworkInformationApiConnectivityPlugin.withConnection( - html.NetworkInformation connection) - : _networkInformation = connection; - - /// Checks the connection status of the device. - @override - Future checkConnectivity() async { - return networkInformationToConnectivityResult(_networkInformation); - } - - StreamController? _connectivityResultStreamController; - late Stream _connectivityResultStream; - - /// Returns a Stream of ConnectivityResults changes. - @override - Stream get onConnectivityChanged { - // use fallback implementation if [_connectionSupported] is not availible - if (_connectionSupported == null) { - return _webPseudoStream(); - } - if (_connectivityResultStreamController == null) { - _connectivityResultStreamController = - StreamController(); - setProperty(_networkInformation, 'onchange', allowInterop((_) { - _connectivityResultStreamController! - .add(networkInformationToConnectivityResult(_networkInformation)); - })); - // ignore: todo - // TODO: Implement the above with _networkInformation.onChange: - // _networkInformation.onChange.listen((_) { - // _connectivityResult - // .add(networkInformationToConnectivityResult(_networkInformation)); - // }); - // Once we can detect when to *cancel* a subscription to the _networkInformation - // onChange Stream upon hot restart. - // https://github.com/dart-lang/sdk/issues/42679 - _connectivityResultStream = - _connectivityResultStreamController!.stream.asBroadcastStream(); - } - return _connectivityResultStream; - } - - /// stores the last fallback network state - ConnectivityResult? _lastFallbackState; - - /// periodically checks the current network state - Stream _webPseudoStream() { - final StreamController webStream = - StreamController.broadcast(); - Timer.periodic( - const Duration(milliseconds: 250), - (timer) async { - final result = await checkConnectivity(); - if (result != _lastFallbackState) { - webStream.add(result); - } - }, - ); - return webStream.stream; - } -} - -/// accesses the JS-native `navigator.connection` -/// -/// ensures `navigator.connection.onchange` is availible -@JS("navigator.connection") -external get _connectionSupported; diff --git a/lib/third_party/connectivity_plus/connectivity_plus/lib/src/web/utils/connectivity_result.dart b/lib/third_party/connectivity_plus/connectivity_plus/lib/src/web/utils/connectivity_result.dart deleted file mode 100644 index 1b64b69c..00000000 --- a/lib/third_party/connectivity_plus/connectivity_plus/lib/src/web/utils/connectivity_result.dart +++ /dev/null @@ -1,50 +0,0 @@ -import 'dart:html' as html show NetworkInformation; - -import 'package:connectivity_plus_platform_interface/connectivity_plus_platform_interface.dart'; - -/// Converts an incoming NetworkInformation object into the correct ConnectivityResult. -ConnectivityResult networkInformationToConnectivityResult( - html.NetworkInformation info, -) { - if (info.downlink == 0 && info.rtt == 0) { - return ConnectivityResult.none; - } - if (info.type != null) { - return _typeToConnectivityResult(info.type!); - } - if (info.effectiveType != null) { - return _effectiveTypeToConnectivityResult(info.effectiveType!); - } - return ConnectivityResult.none; -} - -ConnectivityResult _effectiveTypeToConnectivityResult(String effectiveType) { - // Possible values: - /*'2g'|'3g'|'4g'|'slow-2g'*/ - switch (effectiveType) { - case 'slow-2g': - case '2g': - case '3g': - case '4g': - return ConnectivityResult.mobile; - default: - return ConnectivityResult.wifi; - } -} - -ConnectivityResult _typeToConnectivityResult(String type) { - // Possible values: - /*'bluetooth'|'cellular'|'ethernet'|'mixed'|'none'|'other'|'unknown'|'wifi'|'wimax'*/ - switch (type) { - case 'none': - return ConnectivityResult.none; - case 'bluetooth': - case 'cellular': - case 'mixed': - case 'other': - case 'unknown': - case 'ethernet': - default: - return ConnectivityResult.mobile; - } -} diff --git a/lib/third_party/connectivity_plus/connectivity_plus/pubspec.yaml b/lib/third_party/connectivity_plus/connectivity_plus/pubspec.yaml index 5d9218ab..980638be 100644 --- a/lib/third_party/connectivity_plus/connectivity_plus/pubspec.yaml +++ b/lib/third_party/connectivity_plus/connectivity_plus/pubspec.yaml @@ -21,9 +21,6 @@ flutter: dartPluginClass: ConnectivityPlusLinuxPlugin macos: pluginClass: ConnectivityPlugin - web: - pluginClass: ConnectivityPlusWebPlugin - fileName: src/connectivity_plus_web.dart windows: pluginClass: ConnectivityPlusWindowsPlugin