diff --git a/packages/sensors/CHANGELOG.md b/packages/sensors/CHANGELOG.md index d90ea5aeb6df..8b02f99683b7 100644 --- a/packages/sensors/CHANGELOG.md +++ b/packages/sensors/CHANGELOG.md @@ -1,3 +1,10 @@ +## 0.4.1 + +* Support the v2 Android embedder. +* Update to AndroidX. +* Migrate to using the new e2e test binding. +* Add a e2e test. + ## 0.4.0+3 * Update and migrate iOS example project. diff --git a/packages/sensors/android/build.gradle b/packages/sensors/android/build.gradle index 56a76026f57a..47e7f63623b7 100644 --- a/packages/sensors/android/build.gradle +++ b/packages/sensors/android/build.gradle @@ -45,3 +45,29 @@ android { disable 'InvalidPackage' } } + +// TODO(cyanglaz): Remove this hack once androidx.lifecycle is included on stable. https://github.com/flutter/flutter/issues/42348 +afterEvaluate { + def containsEmbeddingDependencies = false + for (def configuration : configurations.all) { + for (def dependency : configuration.dependencies) { + if (dependency.group == 'io.flutter' && + dependency.name.startsWith('flutter_embedding') && + dependency.isTransitive()) + { + containsEmbeddingDependencies = true + break + } + } + } + if (!containsEmbeddingDependencies) { + android { + dependencies { + def lifecycle_version = "1.1.1" + api "android.arch.lifecycle:runtime:$lifecycle_version" + api "android.arch.lifecycle:common:$lifecycle_version" + api "android.arch.lifecycle:common-java8:$lifecycle_version" + } + } + } +} diff --git a/packages/sensors/android/src/main/java/io/flutter/plugins/sensors/SensorsPlugin.java b/packages/sensors/android/src/main/java/io/flutter/plugins/sensors/SensorsPlugin.java index 65c47707029b..063f40641bcf 100644 --- a/packages/sensors/android/src/main/java/io/flutter/plugins/sensors/SensorsPlugin.java +++ b/packages/sensors/android/src/main/java/io/flutter/plugins/sensors/SensorsPlugin.java @@ -6,71 +6,67 @@ import android.content.Context; import android.hardware.Sensor; -import android.hardware.SensorEvent; -import android.hardware.SensorEventListener; import android.hardware.SensorManager; +import io.flutter.embedding.engine.plugins.FlutterPlugin; +import io.flutter.plugin.common.BinaryMessenger; import io.flutter.plugin.common.EventChannel; import io.flutter.plugin.common.PluginRegistry.Registrar; /** SensorsPlugin */ -public class SensorsPlugin implements EventChannel.StreamHandler { +public class SensorsPlugin implements FlutterPlugin { private static final String ACCELEROMETER_CHANNEL_NAME = "plugins.flutter.io/sensors/accelerometer"; private static final String GYROSCOPE_CHANNEL_NAME = "plugins.flutter.io/sensors/gyroscope"; private static final String USER_ACCELEROMETER_CHANNEL_NAME = "plugins.flutter.io/sensors/user_accel"; + private EventChannel accelerometerChannel; + private EventChannel userAccelChannel; + private EventChannel gyroscopeChannel; + /** Plugin registration. */ public static void registerWith(Registrar registrar) { - final EventChannel accelerometerChannel = - new EventChannel(registrar.messenger(), ACCELEROMETER_CHANNEL_NAME); - accelerometerChannel.setStreamHandler( - new SensorsPlugin(registrar.context(), Sensor.TYPE_ACCELEROMETER)); - - final EventChannel userAccelChannel = - new EventChannel(registrar.messenger(), USER_ACCELEROMETER_CHANNEL_NAME); - userAccelChannel.setStreamHandler( - new SensorsPlugin(registrar.context(), Sensor.TYPE_LINEAR_ACCELERATION)); - - final EventChannel gyroscopeChannel = - new EventChannel(registrar.messenger(), GYROSCOPE_CHANNEL_NAME); - gyroscopeChannel.setStreamHandler( - new SensorsPlugin(registrar.context(), Sensor.TYPE_GYROSCOPE)); - } - - private SensorEventListener sensorEventListener; - private final SensorManager sensorManager; - private final Sensor sensor; - - private SensorsPlugin(Context context, int sensorType) { - sensorManager = (SensorManager) context.getSystemService(context.SENSOR_SERVICE); - sensor = sensorManager.getDefaultSensor(sensorType); + SensorsPlugin plugin = new SensorsPlugin(); + plugin.setupEventChannels(registrar.context(), registrar.messenger()); } @Override - public void onListen(Object arguments, EventChannel.EventSink events) { - sensorEventListener = createSensorEventListener(events); - sensorManager.registerListener(sensorEventListener, sensor, sensorManager.SENSOR_DELAY_NORMAL); + public void onAttachedToEngine(FlutterPluginBinding binding) { + final Context context = binding.getApplicationContext(); + setupEventChannels(context, binding.getFlutterEngine().getDartExecutor()); } @Override - public void onCancel(Object arguments) { - sensorManager.unregisterListener(sensorEventListener); + public void onDetachedFromEngine(FlutterPluginBinding binding) { + teardownEventChannels(); } - SensorEventListener createSensorEventListener(final EventChannel.EventSink events) { - return new SensorEventListener() { - @Override - public void onAccuracyChanged(Sensor sensor, int accuracy) {} + private void setupEventChannels(Context context, BinaryMessenger messenger) { + accelerometerChannel = new EventChannel(messenger, ACCELEROMETER_CHANNEL_NAME); + final StreamHandlerImpl accelerationStreamHandler = + new StreamHandlerImpl( + (SensorManager) context.getSystemService(context.SENSOR_SERVICE), + Sensor.TYPE_ACCELEROMETER); + accelerometerChannel.setStreamHandler(accelerationStreamHandler); + + userAccelChannel = new EventChannel(messenger, USER_ACCELEROMETER_CHANNEL_NAME); + final StreamHandlerImpl linearAccelerationStreamHandler = + new StreamHandlerImpl( + (SensorManager) context.getSystemService(context.SENSOR_SERVICE), + Sensor.TYPE_LINEAR_ACCELERATION); + userAccelChannel.setStreamHandler(linearAccelerationStreamHandler); + + gyroscopeChannel = new EventChannel(messenger, GYROSCOPE_CHANNEL_NAME); + final StreamHandlerImpl gyroScopeStreamHandler = + new StreamHandlerImpl( + (SensorManager) context.getSystemService(context.SENSOR_SERVICE), + Sensor.TYPE_GYROSCOPE); + gyroscopeChannel.setStreamHandler(gyroScopeStreamHandler); + } - @Override - public void onSensorChanged(SensorEvent event) { - double[] sensorValues = new double[event.values.length]; - for (int i = 0; i < event.values.length; i++) { - sensorValues[i] = event.values[i]; - } - events.success(sensorValues); - } - }; + private void teardownEventChannels() { + accelerometerChannel.setStreamHandler(null); + userAccelChannel.setStreamHandler(null); + gyroscopeChannel.setStreamHandler(null); } } diff --git a/packages/sensors/android/src/main/java/io/flutter/plugins/sensors/StreamHandlerImpl.java b/packages/sensors/android/src/main/java/io/flutter/plugins/sensors/StreamHandlerImpl.java new file mode 100644 index 000000000000..ac0546109f96 --- /dev/null +++ b/packages/sensors/android/src/main/java/io/flutter/plugins/sensors/StreamHandlerImpl.java @@ -0,0 +1,50 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package io.flutter.plugins.sensors; + +import android.hardware.Sensor; +import android.hardware.SensorEvent; +import android.hardware.SensorEventListener; +import android.hardware.SensorManager; +import io.flutter.plugin.common.EventChannel; + +class StreamHandlerImpl implements EventChannel.StreamHandler { + + private SensorEventListener sensorEventListener; + private final SensorManager sensorManager; + private final Sensor sensor; + + StreamHandlerImpl(SensorManager sensorManager, int sensorType) { + this.sensorManager = sensorManager; + sensor = sensorManager.getDefaultSensor(sensorType); + } + + @Override + public void onListen(Object arguments, EventChannel.EventSink events) { + sensorEventListener = createSensorEventListener(events); + sensorManager.registerListener(sensorEventListener, sensor, sensorManager.SENSOR_DELAY_NORMAL); + } + + @Override + public void onCancel(Object arguments) { + sensorManager.unregisterListener(sensorEventListener); + } + + SensorEventListener createSensorEventListener(final EventChannel.EventSink events) { + return new SensorEventListener() { + @Override + public void onAccuracyChanged(Sensor sensor, int accuracy) {} + + @Override + public void onSensorChanged(SensorEvent event) { + double[] sensorValues = new double[event.values.length]; + for (int i = 0; i < event.values.length; i++) { + sensorValues[i] = event.values[i]; + } + events.success(sensorValues); + } + }; + } +} diff --git a/packages/sensors/example/android/app/src/main/AndroidManifest.xml b/packages/sensors/example/android/app/src/main/AndroidManifest.xml index 92a8fc62ea99..67d4eb5e4a5f 100644 --- a/packages/sensors/example/android/app/src/main/AndroidManifest.xml +++ b/packages/sensors/example/android/app/src/main/AndroidManifest.xml @@ -4,12 +4,18 @@ - + + diff --git a/packages/sensors/example/android/app/src/main/java/io/flutter/plugins/sensorsexample/EmbeddingV1Activity.java b/packages/sensors/example/android/app/src/main/java/io/flutter/plugins/sensorsexample/EmbeddingV1Activity.java new file mode 100644 index 000000000000..c91a3a942ba5 --- /dev/null +++ b/packages/sensors/example/android/app/src/main/java/io/flutter/plugins/sensorsexample/EmbeddingV1Activity.java @@ -0,0 +1,17 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package io.flutter.plugins.sensorsexample; + +import android.os.Bundle; +import io.flutter.app.FlutterActivity; +import io.flutter.plugins.GeneratedPluginRegistrant; + +public class EmbeddingV1Activity extends FlutterActivity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + GeneratedPluginRegistrant.registerWith(this); + } +} diff --git a/packages/sensors/example/android/app/src/main/java/io/flutter/plugins/sensorsexample/EmbeddingV1ActivityTest.java b/packages/sensors/example/android/app/src/main/java/io/flutter/plugins/sensorsexample/EmbeddingV1ActivityTest.java new file mode 100644 index 000000000000..6d0274f50e2c --- /dev/null +++ b/packages/sensors/example/android/app/src/main/java/io/flutter/plugins/sensorsexample/EmbeddingV1ActivityTest.java @@ -0,0 +1,13 @@ +package io.flutter.plugins.sensorsexample; + +import androidx.test.rule.ActivityTestRule; +import dev.flutter.plugins.e2e.FlutterRunner; +import org.junit.Rule; +import org.junit.runner.RunWith; + +@RunWith(FlutterRunner.class) +public class EmbeddingV1ActivityTest { + @Rule + public ActivityTestRule rule = + new ActivityTestRule<>(EmbeddingV1Activity.class); +} diff --git a/packages/sensors/example/android/app/src/main/java/io/flutter/plugins/sensorsexample/MainActivity.java b/packages/sensors/example/android/app/src/main/java/io/flutter/plugins/sensorsexample/MainActivity.java index d4dad76b9b61..38d05d82afb5 100644 --- a/packages/sensors/example/android/app/src/main/java/io/flutter/plugins/sensorsexample/MainActivity.java +++ b/packages/sensors/example/android/app/src/main/java/io/flutter/plugins/sensorsexample/MainActivity.java @@ -1,13 +1,20 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + package io.flutter.plugins.sensorsexample; -import android.os.Bundle; -import io.flutter.app.FlutterActivity; -import io.flutter.plugins.GeneratedPluginRegistrant; +import io.flutter.embedding.android.FlutterActivity; +import io.flutter.embedding.engine.FlutterEngine; +import io.flutter.plugins.sensors.SensorsPlugin; public class MainActivity extends FlutterActivity { + + // TODO(cyanglaz): Remove this once v2 of GeneratedPluginRegistrant rolls to stable. + // https://github.com/flutter/flutter/issues/42694 @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - GeneratedPluginRegistrant.registerWith(this); + public void configureFlutterEngine(FlutterEngine flutterEngine) { + super.configureFlutterEngine(flutterEngine); + flutterEngine.getPlugins().add(new SensorsPlugin()); } } diff --git a/packages/sensors/example/android/app/src/main/java/io/flutter/plugins/sensorsexample/MainActivityTest.java b/packages/sensors/example/android/app/src/main/java/io/flutter/plugins/sensorsexample/MainActivityTest.java new file mode 100644 index 000000000000..dee5dffe3553 --- /dev/null +++ b/packages/sensors/example/android/app/src/main/java/io/flutter/plugins/sensorsexample/MainActivityTest.java @@ -0,0 +1,15 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package io.flutter.plugins.sensorsexample; + +import androidx.test.rule.ActivityTestRule; +import dev.flutter.plugins.e2e.FlutterRunner; +import org.junit.Rule; +import org.junit.runner.RunWith; + +@RunWith(FlutterRunner.class) +public class MainActivityTest { + @Rule public ActivityTestRule rule = new ActivityTestRule<>(MainActivity.class); +} diff --git a/packages/sensors/example/android/gradle.properties b/packages/sensors/example/android/gradle.properties index 8bd86f680510..38c8d4544ff1 100644 --- a/packages/sensors/example/android/gradle.properties +++ b/packages/sensors/example/android/gradle.properties @@ -1 +1,4 @@ org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +android.useAndroidX=true +android.enableJetifier=true diff --git a/packages/sensors/example/pubspec.yaml b/packages/sensors/example/pubspec.yaml index 0da50897c809..c82faa93999c 100644 --- a/packages/sensors/example/pubspec.yaml +++ b/packages/sensors/example/pubspec.yaml @@ -7,6 +7,15 @@ dependencies: sensors: path: ../ -flutter: +dev_dependencies: + flutter_driver: + sdk: flutter + e2e: ^0.2.0 +flutter: uses-material-design: true + +environment: + sdk: ">=2.0.0-dev.28.0 <3.0.0" + flutter: ">=1.9.1+hotfix.2 <2.0.0" + diff --git a/packages/sensors/example/test_driver/test/sensors_e2e_test.dart b/packages/sensors/example/test_driver/test/sensors_e2e_test.dart new file mode 100644 index 000000000000..ff6e9ce74ad9 --- /dev/null +++ b/packages/sensors/example/test_driver/test/sensors_e2e_test.dart @@ -0,0 +1,15 @@ +// Copyright 2019, the Chromium project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:async'; +import 'dart:io'; +import 'package:flutter_driver/flutter_driver.dart'; + +Future main() async { + final FlutterDriver driver = await FlutterDriver.connect(); + final String result = + await driver.requestData(null, timeout: const Duration(minutes: 1)); + driver.close(); + exit(result == 'pass' ? 0 : 1); +} diff --git a/packages/sensors/pubspec.yaml b/packages/sensors/pubspec.yaml index 2cb3395c7dbc..6db40e93f193 100644 --- a/packages/sensors/pubspec.yaml +++ b/packages/sensors/pubspec.yaml @@ -3,7 +3,7 @@ description: Flutter plugin for accessing the Android and iOS accelerometer and gyroscope sensors. author: Flutter Team homepage: https://github.com/flutter/plugins/tree/master/packages/sensors -version: 0.4.0+3 +version: 0.4.1 flutter: plugin: @@ -19,7 +19,8 @@ dev_dependencies: test: ^1.3.0 flutter_test: sdk: flutter + e2e: ^0.2.0 environment: sdk: ">=2.0.0-dev.28.0 <3.0.0" - flutter: ">=0.1.4 <2.0.0" + flutter: ">=1.6.7 <2.0.0" diff --git a/packages/sensors/test/sensors_e2e.dart b/packages/sensors/test/sensors_e2e.dart new file mode 100644 index 000000000000..acc356dfc235 --- /dev/null +++ b/packages/sensors/test/sensors_e2e.dart @@ -0,0 +1,24 @@ +// Copyright 2019, the Chromium project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:async'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:sensors/sensors.dart'; +import 'package:e2e/e2e.dart'; + +void main() { + E2EWidgetsFlutterBinding.ensureInitialized(); + + testWidgets('Can subscript to accelerometerEvents and get non-null events', + (WidgetTester tester) async { + final Completer completer = + Completer(); + StreamSubscription subscription; + subscription = accelerometerEvents.listen((AccelerometerEvent event) { + completer.complete(event); + subscription.cancel(); + }); + expect(await completer.future, isNotNull); + }); +}