diff --git a/.gitignore b/.gitignore index ccb0eeb34605..734169649fd3 100644 --- a/.gitignore +++ b/.gitignore @@ -22,6 +22,7 @@ Pods/ ServiceDefinitions.json xcuserdata/ *.xcworkspace +**/DerivedData/ local.properties keystore.properties diff --git a/.opensource/project.json b/.opensource/project.json index 19da74a6cafd..b00f3a46f6ea 100644 --- a/.opensource/project.json +++ b/.opensource/project.json @@ -1,24 +1,11 @@ { - "name": "FlutterFire", + "name": "FlutterFire - MOVED", "platforms": [ "Android", "iOS" ], "content": "FlutterFire.md", - "pages": { - "packages/cloud_firestore/README.md": "Cloud Firestore", - "packages/cloud_functions/README.md": "Cloud Functions", - "packages/firebase_admob/README.md": "Admob", - "packages/firebase_analytics/README.md": "Analytics", - "packages/firebase_auth/README.md": "Authentication", - "packages/firebase_core/README.md": "Core", - "packages/firebase_crashlytics/README.md": "Crashlytics", - "packages/firebase_database/README.md": "Realtime Database", - "packages/firebase_dynamic_links/README.md": "Dynamic Links", - "packages/firebase_messaging/README.md": "Cloud Messaging", - "packages/firebase_ml_vision/README.md": "ML Kit: Vision", - "packages/firebase_performance/README.md": "Performance Monitoring", - "packages/firebase_remote_config/README.md": "Remote Config", - "packages/firebase_storage/README.md": "Cloud Storage" - } + "related": [ + "FirebaseExtended/flutterfire" + ] } diff --git a/FlutterFire.md b/FlutterFire.md new file mode 100644 index 000000000000..00326167e7ab --- /dev/null +++ b/FlutterFire.md @@ -0,0 +1,6 @@ +# FlutterFire - MOVED + +The FlutterFire family of plugins has moved to the FirebaseExtended organization on GitHub. This makes it easier for us to collaborate with the Firebase team. We want to build the best integration we can! + +Visit FlutterFire at its new home: +https://github.com/FirebaseExtended/flutterfire \ No newline at end of file diff --git a/examples/all_plugins/android/gradle.properties b/examples/all_plugins/android/gradle.properties deleted file mode 100644 index bb0411185aea..000000000000 --- a/examples/all_plugins/android/gradle.properties +++ /dev/null @@ -1,4 +0,0 @@ -android.enableJetifier=true -android.useAndroidX=true -org.gradle.jvmargs=-Xmx1536M - diff --git a/examples/all_plugins/ios/Flutter/Debug.xcconfig b/examples/all_plugins/ios/Flutter/Debug.xcconfig deleted file mode 100644 index 592ceee85b89..000000000000 --- a/examples/all_plugins/ios/Flutter/Debug.xcconfig +++ /dev/null @@ -1 +0,0 @@ -#include "Generated.xcconfig" diff --git a/examples/all_plugins/ios/Flutter/Release.xcconfig b/examples/all_plugins/ios/Flutter/Release.xcconfig deleted file mode 100644 index 592ceee85b89..000000000000 --- a/examples/all_plugins/ios/Flutter/Release.xcconfig +++ /dev/null @@ -1 +0,0 @@ -#include "Generated.xcconfig" diff --git a/examples/all_plugins/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/examples/all_plugins/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 1d526a16ed0f..000000000000 --- a/examples/all_plugins/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/examples/all_plugins/ios/Runner.xcworkspace/contents.xcworkspacedata b/examples/all_plugins/ios/Runner.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 1d526a16ed0f..000000000000 --- a/examples/all_plugins/ios/Runner.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/examples/all_plugins/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/examples/all_plugins/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png deleted file mode 100644 index 3d43d11e66f4..000000000000 Binary files a/examples/all_plugins/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png and /dev/null differ diff --git a/examples/all_plugins/lib/main.dart b/examples/all_plugins/lib/main.dart deleted file mode 100644 index f4ebf1dd00e1..000000000000 --- a/examples/all_plugins/lib/main.dart +++ /dev/null @@ -1,111 +0,0 @@ -import 'package:flutter/material.dart'; - -void main() => runApp(MyApp()); - -class MyApp extends StatelessWidget { - // This widget is the root of your application. - @override - Widget build(BuildContext context) { - return MaterialApp( - title: 'Flutter Demo', - theme: ThemeData( - // This is the theme of your application. - // - // Try running your application with "flutter run". You'll see the - // application has a blue toolbar. Then, without quitting the app, try - // changing the primarySwatch below to Colors.green and then invoke - // "hot reload" (press "r" in the console where you ran "flutter run", - // or simply save your changes to "hot reload" in a Flutter IDE). - // Notice that the counter didn't reset back to zero; the application - // is not restarted. - primarySwatch: Colors.blue, - ), - home: MyHomePage(title: 'Flutter Demo Home Page'), - ); - } -} - -class MyHomePage extends StatefulWidget { - MyHomePage({Key key, this.title}) : super(key: key); - - // This widget is the home page of your application. It is stateful, meaning - // that it has a State object (defined below) that contains fields that affect - // how it looks. - - // This class is the configuration for the state. It holds the values (in this - // case the title) provided by the parent (in this case the App widget) and - // used by the build method of the State. Fields in a Widget subclass are - // always marked "final". - - final String title; - - @override - _MyHomePageState createState() => _MyHomePageState(); -} - -class _MyHomePageState extends State { - int _counter = 0; - - void _incrementCounter() { - setState(() { - // This call to setState tells the Flutter framework that something has - // changed in this State, which causes it to rerun the build method below - // so that the display can reflect the updated values. If we changed - // _counter without calling setState(), then the build method would not be - // called again, and so nothing would appear to happen. - _counter++; - }); - } - - @override - Widget build(BuildContext context) { - // This method is rerun every time setState is called, for instance as done - // by the _incrementCounter method above. - // - // The Flutter framework has been optimized to make rerunning build methods - // fast, so that you can just rebuild anything that needs updating rather - // than having to individually change instances of widgets. - return Scaffold( - appBar: AppBar( - // Here we take the value from the MyHomePage object that was created by - // the App.build method, and use it to set our appbar title. - title: Text(widget.title), - ), - body: Center( - // Center is a layout widget. It takes a single child and positions it - // in the middle of the parent. - child: Column( - // Column is also layout widget. It takes a list of children and - // arranges them vertically. By default, it sizes itself to fit its - // children horizontally, and tries to be as tall as its parent. - // - // Invoke "debug painting" (press "p" in the console, choose the - // "Toggle Debug Paint" action from the Flutter Inspector in Android - // Studio, or the "Toggle Debug Paint" command in Visual Studio Code) - // to see the wireframe for each widget. - // - // Column has various properties to control how it sizes itself and - // how it positions its children. Here we use mainAxisAlignment to - // center the children vertically; the main axis here is the vertical - // axis because Columns are vertical (the cross axis would be - // horizontal). - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - 'You have pushed the button this many times:', - ), - Text( - '$_counter', - style: Theme.of(context).textTheme.display1, - ), - ], - ), - ), - floatingActionButton: FloatingActionButton( - onPressed: _incrementCounter, - tooltip: 'Increment', - child: Icon(Icons.add), - ), // This trailing comma makes auto-formatting nicer for build methods. - ); - } -} diff --git a/examples/all_plugins/pubspec.yaml b/examples/all_plugins/pubspec.yaml deleted file mode 100644 index 75fa414088ac..000000000000 --- a/examples/all_plugins/pubspec.yaml +++ /dev/null @@ -1 +0,0 @@ -### Generated file. Run `pub global run flutter_plugin_tools gen-pubspec`. diff --git a/packages/android_intent/CHANGELOG.md b/packages/android_intent/CHANGELOG.md index 7a818f38548a..82b4774ee29d 100644 --- a/packages/android_intent/CHANGELOG.md +++ b/packages/android_intent/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.3.3+1 + +* Added "action_application_details_settings" action to open application info settings . + ## 0.3.3 * Added "flags" option to call intent.addFlags(int) in native. diff --git a/packages/android_intent/README.md b/packages/android_intent/README.md index 5a9243e6914b..a6e4a4206a6e 100644 --- a/packages/android_intent/README.md +++ b/packages/android_intent/README.md @@ -29,6 +29,19 @@ for it in the plugin and use an action constant to refer to it. For instance: `'action_location_source_settings'` translates to `android.settings.LOCATION_SOURCE_SETTINGS` +`'action_application_details_settings'` translates to `android.settings.ACTION_APPLICATION_DETAILS_SETTINGS` + +```dart +if (platform.isAndroid) { + final AndroidIntent intent = AndroidIntent( + action: 'action_application_details_settings', + data: 'package:com.example.app', // replace com.example.app with your applicationId + ); + await intent.launch(); +} + +``` + Feel free to add support for additional Android intents. The Dart values supported for the arguments parameter, and their corresponding diff --git a/packages/android_intent/android/src/main/java/io/flutter/plugins/androidintent/AndroidIntentPlugin.java b/packages/android_intent/android/src/main/java/io/flutter/plugins/androidintent/AndroidIntentPlugin.java index a66116cdceeb..b6d3c81b1a8c 100644 --- a/packages/android_intent/android/src/main/java/io/flutter/plugins/androidintent/AndroidIntentPlugin.java +++ b/packages/android_intent/android/src/main/java/io/flutter/plugins/androidintent/AndroidIntentPlugin.java @@ -46,6 +46,8 @@ private String convertAction(String action) { return Settings.ACTION_SETTINGS; case "action_location_source_settings": return Settings.ACTION_LOCATION_SOURCE_SETTINGS; + case "action_application_details_settings": + return Settings.ACTION_APPLICATION_DETAILS_SETTINGS; default: return action; } diff --git a/packages/android_intent/example/lib/main.dart b/packages/android_intent/example/lib/main.dart index becf3d6e1e75..f56cffd2bd20 100644 --- a/packages/android_intent/example/lib/main.dart +++ b/packages/android_intent/example/lib/main.dart @@ -142,6 +142,14 @@ class ExplicitIntentsWidget extends StatelessWidget { intent.launch(); } + void _openApplicationDetails() { + final AndroidIntent intent = const AndroidIntent( + action: 'action_application_details_settings', + data: 'package:io.flutter.plugins.androidintentexample', + ); + intent.launch(); + } + @override Widget build(BuildContext context) { return Scaffold( @@ -186,6 +194,12 @@ class ExplicitIntentsWidget extends StatelessWidget { 'Tap here to open Location Settings Configuration', ), onPressed: _openLocationSettingsConfiguration, + ), + RaisedButton( + child: const Text( + 'Tap here to open Application Details', + ), + onPressed: _openApplicationDetails, ) ], ), diff --git a/packages/android_intent/pubspec.yaml b/packages/android_intent/pubspec.yaml index 11cbc319bbf0..3da7690f2c0d 100644 --- a/packages/android_intent/pubspec.yaml +++ b/packages/android_intent/pubspec.yaml @@ -2,7 +2,7 @@ name: android_intent description: Flutter plugin for launching Android Intents. Not supported on iOS. author: Flutter Team homepage: https://github.com/flutter/plugins/tree/master/packages/android_intent -version: 0.3.3 +version: 0.3.3+1 flutter: plugin: diff --git a/packages/google_maps_flutter/CHANGELOG.md b/packages/google_maps_flutter/CHANGELOG.md index c88a00be904a..addc8831efe3 100644 --- a/packages/google_maps_flutter/CHANGELOG.md +++ b/packages/google_maps_flutter/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.5.21+1 + +* Fix `prefer_const_constructors` analyzer warnings in example app. + ## 0.5.21 * Don't recreate map elements if they didn't change since last widget build. diff --git a/packages/google_maps_flutter/example/lib/padding.dart b/packages/google_maps_flutter/example/lib/padding.dart index be45cb38d0c1..599f8a564b6e 100644 --- a/packages/google_maps_flutter/example/lib/padding.dart +++ b/packages/google_maps_flutter/example/lib/padding.dart @@ -93,7 +93,7 @@ class MarkerIconsBodyState extends State { controller: _topController, keyboardType: TextInputType.number, textAlign: TextAlign.center, - decoration: InputDecoration( + decoration: const InputDecoration( hintText: "Top", ), ), @@ -105,7 +105,7 @@ class MarkerIconsBodyState extends State { controller: _bottomController, keyboardType: TextInputType.number, textAlign: TextAlign.center, - decoration: InputDecoration( + decoration: const InputDecoration( hintText: "Bottom", ), ), @@ -117,7 +117,7 @@ class MarkerIconsBodyState extends State { controller: _leftController, keyboardType: TextInputType.number, textAlign: TextAlign.center, - decoration: InputDecoration( + decoration: const InputDecoration( hintText: "Left", ), ), @@ -129,7 +129,7 @@ class MarkerIconsBodyState extends State { controller: _rightController, keyboardType: TextInputType.number, textAlign: TextAlign.center, - decoration: InputDecoration( + decoration: const InputDecoration( hintText: "Right", ), ), diff --git a/packages/google_maps_flutter/pubspec.yaml b/packages/google_maps_flutter/pubspec.yaml index f8a852998d42..a72cb71fdd78 100644 --- a/packages/google_maps_flutter/pubspec.yaml +++ b/packages/google_maps_flutter/pubspec.yaml @@ -2,7 +2,7 @@ name: google_maps_flutter description: A Flutter plugin for integrating Google Maps in iOS and Android applications. author: Flutter Team homepage: https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter -version: 0.5.21 +version: 0.5.21+1 dependencies: flutter: diff --git a/packages/in_app_purchase/CHANGELOG.md b/packages/in_app_purchase/CHANGELOG.md index fbbb870dcbe0..2f0e89e1cdec 100644 --- a/packages/in_app_purchase/CHANGELOG.md +++ b/packages/in_app_purchase/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.2.1+3 + +* Android : Improved testability. + ## 0.2.1+2 * Android: Require a non-null Activity to use the `launchBillingFlow` method. diff --git a/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/BillingClientFactory.java b/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/BillingClientFactory.java new file mode 100644 index 000000000000..078986c04c86 --- /dev/null +++ b/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/BillingClientFactory.java @@ -0,0 +1,19 @@ +package io.flutter.plugins.inapppurchase; + +import android.content.Context; +import com.android.billingclient.api.BillingClient; +import io.flutter.plugin.common.MethodChannel; + +interface BillingClientFactory { + BillingClient createBillingClient(Context context, MethodChannel channel); +} + +final class BillingClientFactoryImpl implements BillingClientFactory { + + @Override + public BillingClient createBillingClient(Context context, MethodChannel channel) { + return BillingClient.newBuilder(context) + .setListener(new PluginPurchaseListener(channel)) + .build(); + } +} diff --git a/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/InAppPurchasePlugin.java b/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/InAppPurchasePlugin.java index e914d2a455de..99f68842d1c0 100644 --- a/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/InAppPurchasePlugin.java +++ b/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/InAppPurchasePlugin.java @@ -19,7 +19,6 @@ import com.android.billingclient.api.ConsumeResponseListener; import com.android.billingclient.api.Purchase; import com.android.billingclient.api.PurchaseHistoryResponseListener; -import com.android.billingclient.api.PurchasesUpdatedListener; import com.android.billingclient.api.SkuDetails; import com.android.billingclient.api.SkuDetailsParams; import com.android.billingclient.api.SkuDetailsResponseListener; @@ -37,6 +36,7 @@ public class InAppPurchasePlugin implements MethodCallHandler { private static final String TAG = "InAppPurchasePlugin"; private @Nullable BillingClient billingClient; + private final BillingClientFactory factory; private final Registrar registrar; private final Context applicationContext; private final MethodChannel channel; @@ -69,12 +69,17 @@ static final class MethodNames { public static void registerWith(Registrar registrar) { final MethodChannel channel = new MethodChannel(registrar.messenger(), "plugins.flutter.io/in_app_purchase"); - channel.setMethodCallHandler(new InAppPurchasePlugin(registrar, channel)); + + final BillingClientFactory factory = new BillingClientFactoryImpl(); + final InAppPurchasePlugin plugin = new InAppPurchasePlugin(factory, registrar, channel); + channel.setMethodCallHandler(plugin); } - public InAppPurchasePlugin(Registrar registrar, MethodChannel channel) { + public InAppPurchasePlugin( + BillingClientFactory factory, Registrar registrar, MethodChannel channel) { this.applicationContext = registrar.context(); this.registrar = registrar; + this.factory = factory; this.channel = channel; } @@ -112,18 +117,9 @@ public void onMethodCall(MethodCall call, Result result) { } } - @VisibleForTesting - /*package*/ InAppPurchasePlugin( - Registrar registrar, @Nullable BillingClient billingClient, MethodChannel channel) { - this.billingClient = billingClient; - this.channel = channel; - this.applicationContext = registrar.context(); - this.registrar = registrar; - } - private void startConnection(final int handle, final Result result) { if (billingClient == null) { - billingClient = buildBillingClient(applicationContext, channel); + billingClient = factory.createBillingClient(applicationContext, channel); } billingClient.startConnection( @@ -282,27 +278,4 @@ private boolean billingClientError(Result result) { result.error("UNAVAILABLE", "BillingClient is unset. Try reconnecting.", null); return true; } - - private static BillingClient buildBillingClient(Context context, MethodChannel channel) { - return BillingClient.newBuilder(context) - .setListener(new PluginPurchaseListener(channel)) - .build(); - } - - @VisibleForTesting - /*package*/ static class PluginPurchaseListener implements PurchasesUpdatedListener { - private final MethodChannel channel; - - PluginPurchaseListener(MethodChannel channel) { - this.channel = channel; - } - - @Override - public void onPurchasesUpdated(int responseCode, @Nullable List purchases) { - final Map callbackArgs = new HashMap<>(); - callbackArgs.put("responseCode", responseCode); - callbackArgs.put("purchasesList", fromPurchasesList(purchases)); - channel.invokeMethod(MethodNames.ON_PURCHASES_UPDATED, callbackArgs); - } - } } diff --git a/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/PluginPurchaseListener.java b/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/PluginPurchaseListener.java new file mode 100644 index 000000000000..f1de27eaacc8 --- /dev/null +++ b/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/PluginPurchaseListener.java @@ -0,0 +1,27 @@ +package io.flutter.plugins.inapppurchase; + +import static io.flutter.plugins.inapppurchase.Translator.fromPurchasesList; + +import androidx.annotation.Nullable; +import com.android.billingclient.api.Purchase; +import com.android.billingclient.api.PurchasesUpdatedListener; +import io.flutter.plugin.common.MethodChannel; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +class PluginPurchaseListener implements PurchasesUpdatedListener { + private final MethodChannel channel; + + PluginPurchaseListener(MethodChannel channel) { + this.channel = channel; + } + + @Override + public void onPurchasesUpdated(int responseCode, @Nullable List purchases) { + final Map callbackArgs = new HashMap<>(); + callbackArgs.put("responseCode", responseCode); + callbackArgs.put("purchasesList", fromPurchasesList(purchases)); + channel.invokeMethod(InAppPurchasePlugin.MethodNames.ON_PURCHASES_UPDATED, callbackArgs); + } +} diff --git a/packages/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/InAppPurchasePluginTest.java b/packages/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/InAppPurchasePluginTest.java index 41a60788691f..31118be8226a 100644 --- a/packages/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/InAppPurchasePluginTest.java +++ b/packages/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/InAppPurchasePluginTest.java @@ -29,7 +29,6 @@ import static org.mockito.Mockito.when; import android.app.Activity; -import android.content.Context; import androidx.annotation.Nullable; import com.android.billingclient.api.BillingClient; import com.android.billingclient.api.BillingClient.BillingResponse; @@ -43,12 +42,10 @@ import com.android.billingclient.api.SkuDetails; import com.android.billingclient.api.SkuDetailsParams; import com.android.billingclient.api.SkuDetailsResponseListener; -import io.flutter.plugin.common.BinaryMessenger; import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel.Result; import io.flutter.plugin.common.PluginRegistry; -import io.flutter.plugins.inapppurchase.InAppPurchasePlugin.PluginPurchaseListener; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -60,20 +57,19 @@ import org.mockito.Spy; public class InAppPurchasePluginTest { - InAppPurchasePlugin plugin; + private InAppPurchasePlugin plugin; @Mock BillingClient mockBillingClient; @Mock MethodChannel mockMethodChannel; @Spy Result result; @Mock PluginRegistry.Registrar registrar; @Mock Activity activity; - @Mock BinaryMessenger messenger; - @Mock Context context; @Before public void setUp() { MockitoAnnotations.initMocks(this); - when(registrar.context()).thenReturn(context); - plugin = new InAppPurchasePlugin(registrar, mockBillingClient, mockMethodChannel); + + BillingClientFactory factory = (context, channel) -> mockBillingClient; + plugin = new InAppPurchasePlugin(factory, registrar, mockMethodChannel); } @Test @@ -85,6 +81,7 @@ public void invalidMethod() { @Test public void isReady_true() { + mockStartConnection(); MethodCall call = new MethodCall(IS_READY, null); when(mockBillingClient.isReady()).thenReturn(true); plugin.onMethodCall(call, result); @@ -93,6 +90,7 @@ public void isReady_true() { @Test public void isReady_false() { + mockStartConnection(); MethodCall call = new MethodCall(IS_READY, null); when(mockBillingClient.isReady()).thenReturn(false); plugin.onMethodCall(call, result); @@ -113,14 +111,7 @@ public void isReady_clientDisconnected() { @Test public void startConnection() { - Map arguments = new HashMap<>(); - arguments.put("handle", 1); - MethodCall call = new MethodCall(START_CONNECTION, arguments); - ArgumentCaptor captor = - ArgumentCaptor.forClass(BillingClientStateListener.class); - doNothing().when(mockBillingClient).startConnection(captor.capture()); - - plugin.onMethodCall(call, result); + ArgumentCaptor captor = mockStartConnection(); verify(result, never()).success(any()); captor.getValue().onBillingSetupFinished(100); @@ -452,6 +443,18 @@ public void consumeAsync() { verify(result, times(1)).success(responseCode); } + private ArgumentCaptor mockStartConnection() { + Map arguments = new HashMap<>(); + arguments.put("handle", 1); + MethodCall call = new MethodCall(START_CONNECTION, arguments); + ArgumentCaptor captor = + ArgumentCaptor.forClass(BillingClientStateListener.class); + doNothing().when(mockBillingClient).startConnection(captor.capture()); + + plugin.onMethodCall(call, result); + return captor; + } + private void establishConnectedBillingClient( @Nullable Map arguments, @Nullable Result result) { if (arguments == null) { diff --git a/packages/in_app_purchase/pubspec.yaml b/packages/in_app_purchase/pubspec.yaml index d3a8cf0fa230..e8e9ceea8fc9 100644 --- a/packages/in_app_purchase/pubspec.yaml +++ b/packages/in_app_purchase/pubspec.yaml @@ -2,7 +2,7 @@ name: in_app_purchase description: A Flutter plugin for in-app purchases. Exposes APIs for making in-app purchases through the App Store and Google Play. author: Flutter Team homepage: https://github.com/flutter/plugins/tree/master/packages/in_app_purchase -version: 0.2.1+2 +version: 0.2.1+3 dependencies: diff --git a/packages/instrumentation_adapter/CHANGELOG.md b/packages/instrumentation_adapter/CHANGELOG.md index 73557c5c704a..f4cd692a1916 100644 --- a/packages/instrumentation_adapter/CHANGELOG.md +++ b/packages/instrumentation_adapter/CHANGELOG.md @@ -1,3 +1,14 @@ +## 0.1.3 + +* Added example app. +* Added stub iOS implementation. +* Updated README. +* No longer throws errors when running tests on the host. + +## 0.1.2 + +* Added support for running tests using Flutter driver. + ## 0.1.1 * Updates about using *androidx* library. diff --git a/packages/instrumentation_adapter/README.md b/packages/instrumentation_adapter/README.md index 81f515569ac5..1063589c615b 100644 --- a/packages/instrumentation_adapter/README.md +++ b/packages/instrumentation_adapter/README.md @@ -12,11 +12,10 @@ Add a dependency on the `instrumentation_adapter` package in the pubspec.yaml of the example app. Invoke `InstrumentationAdapterFlutterBinding.ensureInitialized()` at the start -of a test file. +of a test file, e.g. ```dart import 'package:instrumentation_adapter/instrumentation_adapter.dart'; -import '../test/package_info.dart' as test; void main() { InstrumentationAdapterFlutterBinding.ensureInitialized(); @@ -90,3 +89,15 @@ gcloud firebase test android run --type instrumentation \ --results-bucket= \ --results-dir= ``` + +## Flutter driver support + +`InstrumentationAdapterFlutterBinding` also reports test results to `FlutterDriver` +when run on the command line via `flutter drive`. + +```dart + 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/instrumentation_adapter/example/.gitignore b/packages/instrumentation_adapter/example/.gitignore new file mode 100644 index 000000000000..2ddde2a5e36f --- /dev/null +++ b/packages/instrumentation_adapter/example/.gitignore @@ -0,0 +1,73 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +.dart_tool/ +.flutter-plugins +.packages +.pub-cache/ +.pub/ +/build/ + +# Android related +**/android/**/gradle-wrapper.jar +**/android/.gradle +**/android/captures/ +**/android/gradlew +**/android/gradlew.bat +**/android/local.properties +**/android/**/GeneratedPluginRegistrant.java + +# iOS/XCode related +**/ios/**/*.mode1v3 +**/ios/**/*.mode2v3 +**/ios/**/*.moved-aside +**/ios/**/*.pbxuser +**/ios/**/*.perspectivev3 +**/ios/**/*sync/ +**/ios/**/.sconsign.dblite +**/ios/**/.tags* +**/ios/**/.vagrant/ +**/ios/**/DerivedData/ +**/ios/**/Icon? +**/ios/**/Pods/ +**/ios/**/.symlinks/ +**/ios/**/profile +**/ios/**/xcuserdata +**/ios/.generated/ +**/ios/Flutter/App.framework +**/ios/Flutter/Flutter.framework +**/ios/Flutter/Generated.xcconfig +**/ios/Flutter/app.flx +**/ios/Flutter/app.zip +**/ios/Flutter/flutter_assets/ +**/ios/Flutter/flutter_export_environment.sh +**/ios/ServiceDefinitions.json +**/ios/Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!**/ios/**/default.mode1v3 +!**/ios/**/default.mode2v3 +!**/ios/**/default.pbxuser +!**/ios/**/default.perspectivev3 +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/examples/all_plugins/.metadata b/packages/instrumentation_adapter/example/.metadata similarity index 82% rename from examples/all_plugins/.metadata rename to packages/instrumentation_adapter/example/.metadata index c36997db797b..76f3d14cd0f9 100644 --- a/examples/all_plugins/.metadata +++ b/packages/instrumentation_adapter/example/.metadata @@ -4,7 +4,7 @@ # This file should be version controlled and should not be manually edited. version: - revision: 9114f4456cb8fd49e51bef9253e357225f209048 + revision: 4fc11db5cc50345b7d64cb4015eb9a92229f6384 channel: master project_type: app diff --git a/examples/all_plugins/README.md b/packages/instrumentation_adapter/example/README.md similarity index 84% rename from examples/all_plugins/README.md rename to packages/instrumentation_adapter/example/README.md index fbf90fd034b9..f6030a4080b2 100644 --- a/examples/all_plugins/README.md +++ b/packages/instrumentation_adapter/example/README.md @@ -1,6 +1,6 @@ -# all_plugins +# instrumentation_adapter_example -Flutter app containing all 1st party plugins. +Demonstrates how to use the instrumentation_adapter plugin. ## Getting Started diff --git a/examples/all_plugins/android/app/build.gradle b/packages/instrumentation_adapter/example/android/app/build.gradle similarity index 82% rename from examples/all_plugins/android/app/build.gradle rename to packages/instrumentation_adapter/example/android/app/build.gradle index 9fbd496f70df..500e9ea951c6 100644 --- a/examples/all_plugins/android/app/build.gradle +++ b/packages/instrumentation_adapter/example/android/app/build.gradle @@ -1,5 +1,3 @@ -gradle.startParameter.showStacktrace = org.gradle.api.logging.configuration.ShowStacktrace.ALWAYS - def localProperties = new Properties() def localPropertiesFile = rootProject.file('local.properties') if (localPropertiesFile.exists()) { @@ -35,9 +33,8 @@ android { defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "io.plugins.all_plugins" + applicationId "com.example.instrumentation_adapter_example" minSdkVersion 16 - multiDexEnabled true targetSdkVersion 28 versionCode flutterVersionCode.toInteger() versionName flutterVersionName @@ -59,8 +56,6 @@ flutter { dependencies { testImplementation 'junit:junit:4.12' - implementation 'com.google.guava:guava:27.0.1-android' - androidTestImplementation 'androidx.test:runner:1.1.0' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0' - api 'androidx.exifinterface:exifinterface:1.0.0' + androidTestImplementation 'androidx.test:runner:1.2.0' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' } diff --git a/packages/instrumentation_adapter/example/android/app/src/androidTest/java/com/example/instrumentation_adapter_example/MainActivityTest.java b/packages/instrumentation_adapter/example/android/app/src/androidTest/java/com/example/instrumentation_adapter_example/MainActivityTest.java new file mode 100644 index 000000000000..bb489bf57942 --- /dev/null +++ b/packages/instrumentation_adapter/example/android/app/src/androidTest/java/com/example/instrumentation_adapter_example/MainActivityTest.java @@ -0,0 +1,11 @@ +package com.example.instrumentation_adapter_example; + +import androidx.test.rule.ActivityTestRule; +import dev.flutter.plugins.instrumentationadapter.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/examples/all_plugins/android/app/src/debug/AndroidManifest.xml b/packages/instrumentation_adapter/example/android/app/src/debug/AndroidManifest.xml similarity index 83% rename from examples/all_plugins/android/app/src/debug/AndroidManifest.xml rename to packages/instrumentation_adapter/example/android/app/src/debug/AndroidManifest.xml index 278e553fdf19..87cc33d27c03 100644 --- a/examples/all_plugins/android/app/src/debug/AndroidManifest.xml +++ b/packages/instrumentation_adapter/example/android/app/src/debug/AndroidManifest.xml @@ -1,5 +1,5 @@ + package="com.example.instrumentation_adapter_example"> diff --git a/examples/all_plugins/android/app/src/main/AndroidManifest.xml b/packages/instrumentation_adapter/example/android/app/src/main/AndroidManifest.xml similarity index 89% rename from examples/all_plugins/android/app/src/main/AndroidManifest.xml rename to packages/instrumentation_adapter/example/android/app/src/main/AndroidManifest.xml index fc8cb90afaa3..653fa39a669d 100644 --- a/examples/all_plugins/android/app/src/main/AndroidManifest.xml +++ b/packages/instrumentation_adapter/example/android/app/src/main/AndroidManifest.xml @@ -1,8 +1,5 @@ - - + package="com.example.instrumentation_adapter_example"> + package="com.example.instrumentation_adapter_example"> diff --git a/examples/all_plugins/android/build.gradle b/packages/instrumentation_adapter/example/android/build.gradle similarity index 72% rename from examples/all_plugins/android/build.gradle rename to packages/instrumentation_adapter/example/android/build.gradle index ad6301ce2ad9..bb8a303898ca 100644 --- a/examples/all_plugins/android/build.gradle +++ b/packages/instrumentation_adapter/example/android/build.gradle @@ -1,5 +1,3 @@ -gradle.startParameter.showStacktrace = org.gradle.api.logging.configuration.ShowStacktrace.ALWAYS - buildscript { repositories { google() @@ -7,7 +5,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:3.3.1' + classpath 'com.android.tools.build:gradle:3.2.1' } } diff --git a/packages/instrumentation_adapter/example/android/gradle.properties b/packages/instrumentation_adapter/example/android/gradle.properties new file mode 100644 index 000000000000..2bd6f4fda009 --- /dev/null +++ b/packages/instrumentation_adapter/example/android/gradle.properties @@ -0,0 +1,2 @@ +org.gradle.jvmargs=-Xmx1536M + diff --git a/examples/all_plugins/android/gradle/wrapper/gradle-wrapper.properties b/packages/instrumentation_adapter/example/android/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from examples/all_plugins/android/gradle/wrapper/gradle-wrapper.properties rename to packages/instrumentation_adapter/example/android/gradle/wrapper/gradle-wrapper.properties diff --git a/examples/all_plugins/android/settings.gradle b/packages/instrumentation_adapter/example/android/settings.gradle similarity index 100% rename from examples/all_plugins/android/settings.gradle rename to packages/instrumentation_adapter/example/android/settings.gradle diff --git a/packages/instrumentation_adapter/example/instrumentation_adapter/widget_test.dart b/packages/instrumentation_adapter/example/instrumentation_adapter/widget_test.dart new file mode 100644 index 000000000000..9829553c6522 --- /dev/null +++ b/packages/instrumentation_adapter/example/instrumentation_adapter/widget_test.dart @@ -0,0 +1,5 @@ +import '../test_driver/widget.dart' as test; + +void main() { + test.main(); +} diff --git a/examples/all_plugins/ios/Flutter/AppFrameworkInfo.plist b/packages/instrumentation_adapter/example/ios/Flutter/AppFrameworkInfo.plist similarity index 94% rename from examples/all_plugins/ios/Flutter/AppFrameworkInfo.plist rename to packages/instrumentation_adapter/example/ios/Flutter/AppFrameworkInfo.plist index 9367d483e44e..6b4c0f78a785 100644 --- a/examples/all_plugins/ios/Flutter/AppFrameworkInfo.plist +++ b/packages/instrumentation_adapter/example/ios/Flutter/AppFrameworkInfo.plist @@ -3,7 +3,7 @@ CFBundleDevelopmentRegion - en + $(DEVELOPMENT_LANGUAGE) CFBundleExecutable App CFBundleIdentifier diff --git a/packages/instrumentation_adapter/example/ios/Flutter/Debug.xcconfig b/packages/instrumentation_adapter/example/ios/Flutter/Debug.xcconfig new file mode 100644 index 000000000000..e8efba114687 --- /dev/null +++ b/packages/instrumentation_adapter/example/ios/Flutter/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "Generated.xcconfig" diff --git a/packages/instrumentation_adapter/example/ios/Flutter/Release.xcconfig b/packages/instrumentation_adapter/example/ios/Flutter/Release.xcconfig new file mode 100644 index 000000000000..399e9340e6f6 --- /dev/null +++ b/packages/instrumentation_adapter/example/ios/Flutter/Release.xcconfig @@ -0,0 +1,2 @@ +#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "Generated.xcconfig" diff --git a/examples/all_plugins/ios/Runner.xcodeproj/project.pbxproj b/packages/instrumentation_adapter/example/ios/Runner.xcodeproj/project.pbxproj similarity index 83% rename from examples/all_plugins/ios/Runner.xcodeproj/project.pbxproj rename to packages/instrumentation_adapter/example/ios/Runner.xcodeproj/project.pbxproj index df9cc66441db..88aca9f4d27e 100644 --- a/examples/all_plugins/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/instrumentation_adapter/example/ios/Runner.xcodeproj/project.pbxproj @@ -13,12 +13,12 @@ 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; }; 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; + F81AEF02CE63DA0020B29F57 /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 241E53603CE376E3BCB194D3 /* libPods-Runner.a */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -37,8 +37,10 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 0D6F1CB5DBBEBCC75AFAD041 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 241E53603CE376E3BCB194D3 /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; @@ -53,6 +55,8 @@ 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + D69CCAD5F82E76E2E22BFA96 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + E23EF4D45DAE46B9DDB9B445 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -62,12 +66,21 @@ files = ( 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, + F81AEF02CE63DA0020B29F57 /* libPods-Runner.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 42D734D13B733A64B01A24A9 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 241E53603CE376E3BCB194D3 /* libPods-Runner.a */, + ); + name = Frameworks; + sourceTree = ""; + }; 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( @@ -87,7 +100,8 @@ 9740EEB11CF90186004384FC /* Flutter */, 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, - CF3B75C9A7D2FA2A4C99F110 /* Frameworks */, + BAB55133DD7BD81A2557E916 /* Pods */, + 42D734D13B733A64B01A24A9 /* Frameworks */, ); sourceTree = ""; }; @@ -123,6 +137,17 @@ name = "Supporting Files"; sourceTree = ""; }; + BAB55133DD7BD81A2557E916 /* Pods */ = { + isa = PBXGroup; + children = ( + D69CCAD5F82E76E2E22BFA96 /* Pods-Runner.debug.xcconfig */, + 0D6F1CB5DBBEBCC75AFAD041 /* Pods-Runner.release.xcconfig */, + E23EF4D45DAE46B9DDB9B445 /* Pods-Runner.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -130,12 +155,14 @@ isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( + 2882CCC16181B61F1ABC876C /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + 0D321280D358770769172C49 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -152,7 +179,7 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0910; + LastUpgradeCheck = 1020; ORGANIZATIONNAME = "The Chromium Authors"; TargetAttributes = { 97C146ED1CF9000F007C117D = { @@ -162,7 +189,7 @@ }; buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; + developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, @@ -185,7 +212,6 @@ files = ( 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, - 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */, 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, ); @@ -194,6 +220,43 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + 0D321280D358770769172C49 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Embed Pods Frameworks"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 2882CCC16181B61F1ABC876C /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -271,12 +334,14 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; @@ -300,6 +365,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; @@ -311,7 +377,6 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = S8QB4VV633; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -323,7 +388,7 @@ "$(inherited)", "$(PROJECT_DIR)/Flutter", ); - PRODUCT_BUNDLE_IDENTIFIER = io.plugins.allPlugins; + PRODUCT_BUNDLE_IDENTIFIER = com.example.instrumentationAdapterExample; PRODUCT_NAME = "$(TARGET_NAME)"; VERSIONING_SYSTEM = "apple-generic"; }; @@ -343,12 +408,14 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; @@ -397,12 +464,14 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; @@ -426,6 +495,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; @@ -448,7 +518,7 @@ "$(inherited)", "$(PROJECT_DIR)/Flutter", ); - PRODUCT_BUNDLE_IDENTIFIER = io.plugins.allPlugins; + PRODUCT_BUNDLE_IDENTIFIER = com.example.instrumentationAdapterExample; PRODUCT_NAME = "$(TARGET_NAME)"; VERSIONING_SYSTEM = "apple-generic"; }; @@ -471,7 +541,7 @@ "$(inherited)", "$(PROJECT_DIR)/Flutter", ); - PRODUCT_BUNDLE_IDENTIFIER = io.plugins.allPlugins; + PRODUCT_BUNDLE_IDENTIFIER = com.example.instrumentationAdapterExample; PRODUCT_NAME = "$(TARGET_NAME)"; VERSIONING_SYSTEM = "apple-generic"; }; diff --git a/examples/all_plugins/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/instrumentation_adapter/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme similarity index 97% rename from examples/all_plugins/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme rename to packages/instrumentation_adapter/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 786d6aad5457..a28140cfdb3f 100644 --- a/examples/all_plugins/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/packages/instrumentation_adapter/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ @@ -46,7 +45,6 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - language = "" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" diff --git a/examples/all_plugins/ios/Runner/AppDelegate.h b/packages/instrumentation_adapter/example/ios/Runner/AppDelegate.h similarity index 100% rename from examples/all_plugins/ios/Runner/AppDelegate.h rename to packages/instrumentation_adapter/example/ios/Runner/AppDelegate.h diff --git a/examples/all_plugins/ios/Runner/AppDelegate.m b/packages/instrumentation_adapter/example/ios/Runner/AppDelegate.m similarity index 100% rename from examples/all_plugins/ios/Runner/AppDelegate.m rename to packages/instrumentation_adapter/example/ios/Runner/AppDelegate.m diff --git a/examples/all_plugins/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/packages/instrumentation_adapter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from examples/all_plugins/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json rename to packages/instrumentation_adapter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/packages/instrumentation_adapter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/packages/instrumentation_adapter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 000000000000..dc9ada4725e9 Binary files /dev/null and b/packages/instrumentation_adapter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/examples/all_plugins/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/packages/instrumentation_adapter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png similarity index 100% rename from examples/all_plugins/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png rename to packages/instrumentation_adapter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png diff --git a/examples/all_plugins/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/packages/instrumentation_adapter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png similarity index 100% rename from examples/all_plugins/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png rename to packages/instrumentation_adapter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png diff --git a/examples/all_plugins/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/packages/instrumentation_adapter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png similarity index 100% rename from examples/all_plugins/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png rename to packages/instrumentation_adapter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png diff --git a/examples/all_plugins/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/packages/instrumentation_adapter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png similarity index 100% rename from examples/all_plugins/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png rename to packages/instrumentation_adapter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png diff --git a/examples/all_plugins/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/packages/instrumentation_adapter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png similarity index 100% rename from examples/all_plugins/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png rename to packages/instrumentation_adapter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png diff --git a/examples/all_plugins/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/packages/instrumentation_adapter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png similarity index 100% rename from examples/all_plugins/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png rename to packages/instrumentation_adapter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png diff --git a/examples/all_plugins/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/packages/instrumentation_adapter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png similarity index 100% rename from examples/all_plugins/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png rename to packages/instrumentation_adapter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png diff --git a/examples/all_plugins/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/packages/instrumentation_adapter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png similarity index 100% rename from examples/all_plugins/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png rename to packages/instrumentation_adapter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png diff --git a/examples/all_plugins/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/packages/instrumentation_adapter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png similarity index 100% rename from examples/all_plugins/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png rename to packages/instrumentation_adapter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png diff --git a/examples/all_plugins/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/packages/instrumentation_adapter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png similarity index 100% rename from examples/all_plugins/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png rename to packages/instrumentation_adapter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png diff --git a/examples/all_plugins/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/packages/instrumentation_adapter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png similarity index 100% rename from examples/all_plugins/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png rename to packages/instrumentation_adapter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png diff --git a/examples/all_plugins/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/packages/instrumentation_adapter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png similarity index 100% rename from examples/all_plugins/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png rename to packages/instrumentation_adapter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png diff --git a/examples/all_plugins/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/packages/instrumentation_adapter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png similarity index 100% rename from examples/all_plugins/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png rename to packages/instrumentation_adapter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png diff --git a/examples/all_plugins/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/packages/instrumentation_adapter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png similarity index 100% rename from examples/all_plugins/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png rename to packages/instrumentation_adapter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png diff --git a/examples/all_plugins/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/packages/instrumentation_adapter/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json similarity index 100% rename from examples/all_plugins/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json rename to packages/instrumentation_adapter/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json diff --git a/examples/all_plugins/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/packages/instrumentation_adapter/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png similarity index 100% rename from examples/all_plugins/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png rename to packages/instrumentation_adapter/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png diff --git a/examples/all_plugins/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/packages/instrumentation_adapter/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png similarity index 100% rename from examples/all_plugins/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png rename to packages/instrumentation_adapter/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png diff --git a/examples/all_plugins/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/packages/instrumentation_adapter/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png similarity index 100% rename from examples/all_plugins/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png rename to packages/instrumentation_adapter/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png diff --git a/examples/all_plugins/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/packages/instrumentation_adapter/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md similarity index 100% rename from examples/all_plugins/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md rename to packages/instrumentation_adapter/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md diff --git a/examples/all_plugins/ios/Runner/Base.lproj/LaunchScreen.storyboard b/packages/instrumentation_adapter/example/ios/Runner/Base.lproj/LaunchScreen.storyboard similarity index 100% rename from examples/all_plugins/ios/Runner/Base.lproj/LaunchScreen.storyboard rename to packages/instrumentation_adapter/example/ios/Runner/Base.lproj/LaunchScreen.storyboard diff --git a/examples/all_plugins/ios/Runner/Base.lproj/Main.storyboard b/packages/instrumentation_adapter/example/ios/Runner/Base.lproj/Main.storyboard similarity index 100% rename from examples/all_plugins/ios/Runner/Base.lproj/Main.storyboard rename to packages/instrumentation_adapter/example/ios/Runner/Base.lproj/Main.storyboard diff --git a/examples/all_plugins/ios/Runner/Info.plist b/packages/instrumentation_adapter/example/ios/Runner/Info.plist similarity index 93% rename from examples/all_plugins/ios/Runner/Info.plist rename to packages/instrumentation_adapter/example/ios/Runner/Info.plist index 127a08b03f39..613203aaeb06 100644 --- a/examples/all_plugins/ios/Runner/Info.plist +++ b/packages/instrumentation_adapter/example/ios/Runner/Info.plist @@ -3,7 +3,7 @@ CFBundleDevelopmentRegion - en + $(DEVELOPMENT_LANGUAGE) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier @@ -11,7 +11,7 @@ CFBundleInfoDictionaryVersion 6.0 CFBundleName - all_plugins + instrumentation_adapter_example CFBundlePackageType APPL CFBundleShortVersionString @@ -41,7 +41,5 @@ UIViewControllerBasedStatusBarAppearance - io.flutter.embedded_views_preview - diff --git a/examples/all_plugins/ios/Runner/main.m b/packages/instrumentation_adapter/example/ios/Runner/main.m similarity index 100% rename from examples/all_plugins/ios/Runner/main.m rename to packages/instrumentation_adapter/example/ios/Runner/main.m diff --git a/packages/instrumentation_adapter/example/lib/main.dart b/packages/instrumentation_adapter/example/lib/main.dart new file mode 100644 index 000000000000..c1206d562f88 --- /dev/null +++ b/packages/instrumentation_adapter/example/lib/main.dart @@ -0,0 +1,25 @@ +import 'dart:io' show Platform; +import 'package:flutter/material.dart'; + +void main() => runApp(MyApp()); + +class MyApp extends StatefulWidget { + @override + _MyAppState createState() => _MyAppState(); +} + +class _MyAppState extends State { + @override + Widget build(BuildContext context) { + return MaterialApp( + home: Scaffold( + appBar: AppBar( + title: const Text('Plugin example app'), + ), + body: Center( + child: Text('Platform: ${Platform.operatingSystem}\n'), + ), + ), + ); + } +} diff --git a/packages/instrumentation_adapter/example/pubspec.yaml b/packages/instrumentation_adapter/example/pubspec.yaml new file mode 100644 index 000000000000..55d547736b24 --- /dev/null +++ b/packages/instrumentation_adapter/example/pubspec.yaml @@ -0,0 +1,26 @@ +name: instrumentation_adapter_example +description: Demonstrates how to use the instrumentation_adapter plugin. +publish_to: 'none' + +environment: + sdk: ">=2.1.0 <3.0.0" + +dependencies: + flutter: + sdk: flutter + + cupertino_icons: ^0.1.2 + +dev_dependencies: + flutter_test: + sdk: flutter + flutter_driver: + sdk: flutter + instrumentation_adapter: + path: ../ + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +flutter: + uses-material-design: true diff --git a/examples/all_plugins/test/widget_test.dart b/packages/instrumentation_adapter/example/test_driver/widget.dart similarity index 50% rename from examples/all_plugins/test/widget_test.dart rename to packages/instrumentation_adapter/example/test_driver/widget.dart index 809cad928ec8..109002c86790 100644 --- a/examples/all_plugins/test/widget_test.dart +++ b/packages/instrumentation_adapter/example/test_driver/widget.dart @@ -5,26 +5,27 @@ // gestures. You can also use WidgetTester to find child widgets in the widget // tree, read text, and verify that the values of widget properties are correct. +import 'dart:io' show Platform; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:instrumentation_adapter/instrumentation_adapter.dart'; -import 'package:all_plugins/main.dart'; +import 'package:instrumentation_adapter_example/main.dart'; void main() { - testWidgets('Counter increments smoke test', (WidgetTester tester) async { + InstrumentationAdapterFlutterBinding.ensureInitialized(); + testWidgets('verify text', (WidgetTester tester) async { // Build our app and trigger a frame. await tester.pumpWidget(MyApp()); - // Verify that our counter starts at 0. - expect(find.text('0'), findsOneWidget); - expect(find.text('1'), findsNothing); - - // Tap the '+' icon and trigger a frame. - await tester.tap(find.byIcon(Icons.add)); - await tester.pump(); - - // Verify that our counter has incremented. - expect(find.text('0'), findsNothing); - expect(find.text('1'), findsOneWidget); + // Verify that platform version is retrieved. + expect( + find.byWidgetPredicate( + (Widget widget) => + widget is Text && + widget.data.startsWith('Platform: ${Platform.operatingSystem}'), + ), + findsOneWidget, + ); }); } diff --git a/packages/instrumentation_adapter/example/test_driver/widget_test.dart b/packages/instrumentation_adapter/example/test_driver/widget_test.dart new file mode 100644 index 000000000000..88e53d1c1f05 --- /dev/null +++ b/packages/instrumentation_adapter/example/test_driver/widget_test.dart @@ -0,0 +1,9 @@ +import 'dart:async'; + +import 'package:flutter_driver/flutter_driver.dart'; + +Future main() async { + final FlutterDriver driver = await FlutterDriver.connect(); + await driver.requestData(null, timeout: const Duration(minutes: 1)); + driver.close(); +} diff --git a/packages/instrumentation_adapter/ios/.gitignore b/packages/instrumentation_adapter/ios/.gitignore new file mode 100644 index 000000000000..aa479fd3ce8a --- /dev/null +++ b/packages/instrumentation_adapter/ios/.gitignore @@ -0,0 +1,37 @@ +.idea/ +.vagrant/ +.sconsign.dblite +.svn/ + +.DS_Store +*.swp +profile + +DerivedData/ +build/ +GeneratedPluginRegistrant.h +GeneratedPluginRegistrant.m + +.generated/ + +*.pbxuser +*.mode1v3 +*.mode2v3 +*.perspectivev3 + +!default.pbxuser +!default.mode1v3 +!default.mode2v3 +!default.perspectivev3 + +xcuserdata + +*.moved-aside + +*.pyc +*sync/ +Icon? +.tags* + +/Flutter/Generated.xcconfig +/Flutter/flutter_export_environment.sh \ No newline at end of file diff --git a/packages/instrumentation_adapter/ios/Assets/.gitkeep b/packages/instrumentation_adapter/ios/Assets/.gitkeep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/packages/instrumentation_adapter/ios/Classes/InstrumentationAdapterPlugin.h b/packages/instrumentation_adapter/ios/Classes/InstrumentationAdapterPlugin.h new file mode 100644 index 000000000000..3d92ba91bf34 --- /dev/null +++ b/packages/instrumentation_adapter/ios/Classes/InstrumentationAdapterPlugin.h @@ -0,0 +1,4 @@ +#import + +@interface InstrumentationAdapterPlugin : NSObject +@end diff --git a/packages/instrumentation_adapter/ios/Classes/InstrumentationAdapterPlugin.m b/packages/instrumentation_adapter/ios/Classes/InstrumentationAdapterPlugin.m new file mode 100644 index 000000000000..704a5b05e031 --- /dev/null +++ b/packages/instrumentation_adapter/ios/Classes/InstrumentationAdapterPlugin.m @@ -0,0 +1,20 @@ +#import "InstrumentationAdapterPlugin.h" + +@implementation InstrumentationAdapterPlugin ++ (void)registerWithRegistrar:(NSObject*)registrar { + FlutterMethodChannel* channel = [FlutterMethodChannel + methodChannelWithName:@"dev.flutter/InstrumentationAdapterFlutterBinding" + binaryMessenger:[registrar messenger]]; + InstrumentationAdapterPlugin* instance = [[InstrumentationAdapterPlugin alloc] init]; + [registrar addMethodCallDelegate:instance channel:channel]; +} + +- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { + if ([@"allTestsFinished" isEqualToString:call.method]) { + result(nil); + } else { + result(FlutterMethodNotImplemented); + } +} + +@end diff --git a/packages/instrumentation_adapter/ios/instrumentation_adapter.podspec b/packages/instrumentation_adapter/ios/instrumentation_adapter.podspec new file mode 100644 index 000000000000..c18e58535998 --- /dev/null +++ b/packages/instrumentation_adapter/ios/instrumentation_adapter.podspec @@ -0,0 +1,21 @@ +# +# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html +# +Pod::Spec.new do |s| + s.name = 'instrumentation_adapter' + s.version = '0.0.1' + s.summary = 'Instrumentation adapter.' + s.description = <<-DESC +Runs tests that use the flutter_test API as integration tests. + DESC + s.homepage = 'https://github.com/flutter/plugins/tree/master/packages/instrumentation_adapter' + s.license = { :file => '../LICENSE' } + s.author = { 'Flutter Team' => 'flutter-dev@googlegroups.com' } + s.source = { :path => '.' } + s.source_files = 'Classes/**/*' + s.public_header_files = 'Classes/**/*.h' + s.dependency 'Flutter' + + s.ios.deployment_target = '8.0' +end + diff --git a/packages/instrumentation_adapter/lib/instrumentation_adapter.dart b/packages/instrumentation_adapter/lib/instrumentation_adapter.dart index 81f81872d950..9999452234cd 100644 --- a/packages/instrumentation_adapter/lib/instrumentation_adapter.dart +++ b/packages/instrumentation_adapter/lib/instrumentation_adapter.dart @@ -2,6 +2,7 @@ // 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_test/flutter_test.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; @@ -14,11 +15,18 @@ class InstrumentationAdapterFlutterBinding InstrumentationAdapterFlutterBinding() { // TODO(jackson): Report test results as they arrive tearDownAll(() async { - await _channel.invokeMethod( - 'allTestsFinished', {'results': _results}); + try { + await _channel.invokeMethod( + 'allTestsFinished', {'results': _results}); + } on MissingPluginException { + // Tests were run on the host rather than a device. + } + if (!_allTestsPassed.isCompleted) _allTestsPassed.complete(true); }); } + final Completer _allTestsPassed = Completer(); + static WidgetsBinding ensureInitialized() { if (WidgetsBinding.instance == null) { InstrumentationAdapterFlutterBinding(); @@ -32,14 +40,46 @@ class InstrumentationAdapterFlutterBinding static Map _results = {}; + // Emulates the Flutter driver extension, returning 'pass' or 'fail'. + @override + void initServiceExtensions() { + super.initServiceExtensions(); + Future> callback(Map params) async { + final String command = params['command']; + Map response; + switch (command) { + case 'request_data': + final bool allTestsPassed = await _allTestsPassed.future; + response = { + 'message': allTestsPassed ? 'pass' : 'fail', + }; + break; + case 'get_health': + response = {'status': 'ok'}; + break; + default: + throw UnimplementedError('$command is not implemented'); + } + return { + 'isError': false, + 'response': response, + }; + } + + registerServiceExtension(name: 'driver', callback: callback); + } + @override Future runTest(Future testBody(), VoidCallback invariantTester, {String description = '', Duration timeout}) async { // TODO(jackson): Report the results individually instead of all at once // See https://github.com/flutter/flutter/issues/38985 + final TestExceptionReporter valueBeforeTest = reportTestException; reportTestException = (FlutterErrorDetails details, String testDescription) { _results[description] = 'failed'; + _allTestsPassed.complete(false); + valueBeforeTest(details, testDescription); }; await super.runTest(testBody, invariantTester, description: description, timeout: timeout); diff --git a/packages/instrumentation_adapter/pubspec.yaml b/packages/instrumentation_adapter/pubspec.yaml index b73c7499aa81..1ac0aed7b05e 100644 --- a/packages/instrumentation_adapter/pubspec.yaml +++ b/packages/instrumentation_adapter/pubspec.yaml @@ -1,6 +1,6 @@ name: instrumentation_adapter -description: Runs tests that use the flutter_test API as platform native instrumentation tests. -version: 0.1.1 +description: Runs tests that use the flutter_test API as integration tests. +version: 0.1.3 author: Flutter Team homepage: https://github.com/flutter/plugins/tree/master/packages/instrumentation_adapter diff --git a/packages/local_auth/CHANGELOG.md b/packages/local_auth/CHANGELOG.md index 1988028a1f9d..832efc795a95 100644 --- a/packages/local_auth/CHANGELOG.md +++ b/packages/local_auth/CHANGELOG.md @@ -1,3 +1,9 @@ +## 0.6.0 + +* Define a new parameter for signaling that the transaction is sensitive. +* Up the biometric version to beta01. +* Handle no device credential error. + ## 0.5.3 * Add face id detection as well by not relying on FingerprintCompat. diff --git a/packages/local_auth/android/build.gradle b/packages/local_auth/android/build.gradle index 142b606405c4..74fe6c550517 100644 --- a/packages/local_auth/android/build.gradle +++ b/packages/local_auth/android/build.gradle @@ -48,6 +48,6 @@ android { dependencies { api "androidx.core:core:1.1.0-beta01" - api "androidx.biometric:biometric:1.0.0-alpha04" + api "androidx.biometric:biometric:1.0.0-beta01" api "androidx.fragment:fragment:1.1.0-alpha06" } diff --git a/packages/local_auth/android/src/main/java/io/flutter/plugins/localauth/AuthenticationHelper.java b/packages/local_auth/android/src/main/java/io/flutter/plugins/localauth/AuthenticationHelper.java index 46d7bf3dec9a..a4ef01bfa504 100644 --- a/packages/local_auth/android/src/main/java/io/flutter/plugins/localauth/AuthenticationHelper.java +++ b/packages/local_auth/android/src/main/java/io/flutter/plugins/localauth/AuthenticationHelper.java @@ -77,6 +77,7 @@ public AuthenticationHelper( .setTitle((String) call.argument("signInTitle")) .setSubtitle((String) call.argument("fingerprintHint")) .setNegativeButtonText((String) call.argument("cancelButton")) + .setConfirmationRequired((Boolean) call.argument("sensitiveTransaction")) .build(); } @@ -95,13 +96,11 @@ private void stop() { @Override public void onAuthenticationError(int errorCode, CharSequence errString) { switch (errorCode) { - // TODO(mehmetf): Re-enable when biometric alpha05 is released. - // https://developer.android.com/jetpack/androidx/releases/biometric - // case BiometricPrompt.ERROR_NO_DEVICE_CREDENTIAL: - // completionHandler.onError( - // "PasscodeNotSet", - // "Phone not secured by PIN, pattern or password, or SIM is currently locked."); - // break; + case BiometricPrompt.ERROR_NO_DEVICE_CREDENTIAL: + completionHandler.onError( + "PasscodeNotSet", + "Phone not secured by PIN, pattern or password, or SIM is currently locked."); + break; case BiometricPrompt.ERROR_NO_SPACE: case BiometricPrompt.ERROR_NO_BIOMETRICS: if (call.argument("useErrorDialogs")) { diff --git a/packages/local_auth/lib/local_auth.dart b/packages/local_auth/lib/local_auth.dart index d5f2ac7c4bae..df69a120aa39 100644 --- a/packages/local_auth/lib/local_auth.dart +++ b/packages/local_auth/lib/local_auth.dart @@ -3,10 +3,10 @@ // found in the LICENSE file. import 'dart:async'; -import 'dart:io'; import 'package:flutter/services.dart'; import 'package:meta/meta.dart'; +import 'package:platform/platform.dart'; import 'auth_strings.dart'; import 'error_codes.dart'; @@ -15,6 +15,13 @@ enum BiometricType { face, fingerprint, iris } const MethodChannel _channel = MethodChannel('plugins.flutter.io/local_auth'); +Platform _platform = const LocalPlatform(); + +@visibleForTesting +void setMockPathProviderPlatform(Platform platform) { + _platform = platform; +} + /// A Flutter plugin for authenticating the user identity locally. class LocalAuthentication { /// Authenticates the user with biometrics available on the device. @@ -44,6 +51,11 @@ class LocalAuthentication { /// Construct [AndroidAuthStrings] and [IOSAuthStrings] if you want to /// customize messages in the dialogs. /// + /// Setting [sensitiveTransaction] to true enables platform specific + /// precautions. For instance, on face unlock, Android opens a confirmation + /// dialog after the face is recognized to make sure the user meant to unlock + /// their phone. + /// /// Throws an [PlatformException] if there were technical problems with local /// authentication (e.g. lack of relevant hardware). This might throw /// [PlatformException] with error code [otherOperatingSystem] on the iOS @@ -54,23 +66,25 @@ class LocalAuthentication { bool stickyAuth = false, AndroidAuthMessages androidAuthStrings = const AndroidAuthMessages(), IOSAuthMessages iOSAuthStrings = const IOSAuthMessages(), + bool sensitiveTransaction = true, }) async { assert(localizedReason != null); final Map args = { 'localizedReason': localizedReason, 'useErrorDialogs': useErrorDialogs, 'stickyAuth': stickyAuth, + 'sensitiveTransaction': sensitiveTransaction, }; - if (Platform.isIOS) { + if (_platform.isIOS) { args.addAll(iOSAuthStrings.args); - } else if (Platform.isAndroid) { + } else if (_platform.isAndroid) { args.addAll(androidAuthStrings.args); } else { throw PlatformException( code: otherOperatingSystem, message: 'Local authentication does not support non-Android/iOS ' 'operating systems.', - details: 'Your operating system is ${Platform.operatingSystem}'); + details: 'Your operating system is ${_platform.operatingSystem}'); } return await _channel.invokeMethod( 'authenticateWithBiometrics', args); diff --git a/packages/local_auth/pubspec.yaml b/packages/local_auth/pubspec.yaml index 286d7aa73871..a78f6287128e 100644 --- a/packages/local_auth/pubspec.yaml +++ b/packages/local_auth/pubspec.yaml @@ -3,7 +3,7 @@ description: Flutter plugin for Android and iOS device authentication sensors such as Fingerprint Reader and Touch ID. author: Flutter Team homepage: https://github.com/flutter/plugins/tree/master/packages/local_auth -version: 0.5.3 +version: 0.6.0 flutter: plugin: @@ -16,6 +16,11 @@ dependencies: sdk: flutter meta: ^1.0.5 intl: ^0.15.1 + platform: ^2.0.0 + +dev_dependencies: + flutter_test: + sdk: flutter environment: sdk: ">=2.0.0-dev.28.0 <3.0.0" diff --git a/packages/local_auth/test/local_auth_test.dart b/packages/local_auth/test/local_auth_test.dart new file mode 100644 index 000000000000..205c5f785708 --- /dev/null +++ b/packages/local_auth/test/local_auth_test.dart @@ -0,0 +1,90 @@ +// 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 'dart:async'; + +import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:local_auth/auth_strings.dart'; +import 'package:local_auth/local_auth.dart'; +import 'package:platform/platform.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + group('LocalAuth', () { + const MethodChannel channel = MethodChannel( + 'plugins.flutter.io/local_auth', + ); + + final List log = []; + LocalAuthentication localAuthentication; + + setUp(() { + channel.setMockMethodCallHandler((MethodCall methodCall) { + log.add(methodCall); + return Future.value(true); + }); + localAuthentication = LocalAuthentication(); + log.clear(); + }); + + test('authenticate with no args on Android.', () async { + setMockPathProviderPlatform(FakePlatform(operatingSystem: 'android')); + await localAuthentication.authenticateWithBiometrics( + localizedReason: 'Needs secure'); + expect( + log, + [ + isMethodCall('authenticateWithBiometrics', + arguments: { + 'localizedReason': 'Needs secure', + 'useErrorDialogs': true, + 'stickyAuth': false, + 'sensitiveTransaction': true, + }..addAll(const AndroidAuthMessages().args)), + ], + ); + }); + + test('authenticate with no args on iOS.', () async { + setMockPathProviderPlatform(FakePlatform(operatingSystem: 'ios')); + await localAuthentication.authenticateWithBiometrics( + localizedReason: 'Needs secure'); + expect( + log, + [ + isMethodCall('authenticateWithBiometrics', + arguments: { + 'localizedReason': 'Needs secure', + 'useErrorDialogs': true, + 'stickyAuth': false, + 'sensitiveTransaction': true, + }..addAll(const IOSAuthMessages().args)), + ], + ); + }); + + test('authenticate with no sensitive transaction.', () async { + setMockPathProviderPlatform(FakePlatform(operatingSystem: 'android')); + await localAuthentication.authenticateWithBiometrics( + localizedReason: 'Insecure', + sensitiveTransaction: false, + useErrorDialogs: false, + ); + expect( + log, + [ + isMethodCall('authenticateWithBiometrics', + arguments: { + 'localizedReason': 'Insecure', + 'useErrorDialogs': false, + 'stickyAuth': false, + 'sensitiveTransaction': false, + }..addAll(const AndroidAuthMessages().args)), + ], + ); + }); + }); +} diff --git a/packages/path_provider/CHANGELOG.md b/packages/path_provider/CHANGELOG.md index 7546844b3549..6ded47745ddc 100644 --- a/packages/path_provider/CHANGELOG.md +++ b/packages/path_provider/CHANGELOG.md @@ -1,3 +1,16 @@ +## 1.3.0 + +* Added iOS-only support for `getLibraryDirectory`. +* Update integration tests and example test. +* Update example app UI to use a `ListView` show the list of content. +* Update .gitignore to include Xcode build output folder `**/DerivedData/` + +## 1.2.2 + +* Correct the integration test for Android's `getApplicationSupportDirectory` call. +* Introduce `setMockPathProviderPlatform` for API for tests. +* Adds missing unit and integration tests. + ## 1.2.1 * Fix fall through bug. diff --git a/packages/path_provider/example/lib/main.dart b/packages/path_provider/example/lib/main.dart index bea99bc4b671..2e9e9513f787 100644 --- a/packages/path_provider/example/lib/main.dart +++ b/packages/path_provider/example/lib/main.dart @@ -36,6 +36,7 @@ class MyHomePage extends StatefulWidget { class _MyHomePageState extends State { Future _tempDirectory; Future _appSupportDirectory; + Future _appLibraryDirectory; Future _appDocumentsDirectory; Future _externalDocumentsDirectory; @@ -72,6 +73,12 @@ class _MyHomePageState extends State { }); } + void _requestAppLibraryDirectory() { + setState(() { + _appLibraryDirectory = getLibraryDirectory(); + }); + } + void _requestExternalStorageDirectory() { setState(() { _externalDocumentsDirectory = getExternalStorageDirectory(); @@ -85,70 +92,55 @@ class _MyHomePageState extends State { title: Text(widget.title), ), body: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, + child: ListView( children: [ - Column( - children: [ - Padding( - padding: const EdgeInsets.all(16.0), - child: RaisedButton( - child: const Text('Get Temporary Directory'), - onPressed: _requestTempDirectory, - ), - ), - ], - ), - Expanded( - child: FutureBuilder( - future: _tempDirectory, builder: _buildDirectory), - ), - Column( - children: [ - Padding( - padding: const EdgeInsets.all(16.0), - child: RaisedButton( - child: const Text('Get Application Documents Directory'), - onPressed: _requestAppDocumentsDirectory, - ), - ), - ], + Padding( + padding: const EdgeInsets.all(16.0), + child: RaisedButton( + child: const Text('Get Temporary Directory'), + onPressed: _requestTempDirectory, + ), ), - Expanded( - child: FutureBuilder( - future: _appDocumentsDirectory, builder: _buildDirectory), + FutureBuilder( + future: _tempDirectory, builder: _buildDirectory), + Padding( + padding: const EdgeInsets.all(16.0), + child: RaisedButton( + child: const Text('Get Application Documents Directory'), + onPressed: _requestAppDocumentsDirectory, + ), ), - Column( - children: [ - Padding( - padding: const EdgeInsets.all(16.0), - child: RaisedButton( - child: const Text('Get Application Support Directory'), - onPressed: _requestAppSupportDirectory, - ), - ), - ], + FutureBuilder( + future: _appDocumentsDirectory, builder: _buildDirectory), + Padding( + padding: const EdgeInsets.all(16.0), + child: RaisedButton( + child: const Text('Get Application Support Directory'), + onPressed: _requestAppSupportDirectory, + ), ), - Expanded( - child: FutureBuilder( - future: _appSupportDirectory, builder: _buildDirectory), + FutureBuilder( + future: _appSupportDirectory, builder: _buildDirectory), + Padding( + padding: const EdgeInsets.all(16.0), + child: RaisedButton( + child: const Text('Get Application Library Directory'), + onPressed: _requestAppLibraryDirectory, + ), ), - Column(children: [ - Padding( - padding: const EdgeInsets.all(16.0), - child: RaisedButton( - child: Text( - '${Platform.isIOS ? "External directories are unavailable " "on iOS" : "Get External Storage Directory"}'), - onPressed: - Platform.isIOS ? null : _requestExternalStorageDirectory, - ), + FutureBuilder( + future: _appLibraryDirectory, builder: _buildDirectory), + Padding( + padding: const EdgeInsets.all(16.0), + child: RaisedButton( + child: Text( + '${Platform.isIOS ? "External directories are unavailable " "on iOS" : "Get External Storage Directory"}'), + onPressed: + Platform.isIOS ? null : _requestExternalStorageDirectory, ), - ]), - Expanded( - child: FutureBuilder( - future: _externalDocumentsDirectory, - builder: _buildDirectory), ), + FutureBuilder( + future: _externalDocumentsDirectory, builder: _buildDirectory) ], ), ), diff --git a/packages/path_provider/example/test_driver/path_provider.dart b/packages/path_provider/example/test_driver/path_provider.dart index 219d6660df7e..8438965f9646 100644 --- a/packages/path_provider/example/test_driver/path_provider.dart +++ b/packages/path_provider/example/test_driver/path_provider.dart @@ -36,8 +36,18 @@ void main() { }); test('getApplicationSupportDirectory', () async { + final Directory result = await getApplicationSupportDirectory(); + final String uuid = Uuid().v1(); + final File file = File('${result.path}/$uuid.txt'); + file.writeAsStringSync('Hello world!'); + expect(file.readAsStringSync(), 'Hello world!'); + expect(result.listSync(), isNotEmpty); + file.deleteSync(); + }); + + test('getLibraryDirectory', () async { if (Platform.isIOS) { - final Directory result = await getApplicationSupportDirectory(); + final Directory result = await getLibraryDirectory(); final String uuid = Uuid().v1(); final File file = File('${result.path}/$uuid.txt'); file.writeAsStringSync('Hello world!'); @@ -45,7 +55,7 @@ void main() { expect(result.listSync(), isNotEmpty); file.deleteSync(); } else if (Platform.isAndroid) { - final Future result = getApplicationSupportDirectory(); + final Future result = getLibraryDirectory(); expect(result, throwsA(isInstanceOf())); } }); diff --git a/packages/path_provider/ios/Classes/PathProviderPlugin.m b/packages/path_provider/ios/Classes/PathProviderPlugin.m index a8dc4a7b5bfe..1bf0e7af1ff8 100644 --- a/packages/path_provider/ios/Classes/PathProviderPlugin.m +++ b/packages/path_provider/ios/Classes/PathProviderPlugin.m @@ -42,6 +42,8 @@ + (void)registerWithRegistrar:(NSObject*)registrar { } else { result(path); } + } else if ([@"getLibraryDirectory" isEqualToString:call.method]) { + result([self getLibraryDirectory]); } else { result(FlutterMethodNotImplemented); } @@ -60,4 +62,8 @@ + (NSString*)getApplicationSupportDirectory { return GetDirectoryOfType(NSApplicationSupportDirectory); } ++ (NSString*)getLibraryDirectory { + return GetDirectoryOfType(NSLibraryDirectory); +} + @end diff --git a/packages/path_provider/lib/path_provider.dart b/packages/path_provider/lib/path_provider.dart index c53468ae05ca..f0587225c498 100644 --- a/packages/path_provider/lib/path_provider.dart +++ b/packages/path_provider/lib/path_provider.dart @@ -3,13 +3,22 @@ // found in the LICENSE file. import 'dart:async'; -import 'dart:io'; +import 'dart:io' show Directory; import 'package:flutter/services.dart'; +import 'package:meta/meta.dart'; +import 'package:platform/platform.dart'; const MethodChannel _channel = MethodChannel('plugins.flutter.io/path_provider'); +Platform _platform = const LocalPlatform(); + +@visibleForTesting +void setMockPathProviderPlatform(Platform platform) { + _platform = platform; +} + /// Path to the temporary directory on the device that is not backed up and is /// suitable for storing caches of downloaded files. /// @@ -50,6 +59,17 @@ Future getApplicationSupportDirectory() async { return Directory(path); } +/// Path to the directory where application can store files that are persistent, +/// backed up, and not visible to the user, such as sqlite.db. +Future getLibraryDirectory() async { + final String path = + await _channel.invokeMethod('getLibraryDirectory'); + if (path == null) { + return null; + } + return Directory(path); +} + /// Path to a directory where the application may place data that is /// user-generated, or that cannot otherwise be recreated by your application. /// @@ -77,7 +97,7 @@ Future getApplicationDocumentsDirectory() async { /// /// On Android this uses the `getExternalFilesDir(null)`. Future getExternalStorageDirectory() async { - if (Platform.isIOS) + if (_platform.isIOS) throw UnsupportedError("Functionality not available on iOS"); final String path = await _channel.invokeMethod('getStorageDirectory'); diff --git a/packages/path_provider/pubspec.yaml b/packages/path_provider/pubspec.yaml index 634ba1ce834b..80c6bde28379 100644 --- a/packages/path_provider/pubspec.yaml +++ b/packages/path_provider/pubspec.yaml @@ -3,7 +3,7 @@ description: Flutter plugin for getting commonly used locations on the Android & iOS file systems, such as the temp and app data directories. author: Flutter Team homepage: https://github.com/flutter/plugins/tree/master/packages/path_provider -version: 1.2.1 +version: 1.3.0 flutter: plugin: @@ -14,6 +14,8 @@ flutter: dependencies: flutter: sdk: flutter + platform: ^2.0.0 + meta: ^1.0.5 dev_dependencies: flutter_test: diff --git a/packages/path_provider/test/path_provider_test.dart b/packages/path_provider/test/path_provider_test.dart index ec02cf8bbb0e..24368c04cb8c 100644 --- a/packages/path_provider/test/path_provider_test.dart +++ b/packages/path_provider/test/path_provider_test.dart @@ -7,6 +7,7 @@ import 'dart:io'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:path_provider/path_provider.dart'; +import 'package:platform/platform.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); @@ -21,6 +22,10 @@ void main() { return response; }); + setUp(() { + setMockPathProviderPlatform(FakePlatform(operatingSystem: 'android')); + }); + tearDown(() { log.clear(); }); @@ -35,6 +40,18 @@ void main() { expect(directory, isNull); }); + test('getApplicationSupportDirectory test', () async { + response = null; + final Directory directory = await getApplicationSupportDirectory(); + expect( + log, + [ + isMethodCall('getApplicationSupportDirectory', arguments: null) + ], + ); + expect(directory, isNull); + }); + test('getApplicationDocumentsDirectory test', () async { response = null; final Directory directory = await getApplicationDocumentsDirectory(); @@ -47,6 +64,50 @@ void main() { expect(directory, isNull); }); + test('getApplicationSupportDirectory test', () async { + response = null; + final Directory directory = await getApplicationSupportDirectory(); + expect( + log, + [ + isMethodCall('getApplicationSupportDirectory', arguments: null) + ], + ); + expect(directory, isNull); + }); + + test('getExternalStorageDirectory test', () async { + response = null; + final Directory directory = await getExternalStorageDirectory(); + expect( + log, + [isMethodCall('getStorageDirectory', arguments: null)], + ); + expect(directory, isNull); + }); + + test('getLibraryDirectory test', () async { + response = null; + final Directory directory = await getLibraryDirectory(); + expect( + log, + [isMethodCall('getLibraryDirectory', arguments: null)], + ); + expect(directory, isNull); + }); + + test('getExternalStorageDirectory iOS test', () async { + setMockPathProviderPlatform(FakePlatform(operatingSystem: 'ios')); + + response = null; + try { + await getExternalStorageDirectory(); + fail('should throw UnsupportedError'); + } catch (e) { + expect(e, isUnsupportedError); + } + }); + test('TemporaryDirectory path test', () async { final String fakePath = "/foo/bar/baz"; response = fakePath; @@ -54,10 +115,38 @@ void main() { expect(directory.path, equals(fakePath)); }); + test('ApplicationSupportDirectory path test', () async { + final String fakePath = "/foo/bar/baz"; + response = fakePath; + final Directory directory = await getApplicationSupportDirectory(); + expect(directory.path, equals(fakePath)); + }); + test('ApplicationDocumentsDirectory path test', () async { final String fakePath = "/foo/bar/baz"; response = fakePath; final Directory directory = await getApplicationDocumentsDirectory(); expect(directory.path, equals(fakePath)); }); + + test('ApplicationSupportDirectory path test', () async { + final String fakePath = "/foo/bar/baz"; + response = fakePath; + final Directory directory = await getApplicationSupportDirectory(); + expect(directory.path, equals(fakePath)); + }); + + test('ApplicationLibraryDirectory path test', () async { + final String fakePath = "/foo/bar/baz"; + response = fakePath; + final Directory directory = await getLibraryDirectory(); + expect(directory.path, equals(fakePath)); + }); + + test('ExternalStorageDirectory path test', () async { + final String fakePath = "/foo/bar/baz"; + response = fakePath; + final Directory directory = await getExternalStorageDirectory(); + expect(directory.path, equals(fakePath)); + }); } diff --git a/packages/video_player/CHANGELOG.md b/packages/video_player/CHANGELOG.md index abf41afcfbb0..4b1ce43d1465 100644 --- a/packages/video_player/CHANGELOG.md +++ b/packages/video_player/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.10.2+1 + +* Use DefaultHttpDataSourceFactory only when network schemas and use +DefaultHttpDataSourceFactory by default. + ## 0.10.2 * **Android Only** Adds optional VideoFormat used to signal what format the plugin should try. diff --git a/packages/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayerPlugin.java b/packages/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayerPlugin.java index 50c26d460fb3..5b1f55fe14d6 100644 --- a/packages/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayerPlugin.java +++ b/packages/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayerPlugin.java @@ -86,9 +86,7 @@ private static class VideoPlayer { Uri uri = Uri.parse(dataSource); DataSource.Factory dataSourceFactory; - if (isFileOrAsset(uri)) { - dataSourceFactory = new DefaultDataSourceFactory(context, "ExoPlayer"); - } else { + if (isHTTP(uri)) { dataSourceFactory = new DefaultHttpDataSourceFactory( "ExoPlayer", @@ -96,6 +94,8 @@ private static class VideoPlayer { DefaultHttpDataSource.DEFAULT_CONNECT_TIMEOUT_MILLIS, DefaultHttpDataSource.DEFAULT_READ_TIMEOUT_MILLIS, true); + } else { + dataSourceFactory = new DefaultDataSourceFactory(context, "ExoPlayer"); } MediaSource mediaSource = buildMediaSource(uri, dataSourceFactory, formatHint, context); @@ -104,12 +104,12 @@ private static class VideoPlayer { setupVideoPlayer(eventChannel, textureEntry, result); } - private static boolean isFileOrAsset(Uri uri) { + private static boolean isHTTP(Uri uri) { if (uri == null || uri.getScheme() == null) { return false; } String scheme = uri.getScheme(); - return scheme.equals("file") || scheme.equals("asset"); + return scheme.equals("http") || scheme.equals("https"); } private MediaSource buildMediaSource( diff --git a/packages/video_player/pubspec.yaml b/packages/video_player/pubspec.yaml index 3c18e734c964..96374a133405 100644 --- a/packages/video_player/pubspec.yaml +++ b/packages/video_player/pubspec.yaml @@ -2,7 +2,7 @@ name: video_player description: Flutter plugin for displaying inline video with other Flutter widgets on Android and iOS. author: Flutter Team -version: 0.10.2 +version: 0.10.2+1 homepage: https://github.com/flutter/plugins/tree/master/packages/video_player flutter: diff --git a/packages/webview_flutter/CHANGELOG.md b/packages/webview_flutter/CHANGELOG.md index 75b2bf4997fc..4419c2f2f03a 100644 --- a/packages/webview_flutter/CHANGELOG.md +++ b/packages/webview_flutter/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.3.14 + +* Added a getTitle getter to WebViewController. + ## 0.3.13 * Add an optional `userAgent` property to set a custom User Agent. diff --git a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebView.java b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebView.java index 2288b8f52d5a..a7f2db308e15 100644 --- a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebView.java +++ b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebView.java @@ -134,6 +134,9 @@ public void onMethodCall(MethodCall methodCall, Result result) { case "clearCache": clearCache(result); break; + case "getTitle": + getTitle(result); + break; default: result.notImplemented(); } @@ -226,6 +229,10 @@ private void clearCache(Result result) { result.success(null); } + private void getTitle(Result result) { + result.success(webView.getTitle()); + } + private void applySettings(Map settings) { for (String key : settings.keySet()) { switch (key) { diff --git a/packages/webview_flutter/example/test_driver/webview.dart b/packages/webview_flutter/example/test_driver/webview.dart index be7e859df27c..e24afd73f557 100644 --- a/packages/webview_flutter/example/test_driver/webview.dart +++ b/packages/webview_flutter/example/test_driver/webview.dart @@ -457,6 +457,43 @@ void main() { expect(isPaused, _webviewBool(false)); }); }); + + test('getTitle', () async { + final String getTitleTest = ''' + + Some title + + + + + '''; + final String getTitleTestBase64 = + base64Encode(const Utf8Encoder().convert(getTitleTest)); + final Completer pageLoaded = Completer(); + final Completer controllerCompleter = + Completer(); + + await pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + initialUrl: 'data:text/html;charset=utf-8;base64,$getTitleTestBase64', + onWebViewCreated: (WebViewController controller) { + controllerCompleter.complete(controller); + }, + onPageFinished: (String url) { + pageLoaded.complete(null); + }, + ), + ), + ); + + final WebViewController controller = await controllerCompleter.future; + await pageLoaded.future; + + final String title = await controller.getTitle(); + expect(title, 'Some title'); + }); } Future pumpWidget(Widget widget) { diff --git a/packages/webview_flutter/ios/Classes/FlutterWebView.m b/packages/webview_flutter/ios/Classes/FlutterWebView.m index fed73d8a7d2c..36f4e8cb5cfe 100644 --- a/packages/webview_flutter/ios/Classes/FlutterWebView.m +++ b/packages/webview_flutter/ios/Classes/FlutterWebView.m @@ -118,6 +118,8 @@ - (void)onMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { [self onRemoveJavaScriptChannels:call result:result]; } else if ([[call method] isEqualToString:@"clearCache"]) { [self clearCache:result]; + } else if ([[call method] isEqualToString:@"getTitle"]) { + [self onGetTitle:result]; } else { result(FlutterMethodNotImplemented); } @@ -238,6 +240,11 @@ - (void)clearCache:(FlutterResult)result { } } +- (void)onGetTitle:(FlutterResult)result { + NSString* title = _webView.title; + result(title); +} + // Returns nil when successful, or an error message when one or more keys are unknown. - (NSString*)applySettings:(NSDictionary*)settings { NSMutableArray* unknownKeys = [[NSMutableArray alloc] init]; diff --git a/packages/webview_flutter/lib/platform_interface.dart b/packages/webview_flutter/lib/platform_interface.dart index 972cb25da54b..7e82bae91138 100644 --- a/packages/webview_flutter/lib/platform_interface.dart +++ b/packages/webview_flutter/lib/platform_interface.dart @@ -158,6 +158,12 @@ abstract class WebViewPlatformController { throw UnimplementedError( "WebView removeJavascriptChannels is not implemented on the current platform"); } + + /// Returns the title of the currently loaded page. + Future getTitle() { + throw UnimplementedError( + "WebView getTitle is not implemented on the current platform"); + } } /// A single setting for configuring a WebViewPlatform which may be absent. diff --git a/packages/webview_flutter/lib/src/webview_method_channel.dart b/packages/webview_flutter/lib/src/webview_method_channel.dart index f34000569551..c2949cc77a2a 100644 --- a/packages/webview_flutter/lib/src/webview_method_channel.dart +++ b/packages/webview_flutter/lib/src/webview_method_channel.dart @@ -103,6 +103,9 @@ class MethodChannelWebViewPlatform implements WebViewPlatformController { 'removeJavascriptChannels', javascriptChannelNames.toList()); } + @override + Future getTitle() => _channel.invokeMethod("getTitle"); + /// Method channel implementation for [WebViewPlatform.clearCookies]. static Future clearCookies() { return _cookieManagerChannel diff --git a/packages/webview_flutter/lib/webview_flutter.dart b/packages/webview_flutter/lib/webview_flutter.dart index 97b7786de9a6..dec62b700122 100644 --- a/packages/webview_flutter/lib/webview_flutter.dart +++ b/packages/webview_flutter/lib/webview_flutter.dart @@ -625,6 +625,11 @@ class WebViewController { // ignore: strong_mode_implicit_dynamic_method return _webViewPlatformController.evaluateJavascript(javascriptString); } + + /// Returns the title of the currently loaded page. + Future getTitle() { + return _webViewPlatformController.getTitle(); + } } /// Manages cookies pertaining to all [WebView]s. diff --git a/packages/webview_flutter/pubspec.yaml b/packages/webview_flutter/pubspec.yaml index 23c09e81444f..69f45118de0a 100644 --- a/packages/webview_flutter/pubspec.yaml +++ b/packages/webview_flutter/pubspec.yaml @@ -1,6 +1,6 @@ name: webview_flutter description: A Flutter plugin that provides a WebView widget on Android and iOS. -version: 0.3.13 +version: 0.3.14 author: Flutter Team homepage: https://github.com/flutter/plugins/tree/master/packages/webview_flutter diff --git a/script/build_all_plugins_app.sh b/script/build_all_plugins_app.sh index 4bf59d2e8a80..dcf3bcdfd2a3 100755 --- a/script/build_all_plugins_app.sh +++ b/script/build_all_plugins_app.sh @@ -10,9 +10,7 @@ REPO_DIR="$(dirname "$SCRIPT_DIR")" source "$SCRIPT_DIR/common.sh" check_changed_packages > /dev/null -cd $REPO_DIR/examples/all_plugins -flutter clean > /dev/null -(cd "$REPO_DIR" && pub global run flutter_plugin_tools gen-pubspec --exclude instrumentation_adapter) +(cd "$REPO_DIR" && pub global run flutter_plugin_tools all-plugins-app --exclude instrumentation_adapter) function error() { echo "$@" 1>&2 @@ -21,7 +19,7 @@ function error() { failures=0 for version in "debug" "release"; do - (flutter build $@ --$version > /dev/null) + (cd $REPO_DIR/all_plugins && flutter build $@ --$version) if [ $? -eq 0 ]; then echo "Successfully built $version all_plugins app." @@ -41,4 +39,5 @@ for version in "debug" "release"; do fi done +rm -rf $REPO_DIR/all_plugins/ exit $failures