diff --git a/packages/connectivity/CHANGELOG.md b/packages/connectivity/CHANGELOG.md index 5a7b5f7f4e05..3ede2383d207 100644 --- a/packages/connectivity/CHANGELOG.md +++ b/packages/connectivity/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.4.5+4 + +* Stability and Maintainability: update documentations. + ## 0.4.5+3 * Remove AndroidX warnings. diff --git a/packages/connectivity/example/README.md b/packages/connectivity/example/README.md deleted file mode 100644 index a7bac8c32e46..000000000000 --- a/packages/connectivity/example/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# connectivity_example - -Demonstrates how to use the connectivity plugin. - -## Getting Started - -For help getting started with Flutter, view our online -[documentation](http://flutter.io/). \ No newline at end of file diff --git a/packages/connectivity/lib/connectivity.dart b/packages/connectivity/lib/connectivity.dart index 03659f5455a9..8108b5c52a79 100644 --- a/packages/connectivity/lib/connectivity.dart +++ b/packages/connectivity/lib/connectivity.dart @@ -15,6 +15,7 @@ import 'package:meta/meta.dart'; /// None: Device not connected to any network enum ConnectivityResult { wifi, mobile, none } +/// Discover network connectivity configurations: Distinguish between WI-FI and cellular, check WI-FI status and more. class Connectivity { /// Constructs a singleton instance of [Connectivity]. /// @@ -35,11 +36,13 @@ class Connectivity { Stream _onConnectivityChanged; + /// Exposed for testing purposes and should not be used by users of the plugin. @visibleForTesting static const MethodChannel methodChannel = MethodChannel( 'plugins.flutter.io/connectivity', ); + /// Exposed for testing purposes and should not be used by users of the plugin. @visibleForTesting static const EventChannel eventChannel = EventChannel( 'plugins.flutter.io/connectivity_status', diff --git a/packages/connectivity/pubspec.yaml b/packages/connectivity/pubspec.yaml index 4466c7ef6054..ede6c241c836 100644 --- a/packages/connectivity/pubspec.yaml +++ b/packages/connectivity/pubspec.yaml @@ -3,7 +3,7 @@ description: Flutter plugin for discovering the state of the network (WiFi & mobile/cellular) connectivity on Android and iOS. author: Flutter Team homepage: https://github.com/flutter/plugins/tree/master/packages/connectivity -version: 0.4.5+3 +version: 0.4.5+4 flutter: plugin: diff --git a/packages/google_sign_in/CHANGELOG.md b/packages/google_sign_in/google_sign_in/CHANGELOG.md similarity index 97% rename from packages/google_sign_in/CHANGELOG.md rename to packages/google_sign_in/google_sign_in/CHANGELOG.md index 300eba20968e..1f7f5b605bb1 100644 --- a/packages/google_sign_in/CHANGELOG.md +++ b/packages/google_sign_in/google_sign_in/CHANGELOG.md @@ -1,3 +1,11 @@ +## 4.0.13 + +* Fix `GoogleUserCircleAvatar` to handle new style profile image URLs. + +## 4.0.12 + +* Move google_sign_in plugin to google_sign_in/google_sign_in to prepare for federated implementations. + ## 4.0.11 * Update iOS CocoaPod dependency to 5.0 to fix deprecated API usage issue. diff --git a/packages/google_sign_in/LICENSE b/packages/google_sign_in/google_sign_in/LICENSE similarity index 100% rename from packages/google_sign_in/LICENSE rename to packages/google_sign_in/google_sign_in/LICENSE diff --git a/packages/google_sign_in/README.md b/packages/google_sign_in/google_sign_in/README.md similarity index 95% rename from packages/google_sign_in/README.md rename to packages/google_sign_in/google_sign_in/README.md index 01c8b5275365..f9e8415f0745 100755 --- a/packages/google_sign_in/README.md +++ b/packages/google_sign_in/google_sign_in/README.md @@ -87,11 +87,11 @@ Future _handleSignIn() async { ## Example -Find the example wiring in the [Google sign-in example application](https://github.com/flutter/plugins/blob/master/packages/google_sign_in/example/lib/main.dart). +Find the example wiring in the [Google sign-in example application](https://github.com/flutter/plugins/blob/master/packages/google_sign_in/google_sign_in/example/lib/main.dart). ## API details -See the [google_sign_in.dart](https://github.com/flutter/plugins/blob/master/packages/google_sign_in/lib/google_sign_in.dart) for more API details. +See the [google_sign_in.dart](https://github.com/flutter/plugins/blob/master/packages/google_sign_in/google_sign_in/lib/google_sign_in.dart) for more API details. ## Issues and feedback diff --git a/packages/google_sign_in/android/build.gradle b/packages/google_sign_in/google_sign_in/android/build.gradle similarity index 100% rename from packages/google_sign_in/android/build.gradle rename to packages/google_sign_in/google_sign_in/android/build.gradle diff --git a/packages/google_sign_in/android/gradle.properties b/packages/google_sign_in/google_sign_in/android/gradle.properties similarity index 100% rename from packages/google_sign_in/android/gradle.properties rename to packages/google_sign_in/google_sign_in/android/gradle.properties diff --git a/packages/google_sign_in/android/settings.gradle b/packages/google_sign_in/google_sign_in/android/settings.gradle similarity index 100% rename from packages/google_sign_in/android/settings.gradle rename to packages/google_sign_in/google_sign_in/android/settings.gradle diff --git a/packages/google_sign_in/android/src/main/AndroidManifest.xml b/packages/google_sign_in/google_sign_in/android/src/main/AndroidManifest.xml similarity index 100% rename from packages/google_sign_in/android/src/main/AndroidManifest.xml rename to packages/google_sign_in/google_sign_in/android/src/main/AndroidManifest.xml diff --git a/packages/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/BackgroundTaskRunner.java b/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/BackgroundTaskRunner.java similarity index 100% rename from packages/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/BackgroundTaskRunner.java rename to packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/BackgroundTaskRunner.java diff --git a/packages/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/Executors.java b/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/Executors.java similarity index 100% rename from packages/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/Executors.java rename to packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/Executors.java diff --git a/packages/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java b/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java similarity index 100% rename from packages/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java rename to packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java diff --git a/packages/google_sign_in/example/README.md b/packages/google_sign_in/google_sign_in/example/README.md similarity index 100% rename from packages/google_sign_in/example/README.md rename to packages/google_sign_in/google_sign_in/example/README.md diff --git a/packages/google_sign_in/example/android.iml b/packages/google_sign_in/google_sign_in/example/android.iml similarity index 100% rename from packages/google_sign_in/example/android.iml rename to packages/google_sign_in/google_sign_in/example/android.iml diff --git a/packages/google_sign_in/example/android/app/build.gradle b/packages/google_sign_in/google_sign_in/example/android/app/build.gradle similarity index 100% rename from packages/google_sign_in/example/android/app/build.gradle rename to packages/google_sign_in/google_sign_in/example/android/app/build.gradle diff --git a/packages/google_sign_in/example/android/app/google-services.json b/packages/google_sign_in/google_sign_in/example/android/app/google-services.json similarity index 100% rename from packages/google_sign_in/example/android/app/google-services.json rename to packages/google_sign_in/google_sign_in/example/android/app/google-services.json diff --git a/packages/google_sign_in/example/android/app/gradle/wrapper/gradle-wrapper.properties b/packages/google_sign_in/google_sign_in/example/android/app/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from packages/google_sign_in/example/android/app/gradle/wrapper/gradle-wrapper.properties rename to packages/google_sign_in/google_sign_in/example/android/app/gradle/wrapper/gradle-wrapper.properties diff --git a/packages/google_sign_in/example/android/app/src/main/AndroidManifest.xml b/packages/google_sign_in/google_sign_in/example/android/app/src/main/AndroidManifest.xml similarity index 100% rename from packages/google_sign_in/example/android/app/src/main/AndroidManifest.xml rename to packages/google_sign_in/google_sign_in/example/android/app/src/main/AndroidManifest.xml diff --git a/packages/google_sign_in/example/android/app/src/main/java/io/flutter/plugins/.gitignore b/packages/google_sign_in/google_sign_in/example/android/app/src/main/java/io/flutter/plugins/.gitignore similarity index 100% rename from packages/google_sign_in/example/android/app/src/main/java/io/flutter/plugins/.gitignore rename to packages/google_sign_in/google_sign_in/example/android/app/src/main/java/io/flutter/plugins/.gitignore diff --git a/packages/google_sign_in/example/android/app/src/main/java/io/flutter/plugins/googlesigninexample/MainActivity.java b/packages/google_sign_in/google_sign_in/example/android/app/src/main/java/io/flutter/plugins/googlesigninexample/MainActivity.java similarity index 100% rename from packages/google_sign_in/example/android/app/src/main/java/io/flutter/plugins/googlesigninexample/MainActivity.java rename to packages/google_sign_in/google_sign_in/example/android/app/src/main/java/io/flutter/plugins/googlesigninexample/MainActivity.java diff --git a/packages/google_sign_in/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/packages/google_sign_in/google_sign_in/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png similarity index 100% rename from packages/google_sign_in/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png rename to packages/google_sign_in/google_sign_in/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png diff --git a/packages/google_sign_in/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/packages/google_sign_in/google_sign_in/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png similarity index 100% rename from packages/google_sign_in/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png rename to packages/google_sign_in/google_sign_in/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png diff --git a/packages/google_sign_in/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/packages/google_sign_in/google_sign_in/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png similarity index 100% rename from packages/google_sign_in/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png rename to packages/google_sign_in/google_sign_in/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png diff --git a/packages/google_sign_in/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/packages/google_sign_in/google_sign_in/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png similarity index 100% rename from packages/google_sign_in/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png rename to packages/google_sign_in/google_sign_in/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png diff --git a/packages/google_sign_in/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/packages/google_sign_in/google_sign_in/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png similarity index 100% rename from packages/google_sign_in/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png rename to packages/google_sign_in/google_sign_in/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png diff --git a/packages/google_sign_in/example/android/build.gradle b/packages/google_sign_in/google_sign_in/example/android/build.gradle similarity index 100% rename from packages/google_sign_in/example/android/build.gradle rename to packages/google_sign_in/google_sign_in/example/android/build.gradle diff --git a/packages/google_sign_in/example/android/gradle.properties b/packages/google_sign_in/google_sign_in/example/android/gradle.properties similarity index 100% rename from packages/google_sign_in/example/android/gradle.properties rename to packages/google_sign_in/google_sign_in/example/android/gradle.properties diff --git a/packages/google_sign_in/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/google_sign_in/google_sign_in/example/android/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from packages/google_sign_in/example/android/gradle/wrapper/gradle-wrapper.properties rename to packages/google_sign_in/google_sign_in/example/android/gradle/wrapper/gradle-wrapper.properties diff --git a/packages/google_sign_in/example/android/settings.gradle b/packages/google_sign_in/google_sign_in/example/android/settings.gradle similarity index 100% rename from packages/google_sign_in/example/android/settings.gradle rename to packages/google_sign_in/google_sign_in/example/android/settings.gradle diff --git a/packages/google_sign_in/example/example.iml b/packages/google_sign_in/google_sign_in/example/example.iml similarity index 100% rename from packages/google_sign_in/example/example.iml rename to packages/google_sign_in/google_sign_in/example/example.iml diff --git a/packages/google_sign_in/example/google_sign_in_example.iml b/packages/google_sign_in/google_sign_in/example/google_sign_in_example.iml similarity index 100% rename from packages/google_sign_in/example/google_sign_in_example.iml rename to packages/google_sign_in/google_sign_in/example/google_sign_in_example.iml diff --git a/packages/google_sign_in/example/ios/Flutter/AppFrameworkInfo.plist b/packages/google_sign_in/google_sign_in/example/ios/Flutter/AppFrameworkInfo.plist similarity index 100% rename from packages/google_sign_in/example/ios/Flutter/AppFrameworkInfo.plist rename to packages/google_sign_in/google_sign_in/example/ios/Flutter/AppFrameworkInfo.plist diff --git a/packages/google_sign_in/example/ios/Flutter/Debug.xcconfig b/packages/google_sign_in/google_sign_in/example/ios/Flutter/Debug.xcconfig similarity index 100% rename from packages/google_sign_in/example/ios/Flutter/Debug.xcconfig rename to packages/google_sign_in/google_sign_in/example/ios/Flutter/Debug.xcconfig diff --git a/packages/google_sign_in/example/ios/Flutter/Release.xcconfig b/packages/google_sign_in/google_sign_in/example/ios/Flutter/Release.xcconfig similarity index 100% rename from packages/google_sign_in/example/ios/Flutter/Release.xcconfig rename to packages/google_sign_in/google_sign_in/example/ios/Flutter/Release.xcconfig diff --git a/packages/google_sign_in/example/ios/Runner.xcodeproj/project.pbxproj b/packages/google_sign_in/google_sign_in/example/ios/Runner.xcodeproj/project.pbxproj similarity index 100% rename from packages/google_sign_in/example/ios/Runner.xcodeproj/project.pbxproj rename to packages/google_sign_in/google_sign_in/example/ios/Runner.xcodeproj/project.pbxproj diff --git a/packages/google_sign_in/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/packages/google_sign_in/google_sign_in/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata similarity index 100% rename from packages/google_sign_in/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata rename to packages/google_sign_in/google_sign_in/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata diff --git a/packages/google_sign_in/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/google_sign_in/google_sign_in/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme similarity index 100% rename from packages/google_sign_in/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme rename to packages/google_sign_in/google_sign_in/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme diff --git a/packages/google_sign_in/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/packages/google_sign_in/google_sign_in/example/ios/Runner.xcworkspace/contents.xcworkspacedata similarity index 100% rename from packages/google_sign_in/example/ios/Runner.xcworkspace/contents.xcworkspacedata rename to packages/google_sign_in/google_sign_in/example/ios/Runner.xcworkspace/contents.xcworkspacedata diff --git a/packages/google_sign_in/example/ios/Runner/AppDelegate.h b/packages/google_sign_in/google_sign_in/example/ios/Runner/AppDelegate.h similarity index 100% rename from packages/google_sign_in/example/ios/Runner/AppDelegate.h rename to packages/google_sign_in/google_sign_in/example/ios/Runner/AppDelegate.h diff --git a/packages/google_sign_in/example/ios/Runner/AppDelegate.m b/packages/google_sign_in/google_sign_in/example/ios/Runner/AppDelegate.m similarity index 100% rename from packages/google_sign_in/example/ios/Runner/AppDelegate.m rename to packages/google_sign_in/google_sign_in/example/ios/Runner/AppDelegate.m diff --git a/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/packages/google_sign_in/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json rename to packages/google_sign_in/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/packages/google_sign_in/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png similarity index 100% rename from packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png rename to packages/google_sign_in/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png diff --git a/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/packages/google_sign_in/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png similarity index 100% rename from packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png rename to packages/google_sign_in/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png diff --git a/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/packages/google_sign_in/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png similarity index 100% rename from packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png rename to packages/google_sign_in/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png diff --git a/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/packages/google_sign_in/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png similarity index 100% rename from packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png rename to packages/google_sign_in/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png diff --git a/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/packages/google_sign_in/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png similarity index 100% rename from packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png rename to packages/google_sign_in/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png diff --git a/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/packages/google_sign_in/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png similarity index 100% rename from packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png rename to packages/google_sign_in/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png diff --git a/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/packages/google_sign_in/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png similarity index 100% rename from packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png rename to packages/google_sign_in/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png diff --git a/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/packages/google_sign_in/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png similarity index 100% rename from packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png rename to packages/google_sign_in/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png diff --git a/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/packages/google_sign_in/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png similarity index 100% rename from packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png rename to packages/google_sign_in/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png diff --git a/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/packages/google_sign_in/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png similarity index 100% rename from packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png rename to packages/google_sign_in/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png diff --git a/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/packages/google_sign_in/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png similarity index 100% rename from packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png rename to packages/google_sign_in/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png diff --git a/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/packages/google_sign_in/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png similarity index 100% rename from packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png rename to packages/google_sign_in/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png diff --git a/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/packages/google_sign_in/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png similarity index 100% rename from packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png rename to packages/google_sign_in/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png diff --git a/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/packages/google_sign_in/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png similarity index 100% rename from packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png rename to packages/google_sign_in/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png diff --git a/packages/google_sign_in/example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/packages/google_sign_in/google_sign_in/example/ios/Runner/Base.lproj/LaunchScreen.storyboard similarity index 100% rename from packages/google_sign_in/example/ios/Runner/Base.lproj/LaunchScreen.storyboard rename to packages/google_sign_in/google_sign_in/example/ios/Runner/Base.lproj/LaunchScreen.storyboard diff --git a/packages/google_sign_in/example/ios/Runner/Base.lproj/Main.storyboard b/packages/google_sign_in/google_sign_in/example/ios/Runner/Base.lproj/Main.storyboard similarity index 100% rename from packages/google_sign_in/example/ios/Runner/Base.lproj/Main.storyboard rename to packages/google_sign_in/google_sign_in/example/ios/Runner/Base.lproj/Main.storyboard diff --git a/packages/google_sign_in/example/ios/Runner/GoogleService-Info.plist b/packages/google_sign_in/google_sign_in/example/ios/Runner/GoogleService-Info.plist similarity index 100% rename from packages/google_sign_in/example/ios/Runner/GoogleService-Info.plist rename to packages/google_sign_in/google_sign_in/example/ios/Runner/GoogleService-Info.plist diff --git a/packages/google_sign_in/example/ios/Runner/Info.plist b/packages/google_sign_in/google_sign_in/example/ios/Runner/Info.plist similarity index 100% rename from packages/google_sign_in/example/ios/Runner/Info.plist rename to packages/google_sign_in/google_sign_in/example/ios/Runner/Info.plist diff --git a/packages/google_sign_in/example/ios/Runner/main.m b/packages/google_sign_in/google_sign_in/example/ios/Runner/main.m similarity index 100% rename from packages/google_sign_in/example/ios/Runner/main.m rename to packages/google_sign_in/google_sign_in/example/ios/Runner/main.m diff --git a/packages/google_sign_in/example/lib/main.dart b/packages/google_sign_in/google_sign_in/example/lib/main.dart similarity index 100% rename from packages/google_sign_in/example/lib/main.dart rename to packages/google_sign_in/google_sign_in/example/lib/main.dart diff --git a/packages/google_sign_in/example/pubspec.yaml b/packages/google_sign_in/google_sign_in/example/pubspec.yaml similarity index 100% rename from packages/google_sign_in/example/pubspec.yaml rename to packages/google_sign_in/google_sign_in/example/pubspec.yaml diff --git a/packages/google_sign_in/ios/Assets/.gitkeep b/packages/google_sign_in/google_sign_in/ios/Assets/.gitkeep similarity index 100% rename from packages/google_sign_in/ios/Assets/.gitkeep rename to packages/google_sign_in/google_sign_in/ios/Assets/.gitkeep diff --git a/packages/google_sign_in/ios/Classes/GoogleSignInPlugin.h b/packages/google_sign_in/google_sign_in/ios/Classes/GoogleSignInPlugin.h similarity index 100% rename from packages/google_sign_in/ios/Classes/GoogleSignInPlugin.h rename to packages/google_sign_in/google_sign_in/ios/Classes/GoogleSignInPlugin.h diff --git a/packages/google_sign_in/ios/Classes/GoogleSignInPlugin.m b/packages/google_sign_in/google_sign_in/ios/Classes/GoogleSignInPlugin.m similarity index 100% rename from packages/google_sign_in/ios/Classes/GoogleSignInPlugin.m rename to packages/google_sign_in/google_sign_in/ios/Classes/GoogleSignInPlugin.m diff --git a/packages/google_sign_in/ios/google_sign_in.podspec b/packages/google_sign_in/google_sign_in/ios/google_sign_in.podspec similarity index 100% rename from packages/google_sign_in/ios/google_sign_in.podspec rename to packages/google_sign_in/google_sign_in/ios/google_sign_in.podspec diff --git a/packages/google_sign_in/lib/google_sign_in.dart b/packages/google_sign_in/google_sign_in/lib/google_sign_in.dart similarity index 100% rename from packages/google_sign_in/lib/google_sign_in.dart rename to packages/google_sign_in/google_sign_in/lib/google_sign_in.dart diff --git a/packages/google_sign_in/lib/src/common.dart b/packages/google_sign_in/google_sign_in/lib/src/common.dart similarity index 100% rename from packages/google_sign_in/lib/src/common.dart rename to packages/google_sign_in/google_sign_in/lib/src/common.dart diff --git a/packages/google_sign_in/google_sign_in/lib/src/fife.dart b/packages/google_sign_in/google_sign_in/lib/src/fife.dart new file mode 100644 index 000000000000..14ecf5fd6083 --- /dev/null +++ b/packages/google_sign_in/google_sign_in/lib/src/fife.dart @@ -0,0 +1,70 @@ +// Copyright 2019 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/// A regular expression that matches against the "size directive" path +/// segment of Google profile image URLs. +/// +/// The format is is "`/sNN-c/`", where `NN` is the max width/height of the +/// image, and "`c`" indicates we want the image cropped. +final RegExp sizeDirective = RegExp(r'^s[0-9]{1,5}(-c)?$'); + +/// Adds [size] (and crop) directive to [photoUrl]. +/// +/// There are two formats for photoUrls coming from the Sign In backend. +/// +/// The two formats can be told apart by the number of path segments in the +/// URL (path segments: parts of the URL separated by slashes "/"): +/// +/// * If the URL has 2 or less path segments, it is a *new* style URL. +/// * If the URL has more than 2 path segments, it is an old style URL. +/// +/// Old style URLs encode the image transformation directives as the last +/// path segment. Look at the [sizeDirective] Regular Expression for more +/// information about these URLs. +/// +/// New style URLs carry the same directives at the end of the URL, +/// after an = sign, like: "`=s120-c-fSoften=1,50,0`". +/// +/// Directives may contain the "=" sign (`fSoften=1,50,0`), but it seems the +/// base URL of the images don't. "Everything after the first = sign" is a +/// good heuristic to split new style URLs. +/// +/// Each directive is separated from others by dashes. Directives are the same +/// as described in the [sizeDirective] RegExp. +/// +/// Modified image URLs are recomposed by performing the parsing steps in reverse. +String addSizeDirectiveToUrl(String photoUrl, double size) { + final Uri profileUri = Uri.parse(photoUrl); + final List pathSegments = List.from(profileUri.pathSegments); + if (pathSegments.length <= 2) { + final String imagePath = pathSegments.last; + // Does this have any existing transformation directives? + final int directiveSeparator = imagePath.indexOf('='); + if (directiveSeparator >= 0) { + // Split the baseUrl from the sizing directive by the first "=" + final String baseUrl = imagePath.substring(0, directiveSeparator); + final String directive = imagePath.substring(directiveSeparator + 1); + // Split the directive by "-" + final Set directives = Set.from(directive.split('-')) + // Remove the size directive, if present, and any empty values + ..removeWhere((String s) => s.isEmpty || sizeDirective.hasMatch(s)) + // Add the size and crop directives + ..addAll(['c', 's${size.round()}']); + // Recompose the URL by performing the reverse of the parsing + pathSegments.last = '$baseUrl=${directives.join("-")}'; + } else { + pathSegments.last = '${pathSegments.last}=c-s${size.round()}'; + } + } else { + // Old style URLs + pathSegments + ..removeWhere(sizeDirective.hasMatch) + ..insert(pathSegments.length - 1, 's${size.round()}-c'); + } + return Uri( + scheme: profileUri.scheme, + host: profileUri.host, + pathSegments: pathSegments, + ).toString(); +} diff --git a/packages/google_sign_in/lib/testing.dart b/packages/google_sign_in/google_sign_in/lib/testing.dart similarity index 100% rename from packages/google_sign_in/lib/testing.dart rename to packages/google_sign_in/google_sign_in/lib/testing.dart diff --git a/packages/google_sign_in/lib/widgets.dart b/packages/google_sign_in/google_sign_in/lib/widgets.dart similarity index 88% rename from packages/google_sign_in/lib/widgets.dart rename to packages/google_sign_in/google_sign_in/lib/widgets.dart index 01ab6c64c00c..3375628f47b5 100644 --- a/packages/google_sign_in/lib/widgets.dart +++ b/packages/google_sign_in/google_sign_in/lib/widgets.dart @@ -8,6 +8,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'src/common.dart'; +import 'src/fife.dart' as fife; /// Builds a CircleAvatar profile image of the appropriate resolution class GoogleUserCircleAvatar extends StatelessWidget { @@ -33,7 +34,7 @@ class GoogleUserCircleAvatar extends StatelessWidget { /// /// The format is is "`/sNN-c/`", where `NN` is the max width/height of the /// image, and "`c`" indicates we want the image cropped. - static final RegExp sizeDirective = RegExp(r'^s[0-9]{1,5}(-c)?$'); + static final RegExp sizeDirective = fife.sizeDirective; /// The Google user's identity; guaranteed to be non-null. final GoogleIdentity identity; @@ -67,8 +68,7 @@ class GoogleUserCircleAvatar extends StatelessWidget { ); } - /// Adds sizing information to [photoUrl], inserted as the last path segment - /// before the image filename. The format is described in [sizeDirective]. + /// Adds correct sizing information to [photoUrl]. /// /// Falls back to the default profile photo if [photoUrl] is [null]. static String _sizedProfileImageUrl(String photoUrl, double size) { @@ -77,17 +77,7 @@ class GoogleUserCircleAvatar extends StatelessWidget { // the default profile photo as a last resort. return 'https://lh3.googleusercontent.com/a/default-user=s${size.round()}-c'; } - final Uri profileUri = Uri.parse(photoUrl); - final List pathSegments = - List.from(profileUri.pathSegments); - pathSegments - ..removeWhere(sizeDirective.hasMatch) - ..insert(pathSegments.length - 1, 's${size.round()}-c'); - return Uri( - scheme: profileUri.scheme, - host: profileUri.host, - pathSegments: pathSegments, - ).toString(); + return fife.addSizeDirectiveToUrl(photoUrl, size); } Widget _buildClippedImage(BuildContext context, BoxConstraints constraints) { diff --git a/packages/google_sign_in/pubspec.yaml b/packages/google_sign_in/google_sign_in/pubspec.yaml similarity index 92% rename from packages/google_sign_in/pubspec.yaml rename to packages/google_sign_in/google_sign_in/pubspec.yaml index e239e01c3b44..833ef6733d2d 100644 --- a/packages/google_sign_in/pubspec.yaml +++ b/packages/google_sign_in/google_sign_in/pubspec.yaml @@ -2,8 +2,8 @@ name: google_sign_in description: Flutter plugin for Google Sign-In, a secure authentication system for signing in with a Google account on Android and iOS. author: Flutter Team -homepage: https://github.com/flutter/plugins/tree/master/packages/google_sign_in -version: 4.0.11 +homepage: https://github.com/flutter/plugins/tree/master/packages/google_sign_in/google_sign_in +version: 4.0.13 flutter: plugin: diff --git a/packages/google_sign_in/google_sign_in/test/fife_test.dart b/packages/google_sign_in/google_sign_in/test/fife_test.dart new file mode 100644 index 000000000000..bfc4937a7c64 --- /dev/null +++ b/packages/google_sign_in/google_sign_in/test/fife_test.dart @@ -0,0 +1,66 @@ +// Copyright 2019 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter_test/flutter_test.dart'; +import 'package:google_sign_in/src/fife.dart'; + +void main() { + group('addSizeDirectiveToUrl', () { + const double size = 20; + + group('Old style URLs', () { + const String base = + 'https://lh3.googleusercontent.com/-ukEAtRyRhw8/AAAAAAAAAAI/AAAAAAAAAAA/ACHi3rfhID9XACtdb9q_xK43VSXQvBV11Q.CMID'; + const String expected = '$base/s20-c/photo.jpg'; + + test('with directives, sets size', () { + final String url = '$base/s64-c/photo.jpg'; + expect(addSizeDirectiveToUrl(url, size), expected); + }); + + test('no directives, sets size and crop', () { + final String url = '$base/photo.jpg'; + expect(addSizeDirectiveToUrl(url, size), expected); + }); + + test('no crop, sets size and crop', () { + final String url = '$base/s64/photo.jpg'; + expect(addSizeDirectiveToUrl(url, size), expected); + }); + }); + + group('New style URLs', () { + const String base = + 'https://lh3.googleusercontent.com/a-/AAuE7mC0Lh4F4uDtEaY7hpe-GIsbDpqfMZ3_2UhBQ8Qk'; + const String expected = '$base=c-s20'; + + test('with directives, sets size', () { + final String url = '$base=s120-c'; + expect(addSizeDirectiveToUrl(url, size), expected); + }); + + test('no directives, sets size and crop', () { + final String url = base; + expect(addSizeDirectiveToUrl(url, size), expected); + }); + + test('no directives, but with an equals sign, sets size and crop', () { + final String url = '$base='; + expect(addSizeDirectiveToUrl(url, size), expected); + }); + + test('no crop, adds crop', () { + final String url = '$base=s120'; + expect(addSizeDirectiveToUrl(url, size), expected); + }); + + test('many directives, sets size and crop, preserves other directives', + () { + final String url = '$base=s120-c-fSoften=1,50,0'; + final String expected = '$base=c-fSoften=1,50,0-s20'; + expect(addSizeDirectiveToUrl(url, size), expected); + }); + }); + }); +} diff --git a/packages/google_sign_in/test/google_sign_in_test.dart b/packages/google_sign_in/google_sign_in/test/google_sign_in_test.dart similarity index 100% rename from packages/google_sign_in/test/google_sign_in_test.dart rename to packages/google_sign_in/google_sign_in/test/google_sign_in_test.dart diff --git a/packages/google_sign_in/google_sign_in_platform_interface/CHANGELOG.md b/packages/google_sign_in/google_sign_in_platform_interface/CHANGELOG.md new file mode 100644 index 000000000000..0d8803f93540 --- /dev/null +++ b/packages/google_sign_in/google_sign_in_platform_interface/CHANGELOG.md @@ -0,0 +1,3 @@ +## 1.0.0 + +* Initial release. diff --git a/packages/google_sign_in/google_sign_in_platform_interface/LICENSE b/packages/google_sign_in/google_sign_in_platform_interface/LICENSE new file mode 100644 index 000000000000..c89293372cf3 --- /dev/null +++ b/packages/google_sign_in/google_sign_in_platform_interface/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/packages/google_sign_in/google_sign_in_platform_interface/README.md b/packages/google_sign_in/google_sign_in_platform_interface/README.md new file mode 100644 index 000000000000..9fd891f63968 --- /dev/null +++ b/packages/google_sign_in/google_sign_in_platform_interface/README.md @@ -0,0 +1,26 @@ +# google_sign_in_platform_interface + +A common platform interface for the [`google_sign_in`][1] plugin. + +This interface allows platform-specific implementations of the `google_sign_in` +plugin, as well as the plugin itself, to ensure they are supporting the +same interface. + +# Usage + +To implement a new platform-specific implementation of `google_sign_in`, extend +[`GoogleSignInPlatform`][2] with an implementation that performs the +platform-specific behavior, and when you register your plugin, set the default +`GoogleSignInPlatform` by calling +`GoogleSignInPlatform.instance = MyPlatformGoogleSignIn()`. + +# Note on breaking changes + +Strongly prefer non-breaking changes (such as adding a method to the interface) +over breaking changes for this package. + +See https://flutter.dev/go/platform-interface-breaking-changes for a discussion +on why a less-clean interface is preferable to a breaking change. + +[1]: ../google_sign_in +[2]: lib/google_sign_in_platform_interface.dart diff --git a/packages/google_sign_in/google_sign_in_platform_interface/lib/google_sign_in_platform_interface.dart b/packages/google_sign_in/google_sign_in_platform_interface/lib/google_sign_in_platform_interface.dart new file mode 100644 index 000000000000..8e4e4541a388 --- /dev/null +++ b/packages/google_sign_in/google_sign_in_platform_interface/lib/google_sign_in_platform_interface.dart @@ -0,0 +1,109 @@ +// 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:meta/meta.dart' show required, visibleForTesting; +import 'src/method_channel_google_sign_in.dart'; +import 'src/types.dart'; + +export 'src/method_channel_google_sign_in.dart'; +export 'src/types.dart'; + +/// The interface that implementations of google_sign_in must implement. +/// +/// Platform implementations that live in a separate package should extend this +/// class rather than implement it as `google_sign_in` 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 [GoogleSignInPlatform] methods. +abstract class GoogleSignInPlatform { + /// Only mock implementations should set this to `true`. + /// + /// Mockito mocks implement this class with `implements` which is forbidden + /// (see class docs). This property provides a backdoor for mocks to skip the + /// verification that the class isn't implemented with `implements`. + @visibleForTesting + bool get isMock => false; + + /// The default instance of [GoogleSignInPlatform] to use. + /// + /// Platform-specific plugins should override this with their own + /// platform-specific class that extends [GoogleSignInPlatform] when they + /// register themselves. + /// + /// Defaults to [MethodChannelGoogleSignIn]. + static GoogleSignInPlatform get instance => _instance; + + static GoogleSignInPlatform _instance = MethodChannelGoogleSignIn(); + + // TODO(amirh): Extract common platform interface logic. + // https://github.com/flutter/flutter/issues/43368 + static set instance(GoogleSignInPlatform instance) { + if (!instance.isMock) { + try { + instance._verifyProvidesDefaultImplementations(); + } on NoSuchMethodError catch (_) { + throw AssertionError( + 'Platform interfaces must not be implemented with `implements`'); + } + } + _instance = instance; + } + + /// This method ensures that [GoogleSignInPlatform] isn't implemented with `implements`. + /// + /// See class docs for more details on why using `implements` to implement + /// [GoogleSignInPlatform] is forbidden. + /// + /// This private method is called by the [instance] setter, which should fail + /// if the provided instance is a class implemented with `implements`. + void _verifyProvidesDefaultImplementations() {} + + /// Initializes the plugin. You must call this method before calling other methods. + /// See: https://developers.google.com/identity/sign-in/web/reference#gapiauth2initparams + Future init( + {@required String hostedDomain, + List scopes, + SignInOption signInOption, + String clientId}) async { + throw UnimplementedError('init() has not been implemented.'); + } + + /// Attempts to reuse pre-existing credentials to sign in again, without user interaction. + Future signInSilently() async { + throw UnimplementedError('signInSilently() has not been implemented.'); + } + + /// Signs in the user with the options specified to [init]. + Future signIn() async { + throw UnimplementedError('signIn() has not been implemented.'); + } + + /// Returns the Tokens used to authenticate other API calls. + Future getTokens( + {@required String email, bool shouldRecoverAuth}) async { + throw UnimplementedError('getTokens() has not been implemented.'); + } + + /// Signs out the current account from the application. + Future signOut() async { + throw UnimplementedError('signOut() has not been implemented.'); + } + + /// Revokes all of the scopes that the user granted. + Future disconnect() async { + throw UnimplementedError('disconnect() has not been implemented.'); + } + + /// Returns whether the current user is currently signed in. + Future isSignedIn() async { + throw UnimplementedError('isSignedIn() has not been implemented.'); + } + + /// Clears any cached information that the plugin may be holding on to. + Future clearAuthCache({@required String token}) async { + throw UnimplementedError('clearAuthCache() has not been implemented.'); + } +} diff --git a/packages/google_sign_in/google_sign_in_platform_interface/lib/src/method_channel_google_sign_in.dart b/packages/google_sign_in/google_sign_in_platform_interface/lib/src/method_channel_google_sign_in.dart new file mode 100644 index 000000000000..bc52a73868eb --- /dev/null +++ b/packages/google_sign_in/google_sign_in_platform_interface/lib/src/method_channel_google_sign_in.dart @@ -0,0 +1,79 @@ +// 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:flutter/services.dart'; +import 'package:meta/meta.dart' show required, visibleForTesting; + +import '../google_sign_in_platform_interface.dart'; +import 'types.dart'; +import 'utils.dart'; + +/// An implementation of [GoogleSignInPlatform] that uses method channels. +class MethodChannelGoogleSignIn extends GoogleSignInPlatform { + @visibleForTesting + MethodChannel channel = + const MethodChannel('plugins.flutter.io/google_sign_in'); + + @override + Future init( + {@required String hostedDomain, + List scopes = const [], + SignInOption signInOption = SignInOption.standard, + String clientId}) { + return channel.invokeMethod('init', { + 'signInOption': signInOption.toString(), + 'scopes': scopes, + 'hostedDomain': hostedDomain, + }); + } + + @override + Future signInSilently() { + return channel + .invokeMapMethod('signInSilently') + .then(getUserDataFromMap); + } + + @override + Future signIn() { + return channel + .invokeMapMethod('signIn') + .then(getUserDataFromMap); + } + + @override + Future getTokens( + {String email, bool shouldRecoverAuth = true}) { + return channel + .invokeMapMethod('getTokens', { + 'email': email, + 'shouldRecoverAuth': shouldRecoverAuth, + }).then(getTokenDataFromMap); + } + + @override + Future signOut() { + return channel.invokeMapMethod('signOut'); + } + + @override + Future disconnect() { + return channel.invokeMapMethod('disconnect'); + } + + @override + Future isSignedIn() { + return channel.invokeMethod('isSignedIn'); + } + + @override + Future clearAuthCache({String token}) { + return channel.invokeMethod( + 'clearAuthCache', + {'token': token}, + ); + } +} diff --git a/packages/google_sign_in/google_sign_in_platform_interface/lib/src/types.dart b/packages/google_sign_in/google_sign_in_platform_interface/lib/src/types.dart new file mode 100644 index 000000000000..98b73c0667f2 --- /dev/null +++ b/packages/google_sign_in/google_sign_in_platform_interface/lib/src/types.dart @@ -0,0 +1,51 @@ +// 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 'package:quiver_hashcode/hashcode.dart'; + +enum SignInOption { standard, games } + +class GoogleSignInUserData { + GoogleSignInUserData( + {this.displayName, this.email, this.id, this.photoUrl, this.idToken}); + String displayName; + String email; + String id; + String photoUrl; + String idToken; + + @override + int get hashCode => + hashObjects([displayName, email, id, photoUrl, idToken]); + + @override + bool operator ==(dynamic other) { + if (identical(this, other)) return true; + if (other is! GoogleSignInUserData) return false; + final GoogleSignInUserData otherUserData = other; + return otherUserData.displayName == displayName && + otherUserData.email == email && + otherUserData.id == id && + otherUserData.photoUrl == photoUrl && + otherUserData.idToken == idToken; + } +} + +class GoogleSignInTokenData { + GoogleSignInTokenData({this.idToken, this.accessToken}); + String idToken; + String accessToken; + + @override + int get hashCode => hash2(idToken, accessToken); + + @override + bool operator ==(dynamic other) { + if (identical(this, other)) return true; + if (other is! GoogleSignInTokenData) return false; + final GoogleSignInTokenData otherTokenData = other; + return otherTokenData.idToken == idToken && + otherTokenData.accessToken == accessToken; + } +} diff --git a/packages/google_sign_in/google_sign_in_platform_interface/lib/src/utils.dart b/packages/google_sign_in/google_sign_in_platform_interface/lib/src/utils.dart new file mode 100644 index 000000000000..eb60f00cba63 --- /dev/null +++ b/packages/google_sign_in/google_sign_in_platform_interface/lib/src/utils.dart @@ -0,0 +1,29 @@ +// 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 '../google_sign_in_platform_interface.dart'; + +/// Converts user data coming from native code into the proper platform interface type. +GoogleSignInUserData getUserDataFromMap(Map data) { + if (data == null) { + return null; + } + return GoogleSignInUserData( + displayName: data['displayName'], + email: data['email'], + id: data['id'], + photoUrl: data['photoUrl'], + idToken: data['idToken']); +} + +/// Converts token data coming from native code into the proper platform interface type. +GoogleSignInTokenData getTokenDataFromMap(Map data) { + if (data == null) { + return null; + } + return GoogleSignInTokenData( + idToken: data['idToken'], + accessToken: data['accessToken'], + ); +} diff --git a/packages/google_sign_in/google_sign_in_platform_interface/pubspec.yaml b/packages/google_sign_in/google_sign_in_platform_interface/pubspec.yaml new file mode 100644 index 000000000000..ceba7a1c516a --- /dev/null +++ b/packages/google_sign_in/google_sign_in_platform_interface/pubspec.yaml @@ -0,0 +1,22 @@ +name: google_sign_in_platform_interface +description: A common platform interface for the google_sign_in plugin. +author: Flutter Team +homepage: https://github.com/flutter/plugins/tree/master/packages/google_sign_in/google_sign_in_platform_interface +# NOTE: We strongly prefer non-breaking changes, even at the expense of a +# less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes +version: 1.0.0 + +dependencies: + flutter: + sdk: flutter + meta: ^1.0.5 + quiver_hashcode: ^2.0.0 + +dev_dependencies: + flutter_test: + sdk: flutter + mockito: ^4.1.1 + +environment: + sdk: ">=2.0.0-dev.28.0 <3.0.0" + flutter: ">=1.5.0 <2.0.0" diff --git a/packages/google_sign_in/google_sign_in_platform_interface/test/google_sign_in_platform_interface_test.dart b/packages/google_sign_in/google_sign_in_platform_interface/test/google_sign_in_platform_interface_test.dart new file mode 100644 index 000000000000..f411b8992821 --- /dev/null +++ b/packages/google_sign_in/google_sign_in_platform_interface/test/google_sign_in_platform_interface_test.dart @@ -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. + +import 'package:google_sign_in_platform_interface/google_sign_in_platform_interface.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/mockito.dart'; + +void main() { + group('$GoogleSignInPlatform', () { + test('$MethodChannelGoogleSignIn is the default instance', () { + expect(GoogleSignInPlatform.instance, isA()); + }); + + test('Cannot be implemented with `implements`', () { + expect(() { + GoogleSignInPlatform.instance = ImplementsGoogleSignInPlatform(); + }, throwsAssertionError); + }); + + test('Can be extended', () { + GoogleSignInPlatform.instance = ExtendsGoogleSignInPlatform(); + }); + + test('Can be mocked with `implements`', () { + final ImplementsGoogleSignInPlatform mock = + ImplementsGoogleSignInPlatform(); + when(mock.isMock).thenReturn(true); + GoogleSignInPlatform.instance = mock; + }); + }); +} + +class ImplementsGoogleSignInPlatform extends Mock + implements GoogleSignInPlatform {} + +class ExtendsGoogleSignInPlatform extends GoogleSignInPlatform {} diff --git a/packages/google_sign_in/google_sign_in_platform_interface/test/method_channel_google_sign_in_test.dart b/packages/google_sign_in/google_sign_in_platform_interface/test/method_channel_google_sign_in_test.dart new file mode 100644 index 000000000000..13de6acf0748 --- /dev/null +++ b/packages/google_sign_in/google_sign_in_platform_interface/test/method_channel_google_sign_in_test.dart @@ -0,0 +1,127 @@ +// 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. + +import 'package:google_sign_in_platform_interface/google_sign_in_platform_interface.dart'; +import 'package:google_sign_in_platform_interface/src/types.dart'; +import 'package:google_sign_in_platform_interface/src/utils.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; + +const Map kUserData = { + "email": "john.doe@gmail.com", + "id": "8162538176523816253123", + "photoUrl": "https://lh5.googleusercontent.com/photo.jpg", + "displayName": "John Doe", +}; + +const Map kTokenData = { + 'idToken': '123', + 'accessToken': '456', +}; + +const Map kDefaultResponses = { + 'init': null, + 'signInSilently': kUserData, + 'signIn': kUserData, + 'signOut': null, + 'disconnect': null, + 'isSignedIn': true, + 'getTokens': kTokenData, +}; + +final GoogleSignInUserData kUser = getUserDataFromMap(kUserData); +final GoogleSignInTokenData kToken = getTokenDataFromMap(kTokenData); + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + group('$MethodChannelGoogleSignIn', () { + final MethodChannelGoogleSignIn googleSignIn = MethodChannelGoogleSignIn(); + final MethodChannel channel = googleSignIn.channel; + + final List log = []; + Map responses; // Some tests mutate some kDefaultResponses + + setUp(() { + responses = Map.from(kDefaultResponses); + channel.setMockMethodCallHandler((MethodCall methodCall) { + log.add(methodCall); + final dynamic response = responses[methodCall.method]; + if (response != null && response is Exception) { + return Future.error('$response'); + } + return Future.value(response); + }); + log.clear(); + }); + + test('signInSilently transforms platform data to GoogleSignInUserData', + () async { + final dynamic response = await googleSignIn.signInSilently(); + expect(response, kUser); + }); + test('signInSilently Exceptions -> throws', () async { + responses['signInSilently'] = Exception('Not a user'); + expect(googleSignIn.signInSilently(), + throwsA(isInstanceOf())); + }); + + test('signIn transforms platform data to GoogleSignInUserData', () async { + final dynamic response = await googleSignIn.signIn(); + expect(response, kUser); + }); + test('signIn Exceptions -> throws', () async { + responses['signIn'] = Exception('Not a user'); + expect(googleSignIn.signIn(), throwsA(isInstanceOf())); + }); + + test('getTokens transforms platform data to GoogleSignInTokenData', + () async { + final dynamic response = await googleSignIn.getTokens( + email: 'example@example.com', shouldRecoverAuth: false); + expect(response, kToken); + expect( + log[0], + isMethodCall('getTokens', arguments: { + 'email': 'example@example.com', + 'shouldRecoverAuth': false, + })); + }); + + test('Other functions pass through arguments to the channel', () async { + final Map tests = { + () { + googleSignIn.init( + hostedDomain: 'example.com', + scopes: ['two', 'scopes'], + signInOption: SignInOption.games, + clientId: 'UNUSED!'); + }: isMethodCall('init', arguments: { + 'hostedDomain': 'example.com', + 'scopes': ['two', 'scopes'], + 'signInOption': 'SignInOption.games', + }), + () { + googleSignIn.getTokens( + email: 'example@example.com', shouldRecoverAuth: false); + }: isMethodCall('getTokens', arguments: { + 'email': 'example@example.com', + 'shouldRecoverAuth': false, + }), + () { + googleSignIn.clearAuthCache(token: 'abc'); + }: isMethodCall('clearAuthCache', arguments: { + 'token': 'abc', + }), + googleSignIn.signOut: isMethodCall('signOut', arguments: null), + googleSignIn.disconnect: isMethodCall('disconnect', arguments: null), + googleSignIn.isSignedIn: isMethodCall('isSignedIn', arguments: null), + }; + + tests.keys.forEach((Function f) => f()); + + expect(log, tests.values); + }); + }); +} diff --git a/packages/image_picker/CHANGELOG.md b/packages/image_picker/CHANGELOG.md index 418d3a0a57d6..d8a170e47499 100644 --- a/packages/image_picker/CHANGELOG.md +++ b/packages/image_picker/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.6.1+11 + +* Stability and Maintainability: update documentations, add unit tests. + ## 0.6.1+10 * iOS: Fix image orientation problems when scaling images. diff --git a/packages/image_picker/README.md b/packages/image_picker/README.md index 201113b2e771..fa73bfd1658a 100755 --- a/packages/image_picker/README.md +++ b/packages/image_picker/README.md @@ -5,8 +5,6 @@ A Flutter plugin for iOS and Android for picking images from the image library, and taking new pictures with the camera. -*Note*: This plugin is still under development, and some APIs might not be available yet. [Feedback welcome](https://github.com/flutter/flutter/issues) and [Pull Requests](https://github.com/flutter/plugins/pulls) are most welcome! - ## Installation First, add `image_picker` as a [dependency in your pubspec.yaml file](https://flutter.io/platform-plugins/). @@ -67,7 +65,7 @@ class _MyHomePageState extends State { ### Handling MainActivity destruction on Android -Android system -- although very rarely -- sometimes kills the MainActivity after the image_picker finishes. When this happens, we lost the data selected from the image_picker. You can use `retrieveLostData` to retrieve the lost data in this situation. For example: +Android system -- although very rarely -- sometimes kills the MainActivity after the image_picker finishes. When this happens, we lost the data selected from the image_picker. You can use `retrieveLostData` to retrieve the lost data in this situation. For example: ```dart Future retrieveLostData() async { diff --git a/packages/image_picker/lib/image_picker.dart b/packages/image_picker/lib/image_picker.dart index bbe5157f4274..b1a7c8b36c00 100755 --- a/packages/image_picker/lib/image_picker.dart +++ b/packages/image_picker/lib/image_picker.dart @@ -20,6 +20,8 @@ enum ImageSource { gallery, } +/// Provides an easy way to pick an image/video from the image library, +/// or to take a picture/video with the camera. class ImagePicker { static const MethodChannel _channel = MethodChannel('plugins.flutter.io/image_picker'); diff --git a/packages/image_picker/pubspec.yaml b/packages/image_picker/pubspec.yaml index 93379d32fe7e..998d921005a1 100755 --- a/packages/image_picker/pubspec.yaml +++ b/packages/image_picker/pubspec.yaml @@ -5,7 +5,7 @@ authors: - Flutter Team - Rhodes Davis Jr. homepage: https://github.com/flutter/plugins/tree/master/packages/image_picker -version: 0.6.1+10 +version: 0.6.1+11 flutter: plugin: diff --git a/packages/image_picker/test/image_picker_test.dart b/packages/image_picker/test/image_picker_test.dart index 1a40e11d76e1..28eae8eaa46d 100644 --- a/packages/image_picker/test/image_picker_test.dart +++ b/packages/image_picker/test/image_picker_test.dart @@ -143,6 +143,33 @@ void main() { }); }); + group('#pickVideo', () { + test('passes the image source argument correctly', () async { + await ImagePicker.pickVideo(source: ImageSource.camera); + await ImagePicker.pickVideo(source: ImageSource.gallery); + + expect( + log, + [ + isMethodCall('pickVideo', arguments: { + 'source': 0, + }), + isMethodCall('pickVideo', arguments: { + 'source': 1, + }), + ], + ); + }); + + test('handles a null image path response gracefully', () async { + channel.setMockMethodCallHandler((MethodCall methodCall) => null); + + expect( + await ImagePicker.pickVideo(source: ImageSource.gallery), isNull); + expect(await ImagePicker.pickVideo(source: ImageSource.camera), isNull); + }); + }); + group('#retrieveLostData', () { test('retrieveLostData get success response', () async { channel.setMockMethodCallHandler((MethodCall methodCall) async { diff --git a/packages/quick_actions/CHANGELOG.md b/packages/quick_actions/CHANGELOG.md index 0069c0c5165e..c5d442932f6d 100644 --- a/packages/quick_actions/CHANGELOG.md +++ b/packages/quick_actions/CHANGELOG.md @@ -1,3 +1,9 @@ +## 0.3.3 + +* Support Android V2 embedding. +* Add e2e tests. +* Migrate to using the new e2e test binding. + ## 0.3.2+4 * Remove AndroidX warnings. @@ -7,6 +13,7 @@ * Define clang module for iOS. ## 0.3.2+2 + * Fix bug that would make the shortcut not open on Android. * Report shortcut used on Android. * Improves example. @@ -17,7 +24,7 @@ ## 0.3.2 -* Fixed the quick actions launch on Android when the app is killed. +* Fixed the quick actions launch on Android when the app is killed. ## 0.3.1 diff --git a/packages/quick_actions/android/build.gradle b/packages/quick_actions/android/build.gradle index 648b654dbfcd..d474a71c7447 100644 --- a/packages/quick_actions/android/build.gradle +++ b/packages/quick_actions/android/build.gradle @@ -32,3 +32,28 @@ android { disable 'InvalidPackage' } } + +afterEvaluate { + def containsEmbeddingDependencies = false + for (def configuration : configurations.all) { + for (def dependency : configuration.dependencies) { + if (dependency.group == 'io.flutter' && + dependency.name.startsWith('flutter_embedding') && + dependency.isTransitive()) + { + containsEmbeddingDependencies = true + break + } + } + } + if (!containsEmbeddingDependencies) { + android { + dependencies { + def lifecycle_version = "1.1.1" + compileOnly "android.arch.lifecycle:runtime:$lifecycle_version" + compileOnly "android.arch.lifecycle:common:$lifecycle_version" + compileOnly "android.arch.lifecycle:common-java8:$lifecycle_version" + } + } + } +} diff --git a/packages/quick_actions/android/src/main/java/io/flutter/plugins/quickactions/MethodCallHandlerImpl.java b/packages/quick_actions/android/src/main/java/io/flutter/plugins/quickactions/MethodCallHandlerImpl.java new file mode 100644 index 000000000000..dcf2390570bd --- /dev/null +++ b/packages/quick_actions/android/src/main/java/io/flutter/plugins/quickactions/MethodCallHandlerImpl.java @@ -0,0 +1,131 @@ +// 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 io.flutter.plugins.quickactions; + +import android.annotation.TargetApi; +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ShortcutInfo; +import android.content.pm.ShortcutManager; +import android.content.res.Resources; +import android.graphics.drawable.Icon; +import android.os.Build; +import io.flutter.plugin.common.MethodCall; +import io.flutter.plugin.common.MethodChannel; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +class MethodCallHandlerImpl implements MethodChannel.MethodCallHandler { + + private static final String CHANNEL_ID = "plugins.flutter.io/quick_actions"; + private static final String EXTRA_ACTION = "some unique action key"; + + private final Context context; + private Activity activity; + + MethodCallHandlerImpl(Context context, Activity activity) { + this.context = context; + this.activity = activity; + } + + void setActivity(Activity activity) { + this.activity = activity; + } + + @Override + public void onMethodCall(MethodCall call, MethodChannel.Result result) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N_MR1) { + // We already know that this functionality does not work for anything + // lower than API 25 so we chose not to return error. Instead we do nothing. + result.success(null); + return; + } + ShortcutManager shortcutManager = + (ShortcutManager) context.getSystemService(Context.SHORTCUT_SERVICE); + switch (call.method) { + case "setShortcutItems": + List> serializedShortcuts = call.arguments(); + List shortcuts = deserializeShortcuts(serializedShortcuts); + shortcutManager.setDynamicShortcuts(shortcuts); + break; + case "clearShortcutItems": + shortcutManager.removeAllDynamicShortcuts(); + break; + case "getLaunchAction": + if (activity == null) { + result.error( + "quick_action_getlaunchaction_no_activity", + "There is no activity available when launching action", + null); + return; + } + final Intent intent = activity.getIntent(); + final String launchAction = intent.getStringExtra(EXTRA_ACTION); + if (launchAction != null && !launchAction.isEmpty()) { + shortcutManager.reportShortcutUsed(launchAction); + intent.removeExtra(EXTRA_ACTION); + } + result.success(launchAction); + return; + default: + result.notImplemented(); + return; + } + result.success(null); + } + + @TargetApi(Build.VERSION_CODES.N_MR1) + private List deserializeShortcuts(List> shortcuts) { + final List shortcutInfos = new ArrayList<>(); + + for (Map shortcut : shortcuts) { + final String icon = shortcut.get("icon"); + final String type = shortcut.get("type"); + final String title = shortcut.get("localizedTitle"); + final ShortcutInfo.Builder shortcutBuilder = new ShortcutInfo.Builder(context, type); + + final int resourceId = loadResourceId(context, icon); + final Intent intent = getIntentToOpenMainActivity(type); + + if (resourceId > 0) { + shortcutBuilder.setIcon(Icon.createWithResource(context, resourceId)); + } + + final ShortcutInfo shortcutInfo = + shortcutBuilder.setLongLabel(title).setShortLabel(title).setIntent(intent).build(); + shortcutInfos.add(shortcutInfo); + } + return shortcutInfos; + } + + private int loadResourceId(Context context, String icon) { + if (icon == null) { + return 0; + } + final String packageName = context.getPackageName(); + final Resources res = context.getResources(); + final int resourceId = res.getIdentifier(icon, "drawable", packageName); + + if (resourceId == 0) { + return res.getIdentifier(icon, "mipmap", packageName); + } else { + return resourceId; + } + } + + private Intent getIntentToOpenMainActivity(String type) { + final String packageName = context.getPackageName(); + + return context + .getPackageManager() + .getLaunchIntentForPackage(packageName) + .setAction(Intent.ACTION_RUN) + .putExtra(EXTRA_ACTION, type) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); + } +} diff --git a/packages/quick_actions/android/src/main/java/io/flutter/plugins/quickactions/QuickActionsPlugin.java b/packages/quick_actions/android/src/main/java/io/flutter/plugins/quickactions/QuickActionsPlugin.java index 3a4ba2410666..76285fb90d10 100644 --- a/packages/quick_actions/android/src/main/java/io/flutter/plugins/quickactions/QuickActionsPlugin.java +++ b/packages/quick_actions/android/src/main/java/io/flutter/plugins/quickactions/QuickActionsPlugin.java @@ -4,33 +4,21 @@ package io.flutter.plugins.quickactions; -import android.annotation.TargetApi; +import android.app.Activity; import android.content.Context; -import android.content.Intent; -import android.content.pm.ShortcutInfo; -import android.content.pm.ShortcutManager; -import android.content.res.Resources; -import android.graphics.drawable.Icon; -import android.os.Build; -import io.flutter.plugin.common.MethodCall; +import io.flutter.embedding.engine.plugins.FlutterPlugin; +import io.flutter.embedding.engine.plugins.activity.ActivityAware; +import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding; +import io.flutter.plugin.common.BinaryMessenger; import io.flutter.plugin.common.MethodChannel; -import io.flutter.plugin.common.MethodChannel.MethodCallHandler; -import io.flutter.plugin.common.MethodChannel.Result; import io.flutter.plugin.common.PluginRegistry.Registrar; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; /** QuickActionsPlugin */ -public class QuickActionsPlugin implements MethodCallHandler { +public class QuickActionsPlugin implements FlutterPlugin, ActivityAware { private static final String CHANNEL_ID = "plugins.flutter.io/quick_actions"; - private static final String EXTRA_ACTION = "some unique action key"; - private final Registrar registrar; - - private QuickActionsPlugin(Registrar registrar) { - this.registrar = registrar; - } + private MethodChannel channel; + private MethodCallHandlerImpl handler; /** * Plugin registration. @@ -38,96 +26,50 @@ private QuickActionsPlugin(Registrar registrar) { *

