[sensor] Support v2 android embedder. (#2164)

diff --git a/packages/sensors/CHANGELOG.md b/packages/sensors/CHANGELOG.md
index d90ea5a..8b02f99 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 56a7602..47e7f63 100644
--- a/packages/sensors/android/build.gradle
+++ b/packages/sensors/android/build.gradle
@@ -45,3 +45,29 @@
         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 65c4770..063f406 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);
 
-      @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);
-      }
-    };
+    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);
+  }
+
+  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 0000000..ac05461
--- /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 92a8fc6..67d4eb5 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 @@
     <uses-permission android:name="android.permission.INTERNET"/>
 
     <application android:name="io.flutter.app.FlutterApplication" android:label="sensors_example" android:icon="@mipmap/ic_launcher">
-        <activity android:name=".MainActivity"
+        <activity android:name=".EmbeddingV1Activity"
                   android:launchMode="singleTop"
                   android:theme="@android:style/Theme.Black.NoTitleBar"
                   android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection"
                   android:hardwareAccelerated="true"
                   android:windowSoftInputMode="adjustResize">
+        </activity>
+        <activity android:name=".MainActivity"
+            android:theme="@android:style/Theme.Black.NoTitleBar"
+            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection"
+            android:hardwareAccelerated="true"
+            android:windowSoftInputMode="adjustResize">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
                 <category android:name="android.intent.category.LAUNCHER"/>
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 0000000..c91a3a9
--- /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 0000000..6d0274f
--- /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<EmbeddingV1Activity> 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 d4dad76..38d05d8 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 0000000..dee5dff
--- /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<MainActivity> rule = new ActivityTestRule<>(MainActivity.class);
+}
diff --git a/packages/sensors/example/android/gradle.properties b/packages/sensors/example/android/gradle.properties
index 8bd86f6..38c8d45 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 0da5089..c82faa9 100644
--- a/packages/sensors/example/pubspec.yaml
+++ b/packages/sensors/example/pubspec.yaml
@@ -7,6 +7,15 @@
   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 0000000..ff6e9ce
--- /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<void> 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 2cb3395..6db40e9 100644
--- a/packages/sensors/pubspec.yaml
+++ b/packages/sensors/pubspec.yaml
@@ -3,7 +3,7 @@
   gyroscope sensors.
 author: Flutter Team <flutter-dev@googlegroups.com>
 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 @@
   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 0000000..acc356d
--- /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<AccelerometerEvent> completer =
+        Completer<AccelerometerEvent>();
+    StreamSubscription<AccelerometerEvent> subscription;
+    subscription = accelerometerEvents.listen((AccelerometerEvent event) {
+      completer.complete(event);
+      subscription.cancel();
+    });
+    expect(await completer.future, isNotNull);
+  });
+}