[local_auth] Add native Android implementation of platform interface (#4700)

diff --git a/packages/local_auth/local_auth/pubspec.yaml b/packages/local_auth/local_auth/pubspec.yaml
index dbffb4c..baf5d46 100644
--- a/packages/local_auth/local_auth/pubspec.yaml
+++ b/packages/local_auth/local_auth/pubspec.yaml
@@ -17,8 +17,7 @@
   plugin:
     platforms:
       android:
-        package: io.flutter.plugins.localauth
-        pluginClass: LocalAuthPlugin
+        default_package: local_auth_android
       ios:
         default_package: local_auth_ios
 
@@ -27,7 +26,9 @@
     sdk: flutter
   flutter_plugin_android_lifecycle: ^2.0.1
   intl: ^0.17.0
-  # Temporary path dependencies to allow moving Android and iOS implementations.
+# Temporary path dependencies to allow moving Android and iOS implementations.
+  local_auth_android:
+    path: ../local_auth_android
   local_auth_ios:
     path: ../local_auth_ios
   local_auth_platform_interface: ^1.0.1
diff --git a/packages/local_auth/local_auth_android/AUTHORS b/packages/local_auth/local_auth_android/AUTHORS
new file mode 100644
index 0000000..d569469
--- /dev/null
+++ b/packages/local_auth/local_auth_android/AUTHORS
@@ -0,0 +1,67 @@
+# Below is a list of people and organizations that have contributed
+# to the Flutter project. Names should be added to the list like so:
+#
+#   Name/Organization <email address>
+
+Google Inc.
+The Chromium Authors
+German Saprykin <saprykin.h@gmail.com>
+Benjamin Sauer <sauer.benjamin@gmail.com>
+larsenthomasj@gmail.com
+Ali Bitek <alibitek@protonmail.ch>
+Pol Batlló <pol.batllo@gmail.com>
+Anatoly Pulyaevskiy
+Hayden Flinner <haydenflinner@gmail.com>
+Stefano Rodriguez <hlsroddy@gmail.com>
+Salvatore Giordano <salvatoregiordanoo@gmail.com>
+Brian Armstrong <brian@flutter.institute>
+Paul DeMarco <paulmdemarco@gmail.com>
+Fabricio Nogueira <feufeu@gmail.com>
+Simon Lightfoot <simon@devangels.london>
+Ashton Thomas <ashton@acrinta.com>
+Thomas Danner <thmsdnnr@gmail.com>
+Diego Velásquez <diego.velasquez.lopez@gmail.com>
+Hajime Nakamura <nkmrhj@gmail.com>
+Tuyển Vũ Xuân <netsoft1985@gmail.com>
+Miguel Ruivo <miguel@miguelruivo.com>
+Sarthak Verma <sarthak@artiosys.com>
+Mike Diarmid <mike@invertase.io>
+Invertase <oss@invertase.io>
+Elliot Hesp <elliot@invertase.io>
+Vince Varga <vince.varga@smaho.com>
+Aawaz Gyawali <awazgyawali@gmail.com>
+EUI Limited <ian.evans3@admiralgroup.co.uk>
+Katarina Sheremet <katarina@sheremet.ch>
+Thomas Stockx <thomas@stockxit.com>
+Sarbagya Dhaubanjar <sarbagyastha@gmail.com>
+Ozkan Eksi <ozeksi@gmail.com>
+Rishab Nayak <rishab@bu.edu>
+ko2ic <ko2ic.dev@gmail.com>
+Jonathan Younger <jonathan@daikini.com>
+Jose Sanchez <josesm82@gmail.com>
+Debkanchan Samadder <debu.samadder@gmail.com>
+Audrius Karosevicius <audrius.karosevicius@gmail.com>
+Lukasz Piliszczuk <lukasz@intheloup.io>
+SoundReply Solutions GmbH <ch@soundreply.com>
+Rafal Wachol <rwachol@gmail.com>
+Pau Picas <pau.picas@gmail.com>
+Christian Weder <chrstian.weder@yapeal.ch>
+Alexandru Tuca <salexandru.tuca@outlook.com>
+Christian Weder <chrstian.weder@yapeal.ch>
+Rhodes Davis Jr. <rody.davis.jr@gmail.com>
+Luigi Agosti <luigi@tengio.com>
+Quentin Le Guennec <quentin@tengio.com>
+Koushik Ravikumar <koushik@tengio.com>
+Nissim Dsilva <nissim@tengio.com>
+Giancarlo Rocha <giancarloiff@gmail.com>
+Ryo Miyake <ryo@miyake.id>
+Théo Champion <contact.theochampion@gmail.com>
+Kazuki Yamaguchi <y.kazuki0614n@gmail.com>
+Eitan Schwartz <eshvartz@gmail.com>
+Chris Rutkowski <chrisrutkowski89@gmail.com>
+Juan Alvarez <juan.alvarez@resideo.com>
+Aleksandr Yurkovskiy <sanekyy@gmail.com>
+Anton Borries <mail@antonborri.es>
+Alex Li <google@alexv525.com>
+Rahul Raj <64.rahulraj@gmail.com>
+Bodhi Mulders <info@bemacized.net>
diff --git a/packages/local_auth/local_auth_android/CHANGELOG.md b/packages/local_auth/local_auth_android/CHANGELOG.md
new file mode 100644
index 0000000..7f198f2
--- /dev/null
+++ b/packages/local_auth/local_auth_android/CHANGELOG.md
@@ -0,0 +1,3 @@
+## 1.0.0
+
+* Initial release from migration to federated architecture. 
diff --git a/packages/local_auth/local_auth_android/LICENSE b/packages/local_auth/local_auth_android/LICENSE
new file mode 100644
index 0000000..c6823b8
--- /dev/null
+++ b/packages/local_auth/local_auth_android/LICENSE
@@ -0,0 +1,25 @@
+Copyright 2013 The Flutter Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of Google Inc. nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/packages/local_auth/local_auth_android/README.md b/packages/local_auth/local_auth_android/README.md
new file mode 100644
index 0000000..0724491
--- /dev/null
+++ b/packages/local_auth/local_auth_android/README.md
@@ -0,0 +1,11 @@
+# local\_auth\_android
+
+The Android implementation of [`local_auth`][1].
+
+## Usage
+
+This package is [endorsed][2], which means you can simply use `local_auth`
+normally. This package will be automatically included in your app when you do.
+
+[1]: https://pub.dev/packages/local_auth
+[2]: https://flutter.dev/docs/development/packages-and-plugins/developing-packages#endorsed-federated-plugin
\ No newline at end of file
diff --git a/packages/local_auth/local_auth/android/build.gradle b/packages/local_auth/local_auth_android/android/build.gradle
similarity index 100%
rename from packages/local_auth/local_auth/android/build.gradle
rename to packages/local_auth/local_auth_android/android/build.gradle
diff --git a/packages/local_auth/local_auth/android/lint-baseline.xml b/packages/local_auth/local_auth_android/android/lint-baseline.xml
similarity index 100%
rename from packages/local_auth/local_auth/android/lint-baseline.xml
rename to packages/local_auth/local_auth_android/android/lint-baseline.xml
diff --git a/packages/local_auth/local_auth/android/settings.gradle b/packages/local_auth/local_auth_android/android/settings.gradle
similarity index 100%
rename from packages/local_auth/local_auth/android/settings.gradle
rename to packages/local_auth/local_auth_android/android/settings.gradle
diff --git a/packages/local_auth/local_auth/android/src/main/AndroidManifest.xml b/packages/local_auth/local_auth_android/android/src/main/AndroidManifest.xml
similarity index 100%
rename from packages/local_auth/local_auth/android/src/main/AndroidManifest.xml
rename to packages/local_auth/local_auth_android/android/src/main/AndroidManifest.xml
diff --git a/packages/local_auth/local_auth/android/src/main/java/io/flutter/plugins/localauth/AuthenticationHelper.java b/packages/local_auth/local_auth_android/android/src/main/java/io/flutter/plugins/localauth/AuthenticationHelper.java
similarity index 100%
rename from packages/local_auth/local_auth/android/src/main/java/io/flutter/plugins/localauth/AuthenticationHelper.java
rename to packages/local_auth/local_auth_android/android/src/main/java/io/flutter/plugins/localauth/AuthenticationHelper.java
diff --git a/packages/local_auth/local_auth/android/src/main/java/io/flutter/plugins/localauth/LocalAuthPlugin.java b/packages/local_auth/local_auth_android/android/src/main/java/io/flutter/plugins/localauth/LocalAuthPlugin.java
similarity index 99%
rename from packages/local_auth/local_auth/android/src/main/java/io/flutter/plugins/localauth/LocalAuthPlugin.java
rename to packages/local_auth/local_auth_android/android/src/main/java/io/flutter/plugins/localauth/LocalAuthPlugin.java
index a63e22a..49a6b78 100644
--- a/packages/local_auth/local_auth/android/src/main/java/io/flutter/plugins/localauth/LocalAuthPlugin.java
+++ b/packages/local_auth/local_auth_android/android/src/main/java/io/flutter/plugins/localauth/LocalAuthPlugin.java
@@ -40,7 +40,7 @@
  */
 @SuppressWarnings("deprecation")
 public class LocalAuthPlugin implements MethodCallHandler, FlutterPlugin, ActivityAware {
-  private static final String CHANNEL_NAME = "plugins.flutter.io/local_auth";
+  private static final String CHANNEL_NAME = "plugins.flutter.io/local_auth_android";
   private static final int LOCK_REQUEST_CODE = 221;
   private Activity activity;
   private final AtomicBoolean authInProgress = new AtomicBoolean(false);
diff --git a/packages/local_auth/local_auth/android/src/main/res/drawable/fingerprint_initial_icon.xml b/packages/local_auth/local_auth_android/android/src/main/res/drawable/fingerprint_initial_icon.xml
similarity index 100%
rename from packages/local_auth/local_auth/android/src/main/res/drawable/fingerprint_initial_icon.xml
rename to packages/local_auth/local_auth_android/android/src/main/res/drawable/fingerprint_initial_icon.xml
diff --git a/packages/local_auth/local_auth/android/src/main/res/drawable/fingerprint_success_icon.xml b/packages/local_auth/local_auth_android/android/src/main/res/drawable/fingerprint_success_icon.xml
similarity index 100%
rename from packages/local_auth/local_auth/android/src/main/res/drawable/fingerprint_success_icon.xml
rename to packages/local_auth/local_auth_android/android/src/main/res/drawable/fingerprint_success_icon.xml
diff --git a/packages/local_auth/local_auth/android/src/main/res/drawable/fingerprint_warning_icon.xml b/packages/local_auth/local_auth_android/android/src/main/res/drawable/fingerprint_warning_icon.xml
similarity index 100%
rename from packages/local_auth/local_auth/android/src/main/res/drawable/fingerprint_warning_icon.xml
rename to packages/local_auth/local_auth_android/android/src/main/res/drawable/fingerprint_warning_icon.xml
diff --git a/packages/local_auth/local_auth/android/src/main/res/drawable/ic_done_white_24dp.xml b/packages/local_auth/local_auth_android/android/src/main/res/drawable/ic_done_white_24dp.xml
similarity index 100%
rename from packages/local_auth/local_auth/android/src/main/res/drawable/ic_done_white_24dp.xml
rename to packages/local_auth/local_auth_android/android/src/main/res/drawable/ic_done_white_24dp.xml
diff --git a/packages/local_auth/local_auth/android/src/main/res/drawable/ic_fingerprint_white_24dp.xml b/packages/local_auth/local_auth_android/android/src/main/res/drawable/ic_fingerprint_white_24dp.xml
similarity index 100%
rename from packages/local_auth/local_auth/android/src/main/res/drawable/ic_fingerprint_white_24dp.xml
rename to packages/local_auth/local_auth_android/android/src/main/res/drawable/ic_fingerprint_white_24dp.xml
diff --git a/packages/local_auth/local_auth/android/src/main/res/drawable/ic_priority_high_white_24dp.xml b/packages/local_auth/local_auth_android/android/src/main/res/drawable/ic_priority_high_white_24dp.xml
similarity index 100%
rename from packages/local_auth/local_auth/android/src/main/res/drawable/ic_priority_high_white_24dp.xml
rename to packages/local_auth/local_auth_android/android/src/main/res/drawable/ic_priority_high_white_24dp.xml
diff --git a/packages/local_auth/local_auth/android/src/main/res/layout/go_to_setting.xml b/packages/local_auth/local_auth_android/android/src/main/res/layout/go_to_setting.xml
similarity index 100%
rename from packages/local_auth/local_auth/android/src/main/res/layout/go_to_setting.xml
rename to packages/local_auth/local_auth_android/android/src/main/res/layout/go_to_setting.xml
diff --git a/packages/local_auth/local_auth/android/src/main/res/layout/scan_fp.xml b/packages/local_auth/local_auth_android/android/src/main/res/layout/scan_fp.xml
similarity index 100%
rename from packages/local_auth/local_auth/android/src/main/res/layout/scan_fp.xml
rename to packages/local_auth/local_auth_android/android/src/main/res/layout/scan_fp.xml
diff --git a/packages/local_auth/local_auth/android/src/main/res/values/colors.xml b/packages/local_auth/local_auth_android/android/src/main/res/values/colors.xml
similarity index 100%
rename from packages/local_auth/local_auth/android/src/main/res/values/colors.xml
rename to packages/local_auth/local_auth_android/android/src/main/res/values/colors.xml
diff --git a/packages/local_auth/local_auth/android/src/main/res/values/dimens.xml b/packages/local_auth/local_auth_android/android/src/main/res/values/dimens.xml
similarity index 100%
rename from packages/local_auth/local_auth/android/src/main/res/values/dimens.xml
rename to packages/local_auth/local_auth_android/android/src/main/res/values/dimens.xml
diff --git a/packages/local_auth/local_auth/android/src/main/res/values/styles.xml b/packages/local_auth/local_auth_android/android/src/main/res/values/styles.xml
similarity index 100%
rename from packages/local_auth/local_auth/android/src/main/res/values/styles.xml
rename to packages/local_auth/local_auth_android/android/src/main/res/values/styles.xml
diff --git a/packages/local_auth/local_auth/android/src/test/java/io/flutter/plugins/localauth/LocalAuthTest.java b/packages/local_auth/local_auth_android/android/src/test/java/io/flutter/plugins/localauth/LocalAuthTest.java
similarity index 100%
rename from packages/local_auth/local_auth/android/src/test/java/io/flutter/plugins/localauth/LocalAuthTest.java
rename to packages/local_auth/local_auth_android/android/src/test/java/io/flutter/plugins/localauth/LocalAuthTest.java
diff --git a/packages/local_auth/local_auth_android/example/README.md b/packages/local_auth/local_auth_android/example/README.md
new file mode 100644
index 0000000..a4a6091
--- /dev/null
+++ b/packages/local_auth/local_auth_android/example/README.md
@@ -0,0 +1,8 @@
+# local_auth_example
+
+Demonstrates how to use the local_auth plugin.
+
+## Getting Started
+
+For help getting started with Flutter, view our online
+[documentation](https://flutter.dev/).
diff --git a/packages/local_auth/local_auth_android/example/android/app/build.gradle b/packages/local_auth/local_auth_android/example/android/app/build.gradle
new file mode 100644
index 0000000..d1cef4b
--- /dev/null
+++ b/packages/local_auth/local_auth_android/example/android/app/build.gradle
@@ -0,0 +1,58 @@
+def localProperties = new Properties()
+def localPropertiesFile = rootProject.file('local.properties')
+if (localPropertiesFile.exists()) {
+    localPropertiesFile.withReader('UTF-8') { reader ->
+        localProperties.load(reader)
+    }
+}
+
+def flutterRoot = localProperties.getProperty('flutter.sdk')
+if (flutterRoot == null) {
+    throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
+}
+
+def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
+if (flutterVersionCode == null) {
+    flutterVersionCode = '1'
+}
+
+def flutterVersionName = localProperties.getProperty('flutter.versionName')
+if (flutterVersionName == null) {
+    flutterVersionName = '1.0'
+}
+
+apply plugin: 'com.android.application'
+apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
+
+android {
+    compileSdkVersion 31
+
+    lintOptions {
+        disable 'InvalidPackage'
+    }
+
+    defaultConfig {
+        applicationId "io.flutter.plugins.localauthexample"
+        minSdkVersion 16
+        targetSdkVersion 28
+        versionCode flutterVersionCode.toInteger()
+        versionName flutterVersionName
+        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+    }
+
+    buildTypes {
+        release {
+            signingConfig signingConfigs.debug
+        }
+    }
+}
+
+flutter {
+    source '../..'
+}
+
+dependencies {
+    testImplementation 'junit:junit:4.12'
+    androidTestImplementation 'androidx.test:runner:1.1.1'
+    androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
+}
diff --git a/packages/local_auth/local_auth_android/example/android/app/gradle/wrapper/gradle-wrapper.properties b/packages/local_auth/local_auth_android/example/android/app/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..186b715
--- /dev/null
+++ b/packages/local_auth/local_auth_android/example/android/app/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/packages/local_auth/local_auth_android/example/android/app/src/androidTest/java/io/flutter/plugins/DartIntegrationTest.java b/packages/local_auth/local_auth_android/example/android/app/src/androidTest/java/io/flutter/plugins/DartIntegrationTest.java
new file mode 100644
index 0000000..0f4298d
--- /dev/null
+++ b/packages/local_auth/local_auth_android/example/android/app/src/androidTest/java/io/flutter/plugins/DartIntegrationTest.java
@@ -0,0 +1,14 @@
+// Copyright 2013 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.
+
+package io.flutter.plugins;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface DartIntegrationTest {}
diff --git a/packages/local_auth/local_auth_android/example/android/app/src/androidTest/java/io/flutter/plugins/localauth/FlutterFragmentActivityTest.java b/packages/local_auth/local_auth_android/example/android/app/src/androidTest/java/io/flutter/plugins/localauth/FlutterFragmentActivityTest.java
new file mode 100644
index 0000000..68c2237
--- /dev/null
+++ b/packages/local_auth/local_auth_android/example/android/app/src/androidTest/java/io/flutter/plugins/localauth/FlutterFragmentActivityTest.java
@@ -0,0 +1,20 @@
+// Copyright 2013 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.
+
+package io.flutter.plugins.localauth;
+
+import androidx.test.rule.ActivityTestRule;
+import dev.flutter.plugins.integration_test.FlutterTestRunner;
+import io.flutter.embedding.android.FlutterFragmentActivity;
+import io.flutter.plugins.DartIntegrationTest;
+import org.junit.Rule;
+import org.junit.runner.RunWith;
+
+@DartIntegrationTest
+@RunWith(FlutterTestRunner.class)
+public class FlutterFragmentActivityTest {
+  @Rule
+  public ActivityTestRule<FlutterFragmentActivity> rule =
+      new ActivityTestRule<>(FlutterFragmentActivity.class);
+}
diff --git a/packages/local_auth/local_auth_android/example/android/app/src/main/AndroidManifest.xml b/packages/local_auth/local_auth_android/example/android/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..8c09177
--- /dev/null
+++ b/packages/local_auth/local_auth_android/example/android/app/src/main/AndroidManifest.xml
@@ -0,0 +1,21 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="io.flutter.plugins.localauthexample">
+
+    <uses-permission android:name="android.permission.INTERNET"/>
+    <uses-permission android:name="android.permission.USE_FINGERPRINT"/>
+
+    <application android:label="local_auth_example" android:icon="@mipmap/ic_launcher">
+        <activity android:name="io.flutter.embedding.android.FlutterFragmentActivity"
+                  android:launchMode="singleTop"
+                  android:theme="@style/Theme.AppCompat.Light"
+                  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"/>
+            </intent-filter>
+        </activity>
+        <meta-data android:name="flutterEmbedding" android:value="2"/>
+    </application>
+</manifest>
diff --git a/packages/local_auth/local_auth_android/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/packages/local_auth/local_auth_android/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..db77bb4
--- /dev/null
+++ b/packages/local_auth/local_auth_android/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/packages/local_auth/local_auth_android/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/packages/local_auth/local_auth_android/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..17987b7
--- /dev/null
+++ b/packages/local_auth/local_auth_android/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/packages/local_auth/local_auth_android/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/packages/local_auth/local_auth_android/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..09d4391
--- /dev/null
+++ b/packages/local_auth/local_auth_android/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/packages/local_auth/local_auth_android/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/packages/local_auth/local_auth_android/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..d5f1c8d
--- /dev/null
+++ b/packages/local_auth/local_auth_android/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/packages/local_auth/local_auth_android/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/packages/local_auth/local_auth_android/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..4d6372e
--- /dev/null
+++ b/packages/local_auth/local_auth_android/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/packages/local_auth/local_auth_android/example/android/build.gradle b/packages/local_auth/local_auth_android/example/android/build.gradle
new file mode 100644
index 0000000..54c9436
--- /dev/null
+++ b/packages/local_auth/local_auth_android/example/android/build.gradle
@@ -0,0 +1,29 @@
+buildscript {
+    repositories {
+        google()
+        mavenCentral()
+    }
+
+    dependencies {
+        classpath 'com.android.tools.build:gradle:4.1.1'
+    }
+}
+
+allprojects {
+    repositories {
+        google()
+        mavenCentral()
+    }
+}
+
+rootProject.buildDir = '../build'
+subprojects {
+    project.buildDir = "${rootProject.buildDir}/${project.name}"
+}
+subprojects {
+    project.evaluationDependsOn(':app')
+}
+
+task clean(type: Delete) {
+    delete rootProject.buildDir
+}
diff --git a/packages/local_auth/local_auth_android/example/android/gradle.properties b/packages/local_auth/local_auth_android/example/android/gradle.properties
new file mode 100644
index 0000000..7fe61a7
--- /dev/null
+++ b/packages/local_auth/local_auth_android/example/android/gradle.properties
@@ -0,0 +1,4 @@
+org.gradle.jvmargs=-Xmx1024m
+android.useAndroidX=true
+android.enableJetifier=true
+android.enableR8=true
diff --git a/packages/local_auth/local_auth_android/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/local_auth/local_auth_android/example/android/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..cd9fe1c
--- /dev/null
+++ b/packages/local_auth/local_auth_android/example/android/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Sun Jan 03 14:07:08 CST 2021
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip
diff --git a/packages/local_auth/local_auth_android/example/android/settings.gradle b/packages/local_auth/local_auth_android/example/android/settings.gradle
new file mode 100644
index 0000000..115da6c
--- /dev/null
+++ b/packages/local_auth/local_auth_android/example/android/settings.gradle
@@ -0,0 +1,15 @@
+include ':app'
+
+def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
+
+def plugins = new Properties()
+def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
+if (pluginsFile.exists()) {
+    pluginsFile.withInputStream { stream -> plugins.load(stream) }
+}
+
+plugins.each { name, path ->
+    def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
+    include ":$name"
+    project(":$name").projectDir = pluginDirectory
+}
diff --git a/packages/local_auth/local_auth_android/example/android/settings_aar.gradle b/packages/local_auth/local_auth_android/example/android/settings_aar.gradle
new file mode 100644
index 0000000..e7b4def
--- /dev/null
+++ b/packages/local_auth/local_auth_android/example/android/settings_aar.gradle
@@ -0,0 +1 @@
+include ':app'
diff --git a/packages/local_auth/local_auth_android/example/integration_test/local_auth_test.dart b/packages/local_auth/local_auth_android/example/integration_test/local_auth_test.dart
new file mode 100644
index 0000000..1dfc0ae
--- /dev/null
+++ b/packages/local_auth/local_auth_android/example/integration_test/local_auth_test.dart
@@ -0,0 +1,19 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:flutter_test/flutter_test.dart';
+import 'package:integration_test/integration_test.dart';
+
+import 'package:local_auth_android/local_auth_android.dart';
+
+void main() {
+  IntegrationTestWidgetsFlutterBinding.ensureInitialized();
+
+  testWidgets('canCheckBiometrics', (WidgetTester tester) async {
+    expect(
+      LocalAuthAndroid().getEnrolledBiometrics(),
+      completion(isList),
+    );
+  });
+}
diff --git a/packages/local_auth/local_auth_android/example/lib/main.dart b/packages/local_auth/local_auth_android/example/lib/main.dart
new file mode 100644
index 0000000..4c04521
--- /dev/null
+++ b/packages/local_auth/local_auth_android/example/lib/main.dart
@@ -0,0 +1,238 @@
+// Copyright 2013 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.
+
+// ignore_for_file: public_member_api_docs
+
+import 'dart:async';
+
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:local_auth_android/local_auth_android.dart';
+import 'package:local_auth_platform_interface/local_auth_platform_interface.dart';
+
+void main() {
+  runApp(MyApp());
+}
+
+class MyApp extends StatefulWidget {
+  @override
+  _MyAppState createState() => _MyAppState();
+}
+
+class _MyAppState extends State<MyApp> {
+  _SupportState _supportState = _SupportState.unknown;
+  bool? _canCheckBiometrics;
+  List<BiometricType>? _availableBiometrics;
+  String _authorized = 'Not Authorized';
+  bool _isAuthenticating = false;
+
+  @override
+  void initState() {
+    super.initState();
+    LocalAuthPlatform.instance.isDeviceSupported().then(
+          (bool isSupported) => setState(() => _supportState = isSupported
+              ? _SupportState.supported
+              : _SupportState.unsupported),
+        );
+  }
+
+  Future<void> _checkBiometrics() async {
+    late bool canCheckBiometrics;
+    try {
+      canCheckBiometrics =
+          (await LocalAuthPlatform.instance.getEnrolledBiometrics()).isNotEmpty;
+    } on PlatformException catch (e) {
+      canCheckBiometrics = false;
+      print(e);
+    }
+    if (!mounted) {
+      return;
+    }
+
+    setState(() {
+      _canCheckBiometrics = canCheckBiometrics;
+    });
+  }
+
+  Future<void> _getEnrolledBiometrics() async {
+    late List<BiometricType> availableBiometrics;
+    try {
+      availableBiometrics =
+          await LocalAuthPlatform.instance.getEnrolledBiometrics();
+    } on PlatformException catch (e) {
+      availableBiometrics = <BiometricType>[];
+      print(e);
+    }
+    if (!mounted) {
+      return;
+    }
+
+    setState(() {
+      _availableBiometrics = availableBiometrics;
+    });
+  }
+
+  Future<void> _authenticate() async {
+    bool authenticated = false;
+    try {
+      setState(() {
+        _isAuthenticating = true;
+        _authorized = 'Authenticating';
+      });
+      authenticated = await LocalAuthPlatform.instance.authenticate(
+        localizedReason: 'Let OS determine authentication method',
+        authMessages: <AuthMessages>[const AndroidAuthMessages()],
+        options: const AuthenticationOptions(
+          useErrorDialogs: true,
+          stickyAuth: true,
+        ),
+      );
+      setState(() {
+        _isAuthenticating = false;
+      });
+    } on PlatformException catch (e) {
+      print(e);
+      setState(() {
+        _isAuthenticating = false;
+        _authorized = 'Error - ${e.message}';
+      });
+      return;
+    }
+    if (!mounted) {
+      return;
+    }
+
+    setState(
+        () => _authorized = authenticated ? 'Authorized' : 'Not Authorized');
+  }
+
+  Future<void> _authenticateWithBiometrics() async {
+    bool authenticated = false;
+    try {
+      setState(() {
+        _isAuthenticating = true;
+        _authorized = 'Authenticating';
+      });
+      authenticated = await LocalAuthPlatform.instance.authenticate(
+        localizedReason:
+            'Scan your fingerprint (or face or whatever) to authenticate',
+        authMessages: <AuthMessages>[const AndroidAuthMessages()],
+        options: const AuthenticationOptions(
+          useErrorDialogs: true,
+          stickyAuth: true,
+          biometricOnly: true,
+        ),
+      );
+      setState(() {
+        _isAuthenticating = false;
+        _authorized = 'Authenticating';
+      });
+    } on PlatformException catch (e) {
+      print(e);
+      setState(() {
+        _isAuthenticating = false;
+        _authorized = 'Error - ${e.message}';
+      });
+      return;
+    }
+    if (!mounted) {
+      return;
+    }
+
+    final String message = authenticated ? 'Authorized' : 'Not Authorized';
+    setState(() {
+      _authorized = message;
+    });
+  }
+
+  Future<void> _cancelAuthentication() async {
+    await LocalAuthPlatform.instance.stopAuthentication();
+    setState(() => _isAuthenticating = false);
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return MaterialApp(
+      home: Scaffold(
+        appBar: AppBar(
+          title: const Text('Plugin example app'),
+        ),
+        body: ListView(
+          padding: const EdgeInsets.only(top: 30),
+          children: <Widget>[
+            Column(
+              mainAxisAlignment: MainAxisAlignment.center,
+              children: <Widget>[
+                if (_supportState == _SupportState.unknown)
+                  const CircularProgressIndicator()
+                else if (_supportState == _SupportState.supported)
+                  const Text('This device is supported')
+                else
+                  const Text('This device is not supported'),
+                const Divider(height: 100),
+                Text('Can check biometrics: $_canCheckBiometrics\n'),
+                ElevatedButton(
+                  child: const Text('Check biometrics'),
+                  onPressed: _checkBiometrics,
+                ),
+                const Divider(height: 100),
+                Text('Available biometrics: $_availableBiometrics\n'),
+                ElevatedButton(
+                  child: const Text('Get available biometrics'),
+                  onPressed: _getEnrolledBiometrics,
+                ),
+                const Divider(height: 100),
+                Text('Current State: $_authorized\n'),
+                if (_isAuthenticating)
+                  ElevatedButton(
+                    onPressed: _cancelAuthentication,
+                    child: Row(
+                      mainAxisSize: MainAxisSize.min,
+                      children: const <Widget>[
+                        Text('Cancel Authentication'),
+                        Icon(Icons.cancel),
+                      ],
+                    ),
+                  )
+                else
+                  Column(
+                    children: <Widget>[
+                      ElevatedButton(
+                        child: Row(
+                          mainAxisSize: MainAxisSize.min,
+                          children: const <Widget>[
+                            Text('Authenticate'),
+                            Icon(Icons.perm_device_information),
+                          ],
+                        ),
+                        onPressed: _authenticate,
+                      ),
+                      ElevatedButton(
+                        child: Row(
+                          mainAxisSize: MainAxisSize.min,
+                          children: <Widget>[
+                            Text(_isAuthenticating
+                                ? 'Cancel'
+                                : 'Authenticate: biometrics only'),
+                            const Icon(Icons.fingerprint),
+                          ],
+                        ),
+                        onPressed: _authenticateWithBiometrics,
+                      ),
+                    ],
+                  ),
+              ],
+            ),
+          ],
+        ),
+      ),
+    );
+  }
+}
+
+enum _SupportState {
+  unknown,
+  supported,
+  unsupported,
+}
diff --git a/packages/local_auth/local_auth_android/example/pubspec.yaml b/packages/local_auth/local_auth_android/example/pubspec.yaml
new file mode 100644
index 0000000..c07a81d
--- /dev/null
+++ b/packages/local_auth/local_auth_android/example/pubspec.yaml
@@ -0,0 +1,28 @@
+name: local_auth_android_example
+description: Demonstrates how to use the local_auth_android plugin.
+publish_to: none
+
+environment:
+  sdk: ">=2.14.0 <3.0.0"
+  flutter: ">=2.8.0"
+
+dependencies:
+  flutter:
+    sdk: flutter
+  local_auth_android:
+    # When depending on this package from a real application you should use:
+    #   local_auth_android: ^x.y.z
+    # See https://dart.dev/tools/pub/dependencies#version-constraints
+    # The example app is bundled with the plugin so we use a path dependency on
+    # the parent directory to use the current plugin's version.
+    path: ../
+  local_auth_platform_interface: ^1.0.0
+
+dev_dependencies:
+  flutter_driver:
+    sdk: flutter
+  integration_test:
+    sdk: flutter
+
+flutter:
+  uses-material-design: true
diff --git a/packages/local_auth/local_auth_android/example/test_driver/integration_test.dart b/packages/local_auth/local_auth_android/example/test_driver/integration_test.dart
new file mode 100644
index 0000000..4f10f2a
--- /dev/null
+++ b/packages/local_auth/local_auth_android/example/test_driver/integration_test.dart
@@ -0,0 +1,7 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:integration_test/integration_test_driver.dart';
+
+Future<void> main() => integrationDriver();
diff --git a/packages/local_auth/local_auth_android/lib/local_auth_android.dart b/packages/local_auth/local_auth_android/lib/local_auth_android.dart
new file mode 100644
index 0000000..a3f314e
--- /dev/null
+++ b/packages/local_auth/local_auth_android/lib/local_auth_android.dart
@@ -0,0 +1,87 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:flutter/services.dart';
+import 'package:local_auth_android/types/auth_messages_android.dart';
+import 'package:local_auth_platform_interface/local_auth_platform_interface.dart';
+import 'package:local_auth_platform_interface/types/auth_messages.dart';
+import 'package:local_auth_platform_interface/types/auth_options.dart';
+import 'package:local_auth_platform_interface/types/biometric_type.dart';
+
+export 'package:local_auth_android/types/auth_messages_android.dart';
+export 'package:local_auth_platform_interface/types/auth_messages.dart';
+export 'package:local_auth_platform_interface/types/auth_options.dart';
+export 'package:local_auth_platform_interface/types/biometric_type.dart';
+
+const MethodChannel _channel =
+    MethodChannel('plugins.flutter.io/local_auth_android');
+
+/// The implementation of [LocalAuthPlatform] for Android.
+class LocalAuthAndroid extends LocalAuthPlatform {
+  /// Registers this class as the default instance of [LocalAuthPlatform].
+  static void registerWith() {
+    LocalAuthPlatform.instance = LocalAuthAndroid();
+  }
+
+  @override
+  Future<bool> authenticate({
+    required String localizedReason,
+    required Iterable<AuthMessages> authMessages,
+    AuthenticationOptions options = const AuthenticationOptions(),
+  }) async {
+    assert(localizedReason.isNotEmpty);
+    final Map<String, Object> args = <String, Object>{
+      'localizedReason': localizedReason,
+      'useErrorDialogs': options.useErrorDialogs,
+      'stickyAuth': options.stickyAuth,
+      'sensitiveTransaction': options.sensitiveTransaction,
+      'biometricOnly': options.biometricOnly,
+    };
+    args.addAll(const AndroidAuthMessages().args);
+    for (final AuthMessages messages in authMessages) {
+      if (messages is AndroidAuthMessages) {
+        args.addAll(messages.args);
+      }
+    }
+    return (await _channel.invokeMethod<bool>('authenticate', args)) ?? false;
+  }
+
+  @override
+  Future<bool> deviceSupportsBiometrics() async {
+    return (await getEnrolledBiometrics()).isNotEmpty;
+  }
+
+  @override
+  Future<List<BiometricType>> getEnrolledBiometrics() async {
+    final List<String> result = (await _channel.invokeListMethod<String>(
+          'getAvailableBiometrics',
+        )) ??
+        <String>[];
+    final List<BiometricType> biometrics = <BiometricType>[];
+    for (final String value in result) {
+      switch (value) {
+        case 'face':
+          biometrics.add(BiometricType.face);
+          break;
+        case 'fingerprint':
+          biometrics.add(BiometricType.fingerprint);
+          break;
+        case 'iris':
+          biometrics.add(BiometricType.iris);
+          break;
+        case 'undefined':
+          break;
+      }
+    }
+    return biometrics;
+  }
+
+  @override
+  Future<bool> isDeviceSupported() async =>
+      (await _channel.invokeMethod<bool>('isDeviceSupported')) ?? false;
+
+  @override
+  Future<bool> stopAuthentication() async =>
+      await _channel.invokeMethod<bool>('stopAuthentication') ?? false;
+}
diff --git a/packages/local_auth/local_auth_android/lib/types/auth_messages_android.dart b/packages/local_auth/local_auth_android/lib/types/auth_messages_android.dart
new file mode 100644
index 0000000..ea61a4b
--- /dev/null
+++ b/packages/local_auth/local_auth_android/lib/types/auth_messages_android.dart
@@ -0,0 +1,191 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:flutter/foundation.dart';
+import 'package:intl/intl.dart';
+import 'package:local_auth_platform_interface/types/auth_messages.dart';
+
+/// Android side authentication messages.
+///
+/// Provides default values for all messages.
+@immutable
+class AndroidAuthMessages extends AuthMessages {
+  /// Constructs a new instance.
+  const AndroidAuthMessages({
+    this.biometricHint,
+    this.biometricNotRecognized,
+    this.biometricRequiredTitle,
+    this.biometricSuccess,
+    this.cancelButton,
+    this.deviceCredentialsRequiredTitle,
+    this.deviceCredentialsSetupDescription,
+    this.goToSettingsButton,
+    this.goToSettingsDescription,
+    this.signInTitle,
+  });
+
+  /// Hint message advising the user how to authenticate with biometrics.
+  /// Maximum 60 characters.
+  final String? biometricHint;
+
+  /// Message to let the user know that authentication was failed.
+  /// Maximum 60 characters.
+  final String? biometricNotRecognized;
+
+  /// Message shown as a title in a dialog which indicates the user
+  /// has not set up biometric authentication on their device.
+  /// Maximum 60 characters.
+  final String? biometricRequiredTitle;
+
+  /// Message to let the user know that authentication was successful.
+  /// Maximum 60 characters
+  final String? biometricSuccess;
+
+  /// Message shown on a button that the user can click to leave the
+  /// current dialog.
+  /// Maximum 30 characters.
+  final String? cancelButton;
+
+  /// Message shown as a title in a dialog which indicates the user
+  /// has not set up credentials authentication on their device.
+  /// Maximum 60 characters.
+  final String? deviceCredentialsRequiredTitle;
+
+  /// Message advising the user to go to the settings and configure
+  /// device credentials on their device.
+  final String? deviceCredentialsSetupDescription;
+
+  /// Message shown on a button that the user can click to go to settings pages
+  /// from the current dialog.
+  /// Maximum 30 characters.
+  final String? goToSettingsButton;
+
+  /// Message advising the user to go to the settings and configure
+  /// biometric on their device.
+  final String? goToSettingsDescription;
+
+  /// Message shown as a title in a dialog which indicates the user
+  /// that they need to scan biometric to continue.
+  /// Maximum 60 characters.
+  final String? signInTitle;
+
+  @override
+  Map<String, String> get args {
+    return <String, String>{
+      'biometricHint': biometricHint ?? androidBiometricHint,
+      'biometricNotRecognized':
+          biometricNotRecognized ?? androidBiometricNotRecognized,
+      'biometricSuccess': biometricSuccess ?? androidBiometricSuccess,
+      'biometricRequired':
+          biometricRequiredTitle ?? androidBiometricRequiredTitle,
+      'cancelButton': cancelButton ?? androidCancelButton,
+      'deviceCredentialsRequired': deviceCredentialsRequiredTitle ??
+          androidDeviceCredentialsRequiredTitle,
+      'deviceCredentialsSetupDescription': deviceCredentialsSetupDescription ??
+          androidDeviceCredentialsSetupDescription,
+      'goToSetting': goToSettingsButton ?? goToSettings,
+      'goToSettingDescription':
+          goToSettingsDescription ?? androidGoToSettingsDescription,
+      'signInTitle': signInTitle ?? androidSignInTitle,
+    };
+  }
+
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) ||
+      other is AndroidAuthMessages &&
+          runtimeType == other.runtimeType &&
+          biometricHint == other.biometricHint &&
+          biometricNotRecognized == other.biometricNotRecognized &&
+          biometricRequiredTitle == other.biometricRequiredTitle &&
+          biometricSuccess == other.biometricSuccess &&
+          cancelButton == other.cancelButton &&
+          deviceCredentialsRequiredTitle ==
+              other.deviceCredentialsRequiredTitle &&
+          deviceCredentialsSetupDescription ==
+              other.deviceCredentialsSetupDescription &&
+          goToSettingsButton == other.goToSettingsButton &&
+          goToSettingsDescription == other.goToSettingsDescription &&
+          signInTitle == other.signInTitle;
+
+  @override
+  int get hashCode =>
+      biometricHint.hashCode ^
+      biometricNotRecognized.hashCode ^
+      biometricRequiredTitle.hashCode ^
+      biometricSuccess.hashCode ^
+      cancelButton.hashCode ^
+      deviceCredentialsRequiredTitle.hashCode ^
+      deviceCredentialsSetupDescription.hashCode ^
+      goToSettingsButton.hashCode ^
+      goToSettingsDescription.hashCode ^
+      signInTitle.hashCode;
+}
+
+// Default strings for AndroidAuthMessages. Currently supports English.
+// Intl.message must be string literals.
+
+/// Message shown on a button that the user can click to go to settings pages
+/// from the current dialog.
+String get goToSettings => Intl.message('Go to settings',
+    desc: 'Message shown on a button that the user can click to go to '
+        'settings pages from the current dialog. Maximum 30 characters.');
+
+/// Hint message advising the user how to authenticate with biometrics.
+String get androidBiometricHint => Intl.message('Verify identity',
+    desc: 'Hint message advising the user how to authenticate with biometrics. '
+        'Maximum 60 characters.');
+
+/// Message to let the user know that authentication was failed.
+String get androidBiometricNotRecognized =>
+    Intl.message('Not recognized. Try again.',
+        desc: 'Message to let the user know that authentication was failed. '
+            'Maximum 60 characters.');
+
+/// Message to let the user know that authentication was successful. It
+String get androidBiometricSuccess => Intl.message('Success',
+    desc: 'Message to let the user know that authentication was successful. '
+        'Maximum 60 characters.');
+
+/// Message shown on a button that the user can click to leave the
+/// current dialog.
+String get androidCancelButton => Intl.message('Cancel',
+    desc: 'Message shown on a button that the user can click to leave the '
+        'current dialog. Maximum 30 characters.');
+
+/// Message shown as a title in a dialog which indicates the user
+/// that they need to scan biometric to continue.
+String get androidSignInTitle => Intl.message('Authentication required',
+    desc: 'Message shown as a title in a dialog which indicates the user '
+        'that they need to scan biometric to continue. Maximum 60 characters.');
+
+/// Message shown as a title in a dialog which indicates the user
+/// has not set up biometric authentication on their device.
+String get androidBiometricRequiredTitle => Intl.message('Biometric required',
+    desc: 'Message shown as a title in a dialog which indicates the user '
+        'has not set up biometric authentication on their device. '
+        'Maximum 60 characters.');
+
+/// Message shown as a title in a dialog which indicates the user
+/// has not set up credentials authentication on their device.
+String get androidDeviceCredentialsRequiredTitle =>
+    Intl.message('Device credentials required',
+        desc: 'Message shown as a title in a dialog which indicates the user '
+            'has not set up credentials authentication on their device. '
+            'Maximum 60 characters.');
+
+/// Message advising the user to go to the settings and configure
+/// device credentials on their device.
+String get androidDeviceCredentialsSetupDescription =>
+    Intl.message('Device credentials required',
+        desc: 'Message advising the user to go to the settings and configure '
+            'device credentials on their device.');
+
+/// Message advising the user to go to the settings and configure
+/// biometric on their device.
+String get androidGoToSettingsDescription => Intl.message(
+    'Biometric authentication is not set up on your device. Go to '
+    '\'Settings > Security\' to add biometric authentication.',
+    desc: 'Message advising the user to go to the settings and configure '
+        'biometric on their device.');
diff --git a/packages/local_auth/local_auth_android/pubspec.yaml b/packages/local_auth/local_auth_android/pubspec.yaml
new file mode 100644
index 0000000..ec2991d
--- /dev/null
+++ b/packages/local_auth/local_auth_android/pubspec.yaml
@@ -0,0 +1,29 @@
+name: local_auth_android
+description: Android implementation of the local_auth plugin.
+repository: https://github.com/flutter/plugins/tree/master/packages/local_auth/local_auth_android
+issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+local_auth%22
+version: 1.0.0
+
+environment:
+  sdk: ">=2.14.0 <3.0.0"
+  flutter: ">=2.8.0"
+
+flutter:
+  plugin:
+    implements: local_auth
+    platforms:
+      android:
+        package: io.flutter.plugins.localauth
+        pluginClass: LocalAuthPlugin
+        dartPluginClass: LocalAuthAndroid
+
+dependencies:
+  flutter:
+    sdk: flutter
+  flutter_plugin_android_lifecycle: ^2.0.1
+  intl: ^0.17.0
+  local_auth_platform_interface: ^1.0.0
+
+dev_dependencies:
+  flutter_test:
+    sdk: flutter
\ No newline at end of file
diff --git a/packages/local_auth/local_auth_android/test/local_auth_test.dart b/packages/local_auth/local_auth_android/test/local_auth_test.dart
new file mode 100644
index 0000000..31f5e57
--- /dev/null
+++ b/packages/local_auth/local_auth_android/test/local_auth_test.dart
@@ -0,0 +1,181 @@
+// Copyright 2013 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_android/local_auth_android.dart';
+import 'package:local_auth_platform_interface/types/auth_messages.dart';
+
+void main() {
+  TestWidgetsFlutterBinding.ensureInitialized();
+
+  group('LocalAuth', () {
+    const MethodChannel channel = MethodChannel(
+      'plugins.flutter.io/local_auth_android',
+    );
+
+    final List<MethodCall> log = <MethodCall>[];
+    late LocalAuthAndroid localAuthentication;
+
+    setUp(() {
+      channel.setMockMethodCallHandler((MethodCall methodCall) {
+        log.add(methodCall);
+        switch (methodCall.method) {
+          case 'getAvailableBiometrics':
+            return Future<List<String>>.value(
+                <String>['face', 'fingerprint', 'iris', 'undefined']);
+          default:
+            return Future<dynamic>.value(true);
+        }
+      });
+      localAuthentication = LocalAuthAndroid();
+      log.clear();
+    });
+
+    test('deviceSupportsBiometrics calls getEnrolledBiometrics', () async {
+      final bool result = await localAuthentication.deviceSupportsBiometrics();
+
+      expect(
+        log,
+        <Matcher>[
+          isMethodCall('getAvailableBiometrics', arguments: null),
+        ],
+      );
+      expect(result, true);
+    });
+
+    test('getEnrolledBiometrics calls platform', () async {
+      final List<BiometricType> result =
+          await localAuthentication.getEnrolledBiometrics();
+
+      expect(
+        log,
+        <Matcher>[
+          isMethodCall('getAvailableBiometrics', arguments: null),
+        ],
+      );
+      expect(result, <BiometricType>[
+        BiometricType.face,
+        BiometricType.fingerprint,
+        BiometricType.iris
+      ]);
+    });
+
+    test('isDeviceSupported calls platform', () async {
+      await localAuthentication.isDeviceSupported();
+      expect(
+        log,
+        <Matcher>[
+          isMethodCall('isDeviceSupported', arguments: null),
+        ],
+      );
+    });
+
+    test('stopAuthentication calls platform', () async {
+      await localAuthentication.stopAuthentication();
+      expect(
+        log,
+        <Matcher>[
+          isMethodCall('stopAuthentication', arguments: null),
+        ],
+      );
+    });
+
+    group('With device auth fail over', () {
+      test('authenticate with no args.', () async {
+        await localAuthentication.authenticate(
+          authMessages: <AuthMessages>[const AndroidAuthMessages()],
+          localizedReason: 'Needs secure',
+          options: const AuthenticationOptions(biometricOnly: true),
+        );
+        expect(
+          log,
+          <Matcher>[
+            isMethodCall('authenticate',
+                arguments: <String, dynamic>{
+                  'localizedReason': 'Needs secure',
+                  'useErrorDialogs': true,
+                  'stickyAuth': false,
+                  'sensitiveTransaction': true,
+                  'biometricOnly': true,
+                }..addAll(const AndroidAuthMessages().args)),
+          ],
+        );
+      });
+
+      test('authenticate with no sensitive transaction.', () async {
+        await localAuthentication.authenticate(
+          authMessages: <AuthMessages>[const AndroidAuthMessages()],
+          localizedReason: 'Insecure',
+          options: const AuthenticationOptions(
+            sensitiveTransaction: false,
+            useErrorDialogs: false,
+            biometricOnly: true,
+          ),
+        );
+        expect(
+          log,
+          <Matcher>[
+            isMethodCall('authenticate',
+                arguments: <String, dynamic>{
+                  'localizedReason': 'Insecure',
+                  'useErrorDialogs': false,
+                  'stickyAuth': false,
+                  'sensitiveTransaction': false,
+                  'biometricOnly': true,
+                }..addAll(const AndroidAuthMessages().args)),
+          ],
+        );
+      });
+    });
+
+    group('With biometrics only', () {
+      test('authenticate with no args.', () async {
+        await localAuthentication.authenticate(
+          authMessages: <AuthMessages>[const AndroidAuthMessages()],
+          localizedReason: 'Needs secure',
+        );
+        expect(
+          log,
+          <Matcher>[
+            isMethodCall('authenticate',
+                arguments: <String, dynamic>{
+                  'localizedReason': 'Needs secure',
+                  'useErrorDialogs': true,
+                  'stickyAuth': false,
+                  'sensitiveTransaction': true,
+                  'biometricOnly': false,
+                }..addAll(const AndroidAuthMessages().args)),
+          ],
+        );
+      });
+
+      test('authenticate with no sensitive transaction.', () async {
+        await localAuthentication.authenticate(
+          authMessages: <AuthMessages>[const AndroidAuthMessages()],
+          localizedReason: 'Insecure',
+          options: const AuthenticationOptions(
+            sensitiveTransaction: false,
+            useErrorDialogs: false,
+          ),
+        );
+        expect(
+          log,
+          <Matcher>[
+            isMethodCall('authenticate',
+                arguments: <String, dynamic>{
+                  'localizedReason': 'Insecure',
+                  'useErrorDialogs': false,
+                  'stickyAuth': false,
+                  'sensitiveTransaction': false,
+                  'biometricOnly': false,
+                }..addAll(const AndroidAuthMessages().args)),
+          ],
+        );
+      });
+    });
+  });
+}