Must be called when the application is created. */ public static void registerWith(Registrar registrar) { - final MethodChannel channel = new MethodChannel(registrar.messenger(), CHANNEL_ID); - channel.setMethodCallHandler(new QuickActionsPlugin(registrar)); + final QuickActionsPlugin plugin = new QuickActionsPlugin(); + plugin.setupChannel(registrar.messenger(), registrar.context(), registrar.activity()); } @Override - public void onMethodCall(MethodCall call, Result result) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N_MR1) { - // We already know that this functionality does not work for anything - // lower than API 25 so we chose not to return error. Instead we do nothing. - result.success(null); - return; - } - Context context = registrar.context(); - ShortcutManager shortcutManager = - (ShortcutManager) context.getSystemService(Context.SHORTCUT_SERVICE); - switch (call.method) { - case "setShortcutItems": - List> serializedShortcuts = call.arguments(); - List shortcuts = deserializeShortcuts(serializedShortcuts); - shortcutManager.setDynamicShortcuts(shortcuts); - break; - case "clearShortcutItems": - shortcutManager.removeAllDynamicShortcuts(); - break; - case "getLaunchAction": - final Intent intent = registrar.activity().getIntent(); - final String launchAction = intent.getStringExtra(EXTRA_ACTION); - if (launchAction != null && !launchAction.isEmpty()) { - shortcutManager.reportShortcutUsed(launchAction); - intent.removeExtra(EXTRA_ACTION); - } - result.success(launchAction); - return; - default: - result.notImplemented(); - return; - } - result.success(null); + public void onAttachedToEngine(FlutterPluginBinding binding) { + setupChannel( + binding.getFlutterEngine().getDartExecutor(), binding.getApplicationContext(), null); } - @TargetApi(Build.VERSION_CODES.N_MR1) - private List deserializeShortcuts(List> shortcuts) { - final List shortcutInfos = new ArrayList<>(); - final Context context = registrar.context(); - - for (Map shortcut : shortcuts) { - final String icon = shortcut.get("icon"); - final String type = shortcut.get("type"); - final String title = shortcut.get("localizedTitle"); - final ShortcutInfo.Builder shortcutBuilder = new ShortcutInfo.Builder(context, type); - - final int resourceId = loadResourceId(context, icon); - final Intent intent = getIntentToOpenMainActivity(type); + @Override + public void onDetachedFromEngine(FlutterPluginBinding binding) { + teardownChannel(); + } - if (resourceId > 0) { - shortcutBuilder.setIcon(Icon.createWithResource(context, resourceId)); - } + @Override + public void onAttachedToActivity(ActivityPluginBinding binding) { + handler.setActivity(binding.getActivity()); + } - final ShortcutInfo shortcutInfo = - shortcutBuilder.setLongLabel(title).setShortLabel(title).setIntent(intent).build(); - shortcutInfos.add(shortcutInfo); - } - return shortcutInfos; + @Override + public void onDetachedFromActivity() { + handler.setActivity(null); } - private int loadResourceId(Context context, String icon) { - if (icon == null) { - return 0; - } - final String packageName = context.getPackageName(); - final Resources res = context.getResources(); - final int resourceId = res.getIdentifier(icon, "drawable", packageName); + @Override + public void onReattachedToActivityForConfigChanges(ActivityPluginBinding binding) { + onAttachedToActivity(binding); + } - if (resourceId == 0) { - return res.getIdentifier(icon, "mipmap", packageName); - } else { - return resourceId; - } + @Override + public void onDetachedFromActivityForConfigChanges() { + onDetachedFromActivity(); } - private Intent getIntentToOpenMainActivity(String type) { - final Context context = registrar.context(); - final String packageName = context.getPackageName(); + private void setupChannel(BinaryMessenger messenger, Context context, Activity activity) { + channel = new MethodChannel(messenger, CHANNEL_ID); + handler = new MethodCallHandlerImpl(context, activity); + channel.setMethodCallHandler(handler); + } - return context - .getPackageManager() - .getLaunchIntentForPackage(packageName) - .setAction(Intent.ACTION_RUN) - .putExtra(EXTRA_ACTION, type) - .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); + private void teardownChannel() { + channel.setMethodCallHandler(null); + channel = null; + handler = null; } } diff --git a/packages/quick_actions/example/android/app/src/main/AndroidManifest.xml b/packages/quick_actions/example/android/app/src/main/AndroidManifest.xml index bb7a1351d343..6c70f1b650cd 100644 --- a/packages/quick_actions/example/android/app/src/main/AndroidManifest.xml +++ b/packages/quick_actions/example/android/app/src/main/AndroidManifest.xml @@ -6,15 +6,22 @@ - + android:windowSoftInputMode="adjustResize" + android:exported="true"> + + diff --git a/packages/quick_actions/example/android/app/src/main/java/io/flutter/plugins/quickactionsexample/EmbeddingV1Activity.java b/packages/quick_actions/example/android/app/src/main/java/io/flutter/plugins/quickactionsexample/EmbeddingV1Activity.java new file mode 100644 index 000000000000..ba6a64d997bc --- /dev/null +++ b/packages/quick_actions/example/android/app/src/main/java/io/flutter/plugins/quickactionsexample/EmbeddingV1Activity.java @@ -0,0 +1,17 @@ +// 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 io.flutter.plugins.quickactionsexample; + +import android.os.Bundle; +import io.flutter.app.FlutterActivity; +import io.flutter.plugins.GeneratedPluginRegistrant; + +public class EmbeddingV1Activity extends FlutterActivity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + GeneratedPluginRegistrant.registerWith(this); + } +} diff --git a/packages/quick_actions/example/android/app/src/main/java/io/flutter/plugins/quickactionsexample/EmbeddingV1ActivityTest.java b/packages/quick_actions/example/android/app/src/main/java/io/flutter/plugins/quickactionsexample/EmbeddingV1ActivityTest.java new file mode 100644 index 000000000000..b3e2a08c44b4 --- /dev/null +++ b/packages/quick_actions/example/android/app/src/main/java/io/flutter/plugins/quickactionsexample/EmbeddingV1ActivityTest.java @@ -0,0 +1,17 @@ +// 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 io.flutter.plugins.quickactionsexample; + +import androidx.test.rule.ActivityTestRule; +import dev.flutter.plugins.e2e.FlutterRunner; +import org.junit.Rule; +import org.junit.runner.RunWith; + +@RunWith(FlutterRunner.class) +public class EmbeddingV1ActivityTest { + @Rule + public ActivityTestRule rule = + new ActivityTestRule<>(EmbeddingV1Activity.class); +} diff --git a/packages/quick_actions/example/android/app/src/main/java/io/flutter/plugins/quickactionsexample/MainActivity.java b/packages/quick_actions/example/android/app/src/main/java/io/flutter/plugins/quickactionsexample/MainActivity.java index 74e3eb873cbc..ce128b60648e 100644 --- a/packages/quick_actions/example/android/app/src/main/java/io/flutter/plugins/quickactionsexample/MainActivity.java +++ b/packages/quick_actions/example/android/app/src/main/java/io/flutter/plugins/quickactionsexample/MainActivity.java @@ -1,17 +1,20 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// 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 io.flutter.plugins.quickactionsexample; -import android.os.Bundle; -import io.flutter.app.FlutterActivity; -import io.flutter.plugins.GeneratedPluginRegistrant; +import io.flutter.embedding.android.FlutterActivity; +import io.flutter.embedding.engine.FlutterEngine; +import io.flutter.plugins.quickactions.QuickActionsPlugin; public class MainActivity extends FlutterActivity { + + // TODO(cyanglaz): Remove this once v2 of GeneratedPluginRegistrant rolls to stable. + // https://github.com/flutter/flutter/issues/42694 @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - GeneratedPluginRegistrant.registerWith(this); + public void configureFlutterEngine(FlutterEngine flutterEngine) { + super.configureFlutterEngine(flutterEngine); + flutterEngine.getPlugins().add(new QuickActionsPlugin()); } } diff --git a/packages/quick_actions/example/android/app/src/main/java/io/flutter/plugins/quickactionsexample/MainActivityTest.java b/packages/quick_actions/example/android/app/src/main/java/io/flutter/plugins/quickactionsexample/MainActivityTest.java new file mode 100644 index 000000000000..4d3e1822d616 --- /dev/null +++ b/packages/quick_actions/example/android/app/src/main/java/io/flutter/plugins/quickactionsexample/MainActivityTest.java @@ -0,0 +1,15 @@ +// 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 io.flutter.plugins.quickactionsexample; + +import androidx.test.rule.ActivityTestRule; +import dev.flutter.plugins.e2e.FlutterRunner; +import org.junit.Rule; +import org.junit.runner.RunWith; + +@RunWith(FlutterRunner.class) +public class MainActivityTest { + @Rule public ActivityTestRule rule = new ActivityTestRule<>(MainActivity.class); +} diff --git a/packages/quick_actions/example/android/gradle.properties b/packages/quick_actions/example/android/gradle.properties index 8bd86f680510..38c8d4544ff1 100644 --- a/packages/quick_actions/example/android/gradle.properties +++ b/packages/quick_actions/example/android/gradle.properties @@ -1 +1,4 @@ org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +android.useAndroidX=true +android.enableJetifier=true diff --git a/packages/quick_actions/example/pubspec.yaml b/packages/quick_actions/example/pubspec.yaml index b5fe2e1a8545..6cbacb5b84d2 100644 --- a/packages/quick_actions/example/pubspec.yaml +++ b/packages/quick_actions/example/pubspec.yaml @@ -7,5 +7,14 @@ dependencies: quick_actions: path: ../ +dev_dependencies: + flutter_driver: + sdk: flutter + e2e: ^0.2.0 + flutter: uses-material-design: true + +environment: + sdk: ">=2.0.0-dev.28.0 <3.0.0" + flutter: ">=1.9.1+hotfix.2 <2.0.0" diff --git a/packages/quick_actions/example/test_driver/quick_actions_e2e.dart b/packages/quick_actions/example/test_driver/quick_actions_e2e.dart new file mode 100644 index 000000000000..41d35b874640 --- /dev/null +++ b/packages/quick_actions/example/test_driver/quick_actions_e2e.dart @@ -0,0 +1,24 @@ +// Copyright 2019, the Chromium project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:flutter_test/flutter_test.dart'; +import 'package:e2e/e2e.dart'; +import 'package:quick_actions/quick_actions.dart'; + +void main() { + E2EWidgetsFlutterBinding.ensureInitialized(); + + testWidgets('Can set shortcuts', (WidgetTester tester) async { + final QuickActions quickActions = QuickActions(); + quickActions.initialize(null); + + const ShortcutItem shortCutItem = ShortcutItem( + type: 'action_one', + localizedTitle: 'Action one', + icon: 'AppIcon', + ); + expect( + quickActions.setShortcutItems([shortCutItem]), completes); + }); +} diff --git a/packages/quick_actions/example/test_driver/quick_actions_e2e_test.dart b/packages/quick_actions/example/test_driver/quick_actions_e2e_test.dart new file mode 100644 index 000000000000..ff6e9ce74ad9 --- /dev/null +++ b/packages/quick_actions/example/test_driver/quick_actions_e2e_test.dart @@ -0,0 +1,15 @@ +// Copyright 2019, the Chromium project authors. Please see the AUTHORS file +// for details. 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 'dart:io'; +import 'package:flutter_driver/flutter_driver.dart'; + +Future main() async { + final FlutterDriver driver = await FlutterDriver.connect(); + final String result = + await driver.requestData(null, timeout: const Duration(minutes: 1)); + driver.close(); + exit(result == 'pass' ? 0 : 1); +} diff --git a/packages/quick_actions/pubspec.yaml b/packages/quick_actions/pubspec.yaml index da725aa55790..c11596b82f47 100644 --- a/packages/quick_actions/pubspec.yaml +++ b/packages/quick_actions/pubspec.yaml @@ -3,7 +3,7 @@ description: Flutter plugin for creating shortcuts on home screen, also known as Quick Actions on iOS and App Shortcuts on Android. author: Flutter Team homepage: https://github.com/flutter/plugins/tree/master/packages/quick_actions -version: 0.3.2+4 +version: 0.3.3 flutter: plugin: @@ -21,7 +21,8 @@ dev_dependencies: mockito: ^3.0.0 flutter_test: sdk: flutter + e2e: ^0.2.0 environment: sdk: ">=2.0.0-dev.28.0 <3.0.0" - flutter: ">=1.5.0 <2.0.0" + flutter: ">=1.6.7 <2.0.0" diff --git a/packages/shared_preferences/CHANGELOG.md b/packages/shared_preferences/CHANGELOG.md index 9015bd836daa..5560dd8a4317 100644 --- a/packages/shared_preferences/CHANGELOG.md +++ b/packages/shared_preferences/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.5.4+4 + +* `setMockInitialValues` needs to handle non-prefixed keys since that's an implementation detail. + ## 0.5.4+3 * Android: Suppress casting warnings. diff --git a/packages/shared_preferences/README.md b/packages/shared_preferences/README.md index 136c6de3dd99..dfd449337293 100644 --- a/packages/shared_preferences/README.md +++ b/packages/shared_preferences/README.md @@ -42,11 +42,5 @@ _incrementCounter() async { You can populate `SharedPreferences` with initial values in your tests by running this code: ```dart -const MethodChannel('plugins.flutter.io/shared_preferences') - .setMockMethodCallHandler((MethodCall methodCall) async { - if (methodCall.method == 'getAll') { - return {}; // set initial values here if desired - } - return null; - }); +SharedPrefernces.setMockInitialValues (Map values); ``` diff --git a/packages/shared_preferences/lib/shared_preferences.dart b/packages/shared_preferences/lib/shared_preferences.dart index aece19b6e29e..3fe176f41f25 100644 --- a/packages/shared_preferences/lib/shared_preferences.dart +++ b/packages/shared_preferences/lib/shared_preferences.dart @@ -181,9 +181,17 @@ class SharedPreferences { /// If the singleton instance has been initialized already, it is nullified. @visibleForTesting static void setMockInitialValues(Map values) { + final Map newValues = + values.map((String key, dynamic value) { + String newKey = key; + if (!key.startsWith(_prefix)) { + newKey = '$_prefix$key'; + } + return MapEntry(newKey, value); + }); _kChannel.setMockMethodCallHandler((MethodCall methodCall) async { if (methodCall.method == 'getAll') { - return values; + return newValues; } return null; }); diff --git a/packages/shared_preferences/pubspec.yaml b/packages/shared_preferences/pubspec.yaml index 9df0c19f1a3a..80bfc6d219e3 100644 --- a/packages/shared_preferences/pubspec.yaml +++ b/packages/shared_preferences/pubspec.yaml @@ -3,7 +3,7 @@ description: Flutter plugin for reading and writing simple key-value pairs. Wraps NSUserDefaults on iOS and SharedPreferences on Android. author: Flutter Team homepage: https://github.com/flutter/plugins/tree/master/packages/shared_preferences -version: 0.5.4+3 +version: 0.5.4+4 flutter: plugin: diff --git a/packages/shared_preferences/test/shared_preferences_test.dart b/packages/shared_preferences/test/shared_preferences_test.dart index 8ebcb96c0ad8..d171f7ae7f05 100755 --- a/packages/shared_preferences/test/shared_preferences_test.dart +++ b/packages/shared_preferences/test/shared_preferences_test.dart @@ -197,4 +197,13 @@ void main() { expect(preferences.getStringList('myList'), []); }); }); + + test('calling mock initial values with non-prefixed keys succeeds', () async { + SharedPreferences.setMockInitialValues({ + 'test': 'foo', + }); + final SharedPreferences prefs = await SharedPreferences.getInstance(); + final String value = prefs.getString('test'); + expect(value, 'foo'); + }); }