Show a warning when a module uses a v1 only plugin (#44499)

diff --git a/packages/flutter_tools/test/general.shard/plugins_test.dart b/packages/flutter_tools/test/general.shard/plugins_test.dart
index ea41d4d..802d8034 100644
--- a/packages/flutter_tools/test/general.shard/plugins_test.dart
+++ b/packages/flutter_tools/test/general.shard/plugins_test.dart
@@ -55,7 +55,7 @@
       dummyPackageDirectory = fs.directory('/pubcache/apackage/lib/');
       packagesFile = fs.file(fs.path.join(flutterProject.directory.path, PackageMap.globalPackagesPath));
       packagesFile..createSync(recursive: true)
-          ..writeAsStringSync('apackage:file://${dummyPackageDirectory.path}');
+          ..writeAsStringSync('apackage:file://${dummyPackageDirectory.path}\n');
     });
 
     // Makes the dummy package pointed to by packagesFile look like a plugin.
@@ -69,6 +69,126 @@
   ''');
     }
 
+
+    void createNewJavaPlugin1() {
+      final Directory pluginUsingJavaAndNewEmbeddingDir =
+              fs.systemTempDirectory.createTempSync('flutter_plugin_using_java_and_new_embedding_dir.');
+      pluginUsingJavaAndNewEmbeddingDir
+        .childFile('pubspec.yaml')
+        .writeAsStringSync('''
+flutter:
+  plugin:
+    androidPackage: plugin1
+    pluginClass: UseNewEmbedding
+              ''');
+      pluginUsingJavaAndNewEmbeddingDir
+        .childDirectory('android')
+        .childDirectory('src')
+        .childDirectory('main')
+        .childDirectory('java')
+        .childDirectory('plugin1')
+        .childFile('UseNewEmbedding.java')
+        ..createSync(recursive: true)
+        ..writeAsStringSync('import io.flutter.embedding.engine.plugins.FlutterPlugin;');
+
+      flutterProject.directory
+        .childFile('.packages')
+        .writeAsStringSync(
+          'plugin1:${pluginUsingJavaAndNewEmbeddingDir.childDirectory('lib').uri.toString()}\n',
+          mode: FileMode.append,
+        );
+    }
+
+    void createNewKotlinPlugin2() {
+      final Directory pluginUsingKotlinAndNewEmbeddingDir =
+          fs.systemTempDirectory.createTempSync('flutter_plugin_using_kotlin_and_new_embedding_dir.');
+      pluginUsingKotlinAndNewEmbeddingDir
+        .childFile('pubspec.yaml')
+        .writeAsStringSync('''
+flutter:
+  plugin:
+    androidPackage: plugin2
+    pluginClass: UseNewEmbedding
+          ''');
+      pluginUsingKotlinAndNewEmbeddingDir
+        .childDirectory('android')
+        .childDirectory('src')
+        .childDirectory('main')
+        .childDirectory('kotlin')
+        .childDirectory('plugin2')
+        .childFile('UseNewEmbedding.kt')
+        ..createSync(recursive: true)
+        ..writeAsStringSync('import io.flutter.embedding.engine.plugins.FlutterPlugin');
+
+      flutterProject.directory
+        .childFile('.packages')
+        .writeAsStringSync(
+          'plugin2:${pluginUsingKotlinAndNewEmbeddingDir.childDirectory('lib').uri.toString()}\n',
+          mode: FileMode.append,
+        );
+    }
+
+    void createOldJavaPlugin3() {
+      final Directory pluginUsingOldEmbeddingDir =
+        fs.systemTempDirectory.createTempSync('flutter_plugin_using_old_embedding_dir.');
+      pluginUsingOldEmbeddingDir
+        .childFile('pubspec.yaml')
+        .writeAsStringSync('''
+flutter:
+  plugin:
+    androidPackage: plugin3
+    pluginClass: UseOldEmbedding
+        ''');
+      pluginUsingOldEmbeddingDir
+        .childDirectory('android')
+        .childDirectory('src')
+        .childDirectory('main')
+        .childDirectory('java')
+        .childDirectory('plugin3')
+        .childFile('UseOldEmbedding.java')
+        ..createSync(recursive: true);
+
+      flutterProject.directory
+        .childFile('.packages')
+        .writeAsStringSync(
+          'plugin3:${pluginUsingOldEmbeddingDir.childDirectory('lib').uri.toString()}\n',
+          mode: FileMode.append,
+        );
+    }
+
+    void createDualSupportJavaPlugin4() {
+      final Directory pluginUsingJavaAndNewEmbeddingDir =
+        fs.systemTempDirectory.createTempSync('flutter_plugin_using_java_and_new_embedding_dir.');
+      pluginUsingJavaAndNewEmbeddingDir
+        .childFile('pubspec.yaml')
+        .writeAsStringSync('''
+flutter:
+  plugin:
+    androidPackage: plugin4
+    pluginClass: UseBothEmbedding
+''');
+      pluginUsingJavaAndNewEmbeddingDir
+        .childDirectory('android')
+        .childDirectory('src')
+        .childDirectory('main')
+        .childDirectory('java')
+        .childDirectory('plugin4')
+        .childFile('UseBothEmbedding.java')
+        ..createSync(recursive: true)
+        ..writeAsStringSync(
+          'import io.flutter.embedding.engine.plugins.FlutterPlugin;\n'
+          'PluginRegistry\n'
+          'registerWith(Irrelevant registrar)\n'
+        );
+
+      flutterProject.directory
+        .childFile('.packages')
+        .writeAsStringSync(
+          'plugin4:${pluginUsingJavaAndNewEmbeddingDir.childDirectory('lib').uri.toString()}',
+          mode: FileMode.append,
+        );
+    }
+
     // Creates the files that would indicate that pod install has run for the
     // given project.
     void simulatePodInstallRun(XcodeBasedProject project) {
@@ -149,6 +269,7 @@
         expect(registrant.existsSync(), isTrue);
         expect(registrant.readAsStringSync(), contains('package io.flutter.plugins'));
         expect(registrant.readAsStringSync(), contains('class GeneratedPluginRegistrant'));
+        expect(registrant.readAsStringSync(), contains('public static void registerWith(PluginRegistry registry)'));
       }, overrides: <Type, Generator>{
         FileSystem: () => fs,
         ProcessManager: () => FakeProcessManager.any(),
@@ -168,6 +289,7 @@
         expect(registrant.existsSync(), isTrue);
         expect(registrant.readAsStringSync(), contains('package io.flutter.plugins'));
         expect(registrant.readAsStringSync(), contains('class GeneratedPluginRegistrant'));
+        expect(registrant.readAsStringSync(), contains('public static void registerWith(@NonNull FlutterEngine flutterEngine)'));
       }, overrides: <Type, Generator>{
         FileSystem: () => fs,
         ProcessManager: () => FakeProcessManager.any(),
@@ -178,72 +300,9 @@
         when(flutterProject.isModule).thenReturn(false);
         when(androidProject.getEmbeddingVersion()).thenReturn(AndroidEmbeddingVersion.v2);
 
-        final Directory pluginUsingJavaAndNewEmbeddingDir =
-          fs.systemTempDirectory.createTempSync('flutter_plugin_using_java_and_new_embedding_dir.');
-        pluginUsingJavaAndNewEmbeddingDir
-          .childFile('pubspec.yaml')
-          .writeAsStringSync('''
-  flutter:
-    plugin:
-      androidPackage: plugin1
-      pluginClass: UseNewEmbedding
-  ''');
-        pluginUsingJavaAndNewEmbeddingDir
-          .childDirectory('android')
-          .childDirectory('src')
-          .childDirectory('main')
-          .childDirectory('java')
-          .childDirectory('plugin1')
-          .childFile('UseNewEmbedding.java')
-          ..createSync(recursive: true)
-          ..writeAsStringSync('import io.flutter.embedding.engine.plugins.FlutterPlugin;');
-
-        final Directory pluginUsingKotlinAndNewEmbeddingDir =
-          fs.systemTempDirectory.createTempSync('flutter_plugin_using_kotlin_and_new_embedding_dir.');
-        pluginUsingKotlinAndNewEmbeddingDir
-          .childFile('pubspec.yaml')
-          .writeAsStringSync('''
-  flutter:
-    plugin:
-      androidPackage: plugin2
-      pluginClass: UseNewEmbedding
-  ''');
-        pluginUsingKotlinAndNewEmbeddingDir
-          .childDirectory('android')
-          .childDirectory('src')
-          .childDirectory('main')
-          .childDirectory('kotlin')
-          .childDirectory('plugin2')
-          .childFile('UseNewEmbedding.kt')
-          ..createSync(recursive: true)
-          ..writeAsStringSync('import io.flutter.embedding.engine.plugins.FlutterPlugin');
-
-        final Directory pluginUsingOldEmbeddingDir =
-          fs.systemTempDirectory.createTempSync('flutter_plugin_using_old_embedding_dir.');
-        pluginUsingOldEmbeddingDir
-          .childFile('pubspec.yaml')
-          .writeAsStringSync('''
-  flutter:
-    plugin:
-      androidPackage: plugin3
-      pluginClass: UseOldEmbedding
-  ''');
-        pluginUsingOldEmbeddingDir
-          .childDirectory('android')
-          .childDirectory('src')
-          .childDirectory('main')
-          .childDirectory('java')
-          .childDirectory('plugin3')
-          .childFile('UseOldEmbedding.java')
-          ..createSync(recursive: true);
-
-        flutterProject.directory
-          .childFile('.packages')
-          .writeAsStringSync('''
-plugin1:${pluginUsingJavaAndNewEmbeddingDir.childDirectory('lib').uri.toString()}
-plugin2:${pluginUsingKotlinAndNewEmbeddingDir.childDirectory('lib').uri.toString()}
-plugin3:${pluginUsingOldEmbeddingDir.childDirectory('lib').uri.toString()}
-''');
+        createNewJavaPlugin1();
+        createNewKotlinPlugin2();
+        createOldJavaPlugin3();
 
         await injectPlugins(flutterProject);
 
@@ -258,6 +317,8 @@
         expect(registrant.readAsStringSync(),
           contains('plugin3.UseOldEmbedding.registerWith(shimPluginRegistry.registrarFor("plugin3.UseOldEmbedding"));'));
 
+        // There should be no warning message
+        expect(testLogger.statusText, isNot(contains('go/android-plugin-migration')));
       }, overrides: <Type, Generator>{
         FileSystem: () => fs,
         ProcessManager: () => FakeProcessManager.any(),
@@ -269,31 +330,8 @@
         when(flutterProject.isModule).thenReturn(false);
         when(androidProject.getEmbeddingVersion()).thenReturn(AndroidEmbeddingVersion.v1);
 
-        final Directory pluginUsingJavaAndNewEmbeddingDir =
-          fs.systemTempDirectory.createTempSync('flutter_plugin_using_java_and_new_embedding_dir.');
-        pluginUsingJavaAndNewEmbeddingDir
-          .childFile('pubspec.yaml')
-          .writeAsStringSync('''
-  flutter:
-    plugin:
-      androidPackage: plugin1
-      pluginClass: UseNewEmbedding
-  ''');
-        pluginUsingJavaAndNewEmbeddingDir
-          .childDirectory('android')
-          .childDirectory('src')
-          .childDirectory('main')
-          .childDirectory('java')
-          .childDirectory('plugin1')
-          .childFile('UseNewEmbedding.java')
-          ..createSync(recursive: true)
-          ..writeAsStringSync('import io.flutter.embedding.engine.plugins.FlutterPlugin;');
+        createNewJavaPlugin1();
 
-        flutterProject.directory
-          .childFile('.packages')
-          .writeAsStringSync('''
-plugin1:${pluginUsingJavaAndNewEmbeddingDir.childDirectory('lib').uri.toString()}
-''');
         await expectLater(
           () async {
             await injectPlugins(flutterProject);
@@ -310,39 +348,12 @@
         XcodeProjectInterpreter: () => xcodeProjectInterpreter,
       });
 
-      testUsingContext('allows app use a plugin that supports v1 and v2 embedding', () async {
+      testUsingContext('old embedding app uses a plugin that supports v1 and v2 embedding', () async {
         when(flutterProject.isModule).thenReturn(false);
         when(androidProject.getEmbeddingVersion()).thenReturn(AndroidEmbeddingVersion.v1);
 
-        final Directory pluginUsingJavaAndNewEmbeddingDir =
-          fs.systemTempDirectory.createTempSync('flutter_plugin_using_java_and_new_embedding_dir.');
-        pluginUsingJavaAndNewEmbeddingDir
-          .childFile('pubspec.yaml')
-          .writeAsStringSync('''
-  flutter:
-    plugin:
-      androidPackage: plugin1
-      pluginClass: UseNewEmbedding
-  ''');
-        pluginUsingJavaAndNewEmbeddingDir
-          .childDirectory('android')
-          .childDirectory('src')
-          .childDirectory('main')
-          .childDirectory('java')
-          .childDirectory('plugin1')
-          .childFile('UseNewEmbedding.java')
-          ..createSync(recursive: true)
-          ..writeAsStringSync(
-            'import io.flutter.embedding.engine.plugins.FlutterPlugin;\n'
-            'PluginRegistry\n'
-            'registerWith(Irrelevant registrar)\n'
-          );
+        createDualSupportJavaPlugin4();
 
-        flutterProject.directory
-          .childFile('.packages')
-          .writeAsStringSync('''
-plugin1:${pluginUsingJavaAndNewEmbeddingDir.childDirectory('lib').uri.toString()}
-''');
         await injectPlugins(flutterProject);
 
         final File registrant = flutterProject.directory
@@ -352,6 +363,8 @@
         expect(registrant.existsSync(), isTrue);
         expect(registrant.readAsStringSync(), contains('package io.flutter.plugins'));
         expect(registrant.readAsStringSync(), contains('class GeneratedPluginRegistrant'));
+        expect(registrant.readAsStringSync(),
+          contains('UseBothEmbedding.registerWith(registry.registrarFor("plugin4.UseBothEmbedding"));'));
       }, overrides: <Type, Generator>{
         FileSystem: () => fs,
         ProcessManager: () => FakeProcessManager.any(),
@@ -359,9 +372,11 @@
         XcodeProjectInterpreter: () => xcodeProjectInterpreter,
       });
 
-      testUsingContext('Registrant doesn\'t use new embedding if app doesn\'t use new embedding', () async {
+      testUsingContext('new embedding app uses a plugin that supports v1 and v2 embedding', () async {
         when(flutterProject.isModule).thenReturn(false);
-        when(androidProject.getEmbeddingVersion()).thenReturn(AndroidEmbeddingVersion.v1);
+        when(androidProject.getEmbeddingVersion()).thenReturn(AndroidEmbeddingVersion.v2);
+
+        createDualSupportJavaPlugin4();
 
         await injectPlugins(flutterProject);
 
@@ -372,32 +387,16 @@
         expect(registrant.existsSync(), isTrue);
         expect(registrant.readAsStringSync(), contains('package io.flutter.plugins'));
         expect(registrant.readAsStringSync(), contains('class GeneratedPluginRegistrant'));
+        expect(registrant.readAsStringSync(),
+          contains('flutterEngine.getPlugins().add(new plugin4.UseBothEmbedding());'));
       }, overrides: <Type, Generator>{
         FileSystem: () => fs,
         ProcessManager: () => FakeProcessManager.any(),
         FeatureFlags: () => featureFlags,
+        XcodeProjectInterpreter: () => xcodeProjectInterpreter,
       });
 
-      testUsingContext('Registrant uses old embedding in module project', () async {
-        when(flutterProject.isModule).thenReturn(true);
-        when(androidProject.getEmbeddingVersion()).thenReturn(AndroidEmbeddingVersion.v1);
-
-        await injectPlugins(flutterProject);
-
-        final File registrant = flutterProject.directory
-          .childDirectory(fs.path.join('android', 'app', 'src', 'main', 'java', 'io', 'flutter', 'plugins'))
-          .childFile('GeneratedPluginRegistrant.java');
-
-        expect(registrant.existsSync(), isTrue);
-        expect(registrant.readAsStringSync(), contains('package io.flutter.plugins'));
-        expect(registrant.readAsStringSync(), contains('class GeneratedPluginRegistrant'));
-      }, overrides: <Type, Generator>{
-        FileSystem: () => fs,
-        ProcessManager: () => FakeProcessManager.any(),
-        FeatureFlags: () => featureFlags,
-      });
-
-      testUsingContext('Registrant uses new embedding if module uses new embedding', () async {
+      testUsingContext('Modules use new embedding', () async {
         when(flutterProject.isModule).thenReturn(true);
         when(androidProject.getEmbeddingVersion()).thenReturn(AndroidEmbeddingVersion.v2);
 
@@ -410,29 +409,76 @@
         expect(registrant.existsSync(), isTrue);
         expect(registrant.readAsStringSync(), contains('package io.flutter.plugins'));
         expect(registrant.readAsStringSync(), contains('class GeneratedPluginRegistrant'));
+        expect(registrant.readAsStringSync(), contains('public static void registerWith(@NonNull FlutterEngine flutterEngine)'));
       }, overrides: <Type, Generator>{
         FileSystem: () => fs,
         ProcessManager: () => FakeProcessManager.any(),
         FeatureFlags: () => featureFlags,
       });
 
-      testUsingContext('Registrant doesn\'t use new embedding if module doesn\'t use new embedding', () async {
+      testUsingContext('Module using old plugin shows warning', () async {
         when(flutterProject.isModule).thenReturn(true);
-        when(androidProject.getEmbeddingVersion()).thenReturn(AndroidEmbeddingVersion.v1);
+        when(androidProject.getEmbeddingVersion()).thenReturn(AndroidEmbeddingVersion.v2);
+
+        createOldJavaPlugin3();
 
         await injectPlugins(flutterProject);
 
         final File registrant = flutterProject.directory
           .childDirectory(fs.path.join('android', 'app', 'src', 'main', 'java', 'io', 'flutter', 'plugins'))
           .childFile('GeneratedPluginRegistrant.java');
-
-        expect(registrant.existsSync(), isTrue);
-        expect(registrant.readAsStringSync(), contains('package io.flutter.plugins'));
-        expect(registrant.readAsStringSync(), contains('class GeneratedPluginRegistrant'));
+        expect(registrant.readAsStringSync(),
+          contains('plugin3.UseOldEmbedding.registerWith(shimPluginRegistry.registrarFor("plugin3.UseOldEmbedding"));'));
+        expect(testLogger.statusText, contains('The plugin `plugin3` is built using an older version of the Android plugin API'));
       }, overrides: <Type, Generator>{
         FileSystem: () => fs,
         ProcessManager: () => FakeProcessManager.any(),
         FeatureFlags: () => featureFlags,
+        XcodeProjectInterpreter: () => xcodeProjectInterpreter,
+      });
+
+      testUsingContext('Module using new plugin shows no warnings', () async {
+        when(flutterProject.isModule).thenReturn(true);
+        when(androidProject.getEmbeddingVersion()).thenReturn(AndroidEmbeddingVersion.v2);
+
+        createNewJavaPlugin1();
+
+        await injectPlugins(flutterProject);
+
+        final File registrant = flutterProject.directory
+          .childDirectory(fs.path.join('android', 'app', 'src', 'main', 'java', 'io', 'flutter', 'plugins'))
+          .childFile('GeneratedPluginRegistrant.java');
+        expect(registrant.readAsStringSync(),
+          contains('flutterEngine.getPlugins().add(new plugin1.UseNewEmbedding());'));
+
+        expect(testLogger.statusText, isNot(contains('go/android-plugin-migration')));
+      }, overrides: <Type, Generator>{
+        FileSystem: () => fs,
+        ProcessManager: () => FakeProcessManager.any(),
+        FeatureFlags: () => featureFlags,
+        XcodeProjectInterpreter: () => xcodeProjectInterpreter,
+      });
+
+      testUsingContext('Module using plugin with v1 and v2 support shows no warning', () async {
+        when(flutterProject.isModule).thenReturn(true);
+        when(androidProject.getEmbeddingVersion()).thenReturn(AndroidEmbeddingVersion.v2);
+
+        createDualSupportJavaPlugin4();
+
+        await injectPlugins(flutterProject);
+
+        final File registrant = flutterProject.directory
+          .childDirectory(fs.path.join('android', 'app', 'src', 'main', 'java', 'io', 'flutter', 'plugins'))
+          .childFile('GeneratedPluginRegistrant.java');
+        expect(registrant.readAsStringSync(),
+          contains('flutterEngine.getPlugins().add(new plugin4.UseBothEmbedding());'));
+
+        expect(testLogger.statusText, isNot(contains('go/android-plugin-migration')));
+      }, overrides: <Type, Generator>{
+        FileSystem: () => fs,
+        ProcessManager: () => FakeProcessManager.any(),
+        FeatureFlags: () => featureFlags,
+        XcodeProjectInterpreter: () => xcodeProjectInterpreter,
       });
 
       testUsingContext('Does not throw when AndroidManifest.xml is not found', () async {