[jnigen] Add ability to use source dependencies from Gradle (https://github.com/dart-lang/jnigen/issues/231)

* Add google maven repository to maven
* add_gradle_sources option
* Add proguard rules and EmojiConfig usage in example
diff --git a/pkgs/jnigen/example/in_app_java/android/app/build.gradle b/pkgs/jnigen/example/in_app_java/android/app/build.gradle
index bd28789..8f38e43 100644
--- a/pkgs/jnigen/example/in_app_java/android/app/build.gradle
+++ b/pkgs/jnigen/example/in_app_java/android/app/build.gradle
@@ -74,4 +74,9 @@
 
 dependencies {
     implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
+
+    /// Add AndroidX emoji2 library as dependency.
+    /// We will be using EmojiCompat's GlyphChecker in our flutter example.
+    def emoji2_version = "1.3.0"
+    implementation "androidx.emoji2:emoji2:$emoji2_version"
 }
diff --git a/pkgs/jnigen/example/in_app_java/android/app/proguard-rules.pro b/pkgs/jnigen/example/in_app_java/android/app/proguard-rules.pro
new file mode 100644
index 0000000..8eecc4c
--- /dev/null
+++ b/pkgs/jnigen/example/in_app_java/android/app/proguard-rules.pro
@@ -0,0 +1,17 @@
+# This is the rules file which prevents `proguard` from aggressively
+# removing the classes which appear to be unused, in release mode.
+#
+# Since JNI is based on runtime lookup for classes, proguard will not have
+# a way to know EmojiCompat class in our example is actually used. Therefore
+# we have to explicitly list it in this file to prevent the application from
+# crashing with ClassNotFoundException.
+#
+# This doesn't apply to builtin classes, eg: those in `android.` namespace Since
+# they are already present on the device.
+# For the Java code which is written by yourself, you can add `androidx.annotation.Keep`
+# instead. (As done in `AndroidUtils.java`).
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+-keep class androidx.emoji2.text.EmojiCompat { public *; }
diff --git a/pkgs/jnigen/example/in_app_java/jnigen.yaml b/pkgs/jnigen/example/in_app_java/jnigen.yaml
index f77215b..f053698 100644
--- a/pkgs/jnigen/example/in_app_java/jnigen.yaml
+++ b/pkgs/jnigen/example/in_app_java/jnigen.yaml
@@ -1,5 +1,6 @@
 android_sdk_config:
   add_gradle_deps: true
+  add_gradle_sources: true
 
 output:
   c:
@@ -13,5 +14,7 @@
   - 'android/app/src/main/java'
 classes:
   - 'com.example.in_app_java.AndroidUtils' # from source_path
+  - 'androidx.emoji2.text.EmojiCompat' # From gradle's source path
+  - 'androidx.emoji2.text.DefaultEmojiCompatConfig' # From gradle's source path
   - 'android.os.Build' # from gradle's compile classpath
   - 'java.util.HashMap' # from gradle's compile classpath
diff --git a/pkgs/jnigen/example/in_app_java/lib/android_utils.dart b/pkgs/jnigen/example/in_app_java/lib/android_utils.dart
index 4030ba7..3faba5b 100644
--- a/pkgs/jnigen/example/in_app_java/lib/android_utils.dart
+++ b/pkgs/jnigen/example/in_app_java/lib/android_utils.dart
@@ -60,6 +60,1925 @@
   AndroidUtils fromRef(jni.JObjectPtr ref) => AndroidUtils.fromRef(ref);
 }
 
+/// from: androidx.emoji2.text.EmojiCompat
+///
+/// Main class to keep Android devices up to date with the newest emojis by adding EmojiSpans
+/// to a given CharSequence.
+/// <p/>
+/// By default, EmojiCompat is initialized by EmojiCompatInitializer, which performs
+/// deferred font loading to avoid potential app startup delays. The default behavior is to load
+/// the font shortly after the first Activity resumes. EmojiCompatInitializer will configure
+/// EmojiCompat to use the system emoji font provider via DefaultEmojiCompatConfig and
+/// always creates a new background thread for font loading.
+/// <p/>
+/// EmojiCompat will only allow one instance to be initialized and any calls to
+/// \#init(Config) after the first one will have no effect. As a result, configuration options
+/// may not be provided when using EmojiCompatInitializer. To provide a custom configuration,
+/// disable EmojiCompatInitializer in the manifest with:
+///
+/// <pre>
+///     &lt;provider
+///         android:name="androidx.startup.InitializationProvider"
+///         android:authorities="${applicationId}.androidx-startup"
+///         android:exported="false"
+///         tools:node="merge"&gt;
+///         &lt;meta-data android:name="androidx.emoji2.text.EmojiCompatInitializer"
+///                   tools:node="remove" /&gt;
+///     &lt;/provider&gt;
+/// </pre>
+///
+/// When not using EmojiCompatInitializer, EmojiCompat must to be initialized manually using
+/// \#init(EmojiCompat.Config). It is recommended to make the initialization as early as
+/// possible in your app, such as from Application\#onCreate().
+/// <p/>
+/// \#init(Config) is fast and may be called from the main thread on the path to
+/// displaying the first activity. However, loading the emoji font takes significant resources on a
+/// background thread, so it is suggested to use \#LOAD_STRATEGY_MANUAL in all manual
+/// configurations to defer font loading until after the first screen displays. Font loading may
+/// be started by calling \#load()}. See the implementation EmojiCompatInitializer
+/// for ideas when building a manual configuration.
+/// <p/>
+/// After initialization the \#get() function can be used to get the configured instance and
+/// the \#process(CharSequence) function can be used to update a CharSequence with emoji
+/// EmojiSpans.
+/// <p/>
+/// <pre><code>CharSequence processedSequence = EmojiCompat.get().process("some string")</pre>
+/// <p/>
+/// During loading information about emojis is not available. Before the
+/// EmojiCompat instance has finished loading, calls to functions such as EmojiCompat\#process(CharSequence) will throw an exception. It is safe to call process when
+/// \#getLoadState() returns \#LOAD_STATE_SUCCEEDED. To register a callback when
+/// loading completes use InitCallback.
+/// <p/>
+class EmojiCompat extends jni.JObject {
+  late final jni.JObjType? _$type;
+  @override
+  jni.JObjType get $type => _$type ??= type;
+
+  EmojiCompat.fromRef(
+    jni.JObjectPtr ref,
+  ) : super.fromRef(ref);
+
+  /// The type which includes information such as the signature of this class.
+  static const type = $EmojiCompatType();
+
+  /// from: static public final java.lang.String EDITOR_INFO_METAVERSION_KEY
+  ///
+  /// Key in EditorInfo\#extras that represents the emoji metadata version used by the
+  /// widget. The existence of the value means that the widget is using EmojiCompat.
+  /// <p/>
+  /// If exists, the value for the key is an {@code int} and can be used to query EmojiCompat to
+  /// see whether the widget has the ability to display a certain emoji using
+  /// \#hasEmojiGlyph(CharSequence, int).
+  static const EDITOR_INFO_METAVERSION_KEY =
+      r"""android.support.text.emoji.emojiCompat_metadataVersion""";
+
+  /// from: static public final java.lang.String EDITOR_INFO_REPLACE_ALL_KEY
+  ///
+  /// Key in EditorInfo\#extras that represents EmojiCompat.Config\#setReplaceAll(boolean) configuration parameter. The key is added only if
+  /// EmojiCompat is used by the widget. If exists, the value is a boolean.
+  static const EDITOR_INFO_REPLACE_ALL_KEY =
+      r"""android.support.text.emoji.emojiCompat_replaceAll""";
+
+  /// from: static public final int LOAD_STATE_DEFAULT
+  ///
+  /// EmojiCompat instance is constructed, however the initialization did not start yet.
+  ///@see \#getLoadState()
+  static const LOAD_STATE_DEFAULT = 3;
+
+  /// from: static public final int LOAD_STATE_LOADING
+  ///
+  /// EmojiCompat is initializing.
+  ///@see \#getLoadState()
+  static const LOAD_STATE_LOADING = 0;
+
+  /// from: static public final int LOAD_STATE_SUCCEEDED
+  ///
+  /// EmojiCompat successfully initialized.
+  ///@see \#getLoadState()
+  static const LOAD_STATE_SUCCEEDED = 1;
+
+  /// from: static public final int LOAD_STATE_FAILED
+  ///
+  /// An unrecoverable error occurred during initialization of EmojiCompat. Calls to functions
+  /// such as \#process(CharSequence) will fail.
+  ///@see \#getLoadState()
+  static const LOAD_STATE_FAILED = 2;
+
+  /// from: static public final int REPLACE_STRATEGY_DEFAULT
+  ///
+  /// Replace strategy that uses the value given in EmojiCompat.Config.
+  ///@see \#process(CharSequence, int, int, int, int)
+  static const REPLACE_STRATEGY_DEFAULT = 0;
+
+  /// from: static public final int REPLACE_STRATEGY_ALL
+  ///
+  /// Replace strategy to add EmojiSpans for all emoji that were found.
+  ///@see \#process(CharSequence, int, int, int, int)
+  static const REPLACE_STRATEGY_ALL = 1;
+
+  /// from: static public final int REPLACE_STRATEGY_NON_EXISTENT
+  ///
+  /// Replace strategy to add EmojiSpans only for emoji that do not exist in the system.
+  static const REPLACE_STRATEGY_NON_EXISTENT = 2;
+
+  /// from: static public final int LOAD_STRATEGY_DEFAULT
+  ///
+  /// EmojiCompat will start loading metadata when \#init(Config) is called.
+  ///@see Config\#setMetadataLoadStrategy(int)
+  static const LOAD_STRATEGY_DEFAULT = 0;
+
+  /// from: static public final int LOAD_STRATEGY_MANUAL
+  ///
+  /// EmojiCompat will wait for \#load() to be called by developer in order to
+  /// start loading metadata.
+  ///@see Config\#setMetadataLoadStrategy(int)
+  static const LOAD_STRATEGY_MANUAL = 1;
+
+  /// from: static public final int EMOJI_UNSUPPORTED
+  ///
+  /// Result of \#getEmojiMatch(CharSequence, int) that means no part of this codepoint
+  /// sequence will ever generate an EmojiSpan at the requested metadata level.
+  ///
+  /// This return value implies:
+  /// - EmojiCompat will always defer to system emoji font
+  /// - System emoji font may or may not support this emoji
+  /// - This application MAY render this emoji
+  ///
+  /// This can be used by keyboards to learn that EmojiCompat does not support this codepoint
+  /// sequence at this metadata version. The system emoji font is not checked by this method,
+  /// and this result will be returned even if the system emoji font supports the emoji. This may
+  /// happen if the application is using an older version of the emoji compat font than the
+  /// system emoji font.
+  ///
+  /// Keyboards may optionally determine that the system emoji font will support the emoji, for
+  /// example by building a internal lookup table or calling
+  /// androidx.core.graphics.PaintCompat\#hasGlyph(Paint, String) to query the system
+  /// emoji font. Keyboards may use a lookup table to optimize this check, however they should be
+  /// aware that OEMs may add or remove emoji from the system emoji font.
+  ///
+  /// Keyboards may finally decide:
+  /// - If the system emoji font DOES NOT support the emoji, then the emoji IS NOT supported by
+  /// this application.
+  /// - If the system emoji font DOES support the emoji, then the emoji IS supported by this
+  /// application.
+  /// - If system emoji font is support is UNKNOWN, then assume the emoji IS NOT supported by
+  /// this application.
+  static const EMOJI_UNSUPPORTED = 0;
+
+  /// from: static public final int EMOJI_SUPPORTED
+  ///
+  /// Result of \#getEmojiMatch(CharSequence, int) that means this codepoint can be drawn
+  /// by an EmojiSpan at this metadata level.
+  ///
+  /// No further checks are required by keyboards for this result. The emoji is always supported
+  /// by this application.
+  ///
+  /// This return value implies:
+  /// - EmojiCompat can draw this emoji
+  /// - System emoji font may or may not support this emoji
+  /// - This application WILL render this emoji
+  ///
+  /// This result implies that EmojiCompat can successfully display this emoji. The system emoji
+  /// font is not checked by this method, and this result may be returned even if the platform
+  /// also supports the emoji sequence.
+  ///
+  /// If the application passes EmojiCompat\#REPLACE_STRATEGY_ALL of true, then an
+  /// EmojiSpan will always be generated for this emoji.
+  ///
+  /// If the application passes EmojiCompat\#REPLACE_STRATEGY_ALL of false, then an
+  /// EmojiSpan will only be generated if
+  /// androidx.core.graphics.PaintCompat\#hasGlyph(Paint, String)
+  /// returns false for this emoji.
+  static const EMOJI_SUPPORTED = 1;
+
+  /// from: static public final int EMOJI_FALLBACK
+  ///
+  /// Result of \#getEmojiMatch(CharSequence, int) that means the full codepoint sequence
+  /// is not known to emojicompat, but at least one subsequence is an emoji that is known at
+  /// this metadata level.
+  ///
+  /// Keyboards may decide that this emoji is not supported by the application when this result is
+  /// returned, with no further processing.
+  ///
+  /// This return value implies:
+  /// - EmojiCompat will decompose this ZWJ sequence into multiple glyphs when replaceAll=true
+  /// - EmojiCompat MAY defer to platform when replaceAll=false
+  /// - System emoji font may or may not support this emoji
+  /// - This application MAY render this emoji
+  ///
+  /// This return value is only ever returned for ZWJ sequences. To understand this result
+  /// consider when it may be returned for the multi-skin-tone handshake introduced in emoji 14.
+  ///
+  /// <pre>
+  ///     U+1FAF1 // unknown @ requested metadata level
+  ///     U+1F3FB // metadata level 1
+  ///     U+200D  // not displayed (ZWJ)
+  ///     U+1FAF2 // unknown @ requested metadata level
+  ///     U+1F3FD // metadata level 1
+  /// </pre>
+  ///
+  /// In this codepoint sequence, U+1F3FB and U+1F3FD are known from metadata level 1. When an
+  /// application is using a metadata level that doesn't understand this ZWJ and provides
+  /// EmojiCompat\#REPLACE_STRATEGY_ALL true, the color emoji are matched and replaced
+  /// with EmojiSpan. The system emoji font, even if it supports this ZWJ sequence, is
+  /// never queried and the added EmojiSpans force fallback rendering for the ZWJ sequence.
+  ///
+  /// The glyph will only display correctly for this application if ALL of the following
+  /// requirements are met:
+  /// - EmojiCompat\#REPLACE_STRATEGY_ALL is false
+  /// - androidx.core.graphics.PaintCompat\#hasGlyph(Paint, String) returns true for each
+  /// emoji subsequence known at this metadata level
+  /// - androidx.core.graphics.PaintCompat\#hasGlyph(Paint, String) returns true for the
+  /// full sequence
+  ///
+  /// Given this return value for the multi-skin-tone handshake above, if
+  /// EmojiCompat\#REPLACE_STRATEGY_ALL is false then the emoji will display if the
+  /// entire emoji sequence is matched by
+  /// androidx.core.graphics.PaintCompat\#hasGlyph(Paint, String) because U+1F3FB and
+  /// U+1F3FD are both in the system emoji font.
+  ///
+  /// Keyboards that wish to determine if the glyph will display correctly by the application in
+  /// response to this return value should consider building an internal lookup for new ZWJ
+  /// sequences instead of repeatedly calling
+  /// androidx.core.graphics.PaintCompat\#hasGlyph(Paint, String) for each emoji
+  /// subsequence.
+  static const EMOJI_FALLBACK = 2;
+
+  static final _init = jniLookup<
+          ffi.NativeFunction<
+              jni.JniResult Function(
+                  ffi.Pointer<ffi.Void>)>>("EmojiCompat__init")
+      .asFunction<jni.JniResult Function(ffi.Pointer<ffi.Void>)>();
+
+  /// from: static public androidx.emoji2.text.EmojiCompat init(android.content.Context context)
+  /// The returned object must be deleted after use, by calling the `delete` method.
+  ///
+  /// Initialize the singleton instance with the default system-provided configuration.
+  ///
+  /// This is the recommended configuration for most applications. For more details see
+  /// DefaultEmojiCompatConfig.
+  ///
+  ///
+  /// This call will use DefaultEmojiCompatConfig to lookup the default emoji font
+  /// provider installed on the system and use that, if present. If there is no default font
+  /// provider onthe system, this call will have no effect.
+  ///
+  ///
+  /// Note: EmojiCompat may only be initialized once, and will return the same instance
+  /// afterwords.
+  ///
+  ///@return Default EmojiCompat for this device, or null if there is no provider on the system.
+  static EmojiCompat init(jni.JObject context) =>
+      const $EmojiCompatType().fromRef(_init(context.reference).object);
+
+  static final _init1 = jniLookup<
+          ffi.NativeFunction<
+              jni.JniResult Function(ffi.Pointer<ffi.Void>,
+                  ffi.Pointer<ffi.Void>)>>("EmojiCompat__init1")
+      .asFunction<
+          jni.JniResult Function(
+              ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>)>();
+
+  /// from: static public androidx.emoji2.text.EmojiCompat init(android.content.Context context, androidx.emoji2.text.DefaultEmojiCompatConfig.DefaultEmojiCompatConfigFactory defaultFactory)
+  /// The returned object must be deleted after use, by calling the `delete` method.
+  ///
+  /// @hide
+  static EmojiCompat init1(
+          jni.JObject context,
+          DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactory
+              defaultFactory) =>
+      const $EmojiCompatType()
+          .fromRef(_init1(context.reference, defaultFactory.reference).object);
+
+  static final _init2 = jniLookup<
+          ffi.NativeFunction<
+              jni.JniResult Function(
+                  ffi.Pointer<ffi.Void>)>>("EmojiCompat__init2")
+      .asFunction<jni.JniResult Function(ffi.Pointer<ffi.Void>)>();
+
+  /// from: static public androidx.emoji2.text.EmojiCompat init(androidx.emoji2.text.EmojiCompat.Config config)
+  /// The returned object must be deleted after use, by calling the `delete` method.
+  ///
+  /// Initialize the singleton instance with a configuration. When used on devices running API 18
+  /// or below, the singleton instance is immediately moved into \#LOAD_STATE_SUCCEEDED
+  /// state without loading any metadata. When called for the first time, the library will create
+  /// the singleton instance and any call after that will not create a new instance and return
+  /// immediately.
+  ///@see EmojiCompat.Config
+  static EmojiCompat init2(EmojiCompat_Config config) =>
+      const $EmojiCompatType().fromRef(_init2(config.reference).object);
+
+  static final _isConfigured =
+      jniLookup<ffi.NativeFunction<jni.JniResult Function()>>(
+              "EmojiCompat__isConfigured")
+          .asFunction<jni.JniResult Function()>();
+
+  /// from: static public boolean isConfigured()
+  ///
+  /// Return true if EmojiCompat has been configured by a successful call to
+  /// EmojiCompat\#init.
+  ///
+  /// You can use this to check if EmojiCompat\#get() will return a valid EmojiCompat
+  /// instance.
+  ///
+  /// This function does not check the \#getLoadState() and will return true even if the
+  /// font is still loading, or has failed to load.
+  ///@return true if EmojiCompat has been successfully initialized.
+  static bool isConfigured() => _isConfigured().boolean;
+
+  static final _reset = jniLookup<
+          ffi.NativeFunction<
+              jni.JniResult Function(
+                  ffi.Pointer<ffi.Void>)>>("EmojiCompat__reset")
+      .asFunction<jni.JniResult Function(ffi.Pointer<ffi.Void>)>();
+
+  /// from: static public androidx.emoji2.text.EmojiCompat reset(androidx.emoji2.text.EmojiCompat.Config config)
+  /// The returned object must be deleted after use, by calling the `delete` method.
+  ///
+  /// Used by the tests to reset EmojiCompat with a new configuration. Every time it is called a
+  /// new instance is created with the new configuration.
+  ///@hide
+  static EmojiCompat reset(EmojiCompat_Config config) =>
+      const $EmojiCompatType().fromRef(_reset(config.reference).object);
+
+  static final _reset1 = jniLookup<
+          ffi.NativeFunction<
+              jni.JniResult Function(
+                  ffi.Pointer<ffi.Void>)>>("EmojiCompat__reset1")
+      .asFunction<jni.JniResult Function(ffi.Pointer<ffi.Void>)>();
+
+  /// from: static public androidx.emoji2.text.EmojiCompat reset(androidx.emoji2.text.EmojiCompat emojiCompat)
+  /// The returned object must be deleted after use, by calling the `delete` method.
+  ///
+  /// Used by the tests to reset EmojiCompat with a new singleton instance.
+  ///@hide
+  static EmojiCompat reset1(EmojiCompat emojiCompat) =>
+      const $EmojiCompatType().fromRef(_reset1(emojiCompat.reference).object);
+
+  static final _skipDefaultConfigurationLookup =
+      jniLookup<ffi.NativeFunction<jni.JniResult Function(ffi.Uint8)>>(
+              "EmojiCompat__skipDefaultConfigurationLookup")
+          .asFunction<jni.JniResult Function(int)>();
+
+  /// from: static public void skipDefaultConfigurationLookup(boolean shouldSkip)
+  ///
+  /// Reset default configuration lookup flag, for tests.
+  ///@hide
+  static void skipDefaultConfigurationLookup(bool shouldSkip) =>
+      _skipDefaultConfigurationLookup(shouldSkip ? 1 : 0).check();
+
+  static final _get0 = jniLookup<ffi.NativeFunction<jni.JniResult Function()>>(
+          "EmojiCompat__get0")
+      .asFunction<jni.JniResult Function()>();
+
+  /// from: static public androidx.emoji2.text.EmojiCompat get()
+  /// The returned object must be deleted after use, by calling the `delete` method.
+  ///
+  /// Return singleton EmojiCompat instance. Should be called after
+  /// \#init(EmojiCompat.Config) is called to initialize the singleton instance.
+  ///@return EmojiCompat instance
+  ///@throws IllegalStateException if called before \#init(EmojiCompat.Config)
+  static EmojiCompat get0() => const $EmojiCompatType().fromRef(_get0().object);
+
+  static final _load = jniLookup<
+          ffi.NativeFunction<
+              jni.JniResult Function(
+                  ffi.Pointer<ffi.Void>)>>("EmojiCompat__load")
+      .asFunction<jni.JniResult Function(ffi.Pointer<ffi.Void>)>();
+
+  /// from: public void load()
+  ///
+  /// When Config\#setMetadataLoadStrategy(int) is set to \#LOAD_STRATEGY_MANUAL,
+  /// this function starts loading the metadata. Calling the function when
+  /// Config\#setMetadataLoadStrategy(int) is {@code not} set to
+  /// \#LOAD_STRATEGY_MANUAL will throw an exception. The load will {@code not} start if:
+  /// <ul>
+  ///     <li>the metadata is already loaded successfully and \#getLoadState() is
+  ///     \#LOAD_STATE_SUCCEEDED.
+  ///     </li>
+  ///      <li>a previous load attempt is not finished yet and \#getLoadState() is
+  ///     \#LOAD_STATE_LOADING.</li>
+  /// </ul>
+  ///@throws IllegalStateException when Config\#setMetadataLoadStrategy(int) is not set
+  /// to \#LOAD_STRATEGY_MANUAL
+  void load() => _load(reference).check();
+
+  static final _registerInitCallback = jniLookup<
+          ffi.NativeFunction<
+              jni.JniResult Function(ffi.Pointer<ffi.Void>,
+                  ffi.Pointer<ffi.Void>)>>("EmojiCompat__registerInitCallback")
+      .asFunction<
+          jni.JniResult Function(
+              ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>)>();
+
+  /// from: public void registerInitCallback(androidx.emoji2.text.EmojiCompat.InitCallback initCallback)
+  ///
+  /// Registers an initialization callback. If the initialization is already completed by the time
+  /// the listener is added, the callback functions are called immediately. Callbacks are called on
+  /// the main looper.
+  /// <p/>
+  /// When used on devices running API 18 or below, InitCallback\#onInitialized() is called
+  /// without loading any metadata. In such cases InitCallback\#onFailed(Throwable) is never
+  /// called.
+  ///@param initCallback the initialization callback to register, cannot be {@code null}
+  ///@see \#unregisterInitCallback(InitCallback)
+  void registerInitCallback(EmojiCompat_InitCallback initCallback) =>
+      _registerInitCallback(reference, initCallback.reference).check();
+
+  static final _unregisterInitCallback = jniLookup<
+              ffi.NativeFunction<
+                  jni.JniResult Function(
+                      ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>)>>(
+          "EmojiCompat__unregisterInitCallback")
+      .asFunction<
+          jni.JniResult Function(
+              ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>)>();
+
+  /// from: public void unregisterInitCallback(androidx.emoji2.text.EmojiCompat.InitCallback initCallback)
+  ///
+  /// Unregisters a callback that was added before.
+  ///@param initCallback the callback to be removed, cannot be {@code null}
+  void unregisterInitCallback(EmojiCompat_InitCallback initCallback) =>
+      _unregisterInitCallback(reference, initCallback.reference).check();
+
+  static final _getLoadState = jniLookup<
+          ffi.NativeFunction<
+              jni.JniResult Function(
+                  ffi.Pointer<ffi.Void>)>>("EmojiCompat__getLoadState")
+      .asFunction<jni.JniResult Function(ffi.Pointer<ffi.Void>)>();
+
+  /// from: public int getLoadState()
+  ///
+  /// Returns loading state of the EmojiCompat instance. When used on devices running API 18 or
+  /// below always returns \#LOAD_STATE_SUCCEEDED.
+  ///@return one of \#LOAD_STATE_DEFAULT, \#LOAD_STATE_LOADING,
+  /// \#LOAD_STATE_SUCCEEDED, \#LOAD_STATE_FAILED
+  int getLoadState() => _getLoadState(reference).integer;
+
+  static final _isEmojiSpanIndicatorEnabled = jniLookup<
+              ffi.NativeFunction<
+                  jni.JniResult Function(ffi.Pointer<ffi.Void>)>>(
+          "EmojiCompat__isEmojiSpanIndicatorEnabled")
+      .asFunction<jni.JniResult Function(ffi.Pointer<ffi.Void>)>();
+
+  /// from: public boolean isEmojiSpanIndicatorEnabled()
+  ///
+  /// @return whether a background should be drawn for the emoji for debugging
+  ///@hide
+  bool isEmojiSpanIndicatorEnabled() =>
+      _isEmojiSpanIndicatorEnabled(reference).boolean;
+
+  static final _getEmojiSpanIndicatorColor = jniLookup<
+              ffi.NativeFunction<
+                  jni.JniResult Function(ffi.Pointer<ffi.Void>)>>(
+          "EmojiCompat__getEmojiSpanIndicatorColor")
+      .asFunction<jni.JniResult Function(ffi.Pointer<ffi.Void>)>();
+
+  /// from: public int getEmojiSpanIndicatorColor()
+  ///
+  /// @return color of background drawn if EmojiCompat\#isEmojiSpanIndicatorEnabled is true
+  ///@hide
+  int getEmojiSpanIndicatorColor() =>
+      _getEmojiSpanIndicatorColor(reference).integer;
+
+  static final _getEmojiStart = jniLookup<
+          ffi.NativeFunction<
+              jni.JniResult Function(
+                  ffi.Pointer<ffi.Void>,
+                  ffi.Pointer<ffi.Void>,
+                  ffi.Int32)>>("EmojiCompat__getEmojiStart")
+      .asFunction<
+          jni.JniResult Function(
+              ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>, int)>();
+
+  /// from: public int getEmojiStart(java.lang.CharSequence charSequence, int offset)
+  ///
+  /// Together with \#getEmojiEnd(CharSequence, int), if the character at {@code offset} is
+  /// part of an emoji, returns the index range of that emoji, start index inclusively/end index
+  /// exclusively so that {@code charSequence.subSequence(start, end)} will return that emoji.
+  /// E.g., getEmojiStart/End("AB\ud83d\ude00", 1) will return (-1,-1) since 'B' is not part an emoji;
+  ///       getEmojiStart/End("AB\ud83d\ude00", 3) will return [2,4), note that "\ud83d\ude00" contains 2 Chars.
+  /// Returns -1 otherwise.
+  ///@param charSequence the whole sequence
+  ///@param offset index of the emoji to look up
+  ///@return the start index inclusively/end index exclusively
+  int getEmojiStart(jni.JObject charSequence, int offset) =>
+      _getEmojiStart(reference, charSequence.reference, offset).integer;
+
+  static final _getEmojiEnd = jniLookup<
+          ffi.NativeFunction<
+              jni.JniResult Function(
+                  ffi.Pointer<ffi.Void>,
+                  ffi.Pointer<ffi.Void>,
+                  ffi.Int32)>>("EmojiCompat__getEmojiEnd")
+      .asFunction<
+          jni.JniResult Function(
+              ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>, int)>();
+
+  /// from: public int getEmojiEnd(java.lang.CharSequence charSequence, int offset)
+  ///
+  /// see \#getEmojiStart(CharSequence, int).
+  int getEmojiEnd(jni.JObject charSequence, int offset) =>
+      _getEmojiEnd(reference, charSequence.reference, offset).integer;
+
+  static final _handleOnKeyDown = jniLookup<
+          ffi.NativeFunction<
+              jni.JniResult Function(ffi.Pointer<ffi.Void>, ffi.Int32,
+                  ffi.Pointer<ffi.Void>)>>("EmojiCompat__handleOnKeyDown")
+      .asFunction<
+          jni.JniResult Function(
+              ffi.Pointer<ffi.Void>, int, ffi.Pointer<ffi.Void>)>();
+
+  /// from: static public boolean handleOnKeyDown(android.text.Editable editable, int keyCode, android.view.KeyEvent event)
+  ///
+  /// Handles onKeyDown commands from a KeyListener and if {@code keyCode} is one of
+  /// KeyEvent\#KEYCODE_DEL or KeyEvent\#KEYCODE_FORWARD_DEL it tries to delete an
+  /// EmojiSpan from an Editable. Returns {@code true} if an EmojiSpan is
+  /// deleted with the characters it covers.
+  /// <p/>
+  /// If there is a selection where selection start is not equal to selection end, does not
+  /// delete.
+  /// <p/>
+  /// When used on devices running API 18 or below, always returns {@code false}.
+  ///@param editable Editable instance passed to KeyListener\#onKeyDown(android.view.View,
+  ///                 Editable, int, KeyEvent)
+  ///@param keyCode keyCode passed to KeyListener\#onKeyDown(android.view.View, Editable,
+  ///                int, KeyEvent)
+  ///@param event KeyEvent passed to KeyListener\#onKeyDown(android.view.View, Editable,
+  ///              int, KeyEvent)
+  ///@return {@code true} if an EmojiSpan is deleted
+  static bool handleOnKeyDown(
+          jni.JObject editable, int keyCode, jni.JObject event) =>
+      _handleOnKeyDown(editable.reference, keyCode, event.reference).boolean;
+
+  static final _handleDeleteSurroundingText = jniLookup<
+          ffi.NativeFunction<
+              jni.JniResult Function(
+                  ffi.Pointer<ffi.Void>,
+                  ffi.Pointer<ffi.Void>,
+                  ffi.Int32,
+                  ffi.Int32,
+                  ffi.Uint8)>>("EmojiCompat__handleDeleteSurroundingText")
+      .asFunction<
+          jni.JniResult Function(
+              ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>, int, int, int)>();
+
+  /// from: static public boolean handleDeleteSurroundingText(android.view.inputmethod.InputConnection inputConnection, android.text.Editable editable, int beforeLength, int afterLength, boolean inCodePoints)
+  ///
+  /// Handles deleteSurroundingText commands from InputConnection and tries to delete an
+  /// EmojiSpan from an Editable. Returns {@code true} if an EmojiSpan is
+  /// deleted.
+  /// <p/>
+  /// If there is a selection where selection start is not equal to selection end, does not
+  /// delete.
+  /// <p/>
+  /// When used on devices running API 18 or below, always returns {@code false}.
+  ///@param inputConnection InputConnection instance
+  ///@param editable TextView.Editable instance
+  ///@param beforeLength the number of characters before the cursor to be deleted
+  ///@param afterLength the number of characters after the cursor to be deleted
+  ///@param inCodePoints {@code true} if length parameters are in codepoints
+  ///@return {@code true} if an EmojiSpan is deleted
+  static bool handleDeleteSurroundingText(
+          jni.JObject inputConnection,
+          jni.JObject editable,
+          int beforeLength,
+          int afterLength,
+          bool inCodePoints) =>
+      _handleDeleteSurroundingText(
+              inputConnection.reference,
+              editable.reference,
+              beforeLength,
+              afterLength,
+              inCodePoints ? 1 : 0)
+          .boolean;
+
+  static final _hasEmojiGlyph = jniLookup<
+          ffi.NativeFunction<
+              jni.JniResult Function(ffi.Pointer<ffi.Void>,
+                  ffi.Pointer<ffi.Void>)>>("EmojiCompat__hasEmojiGlyph")
+      .asFunction<
+          jni.JniResult Function(
+              ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>)>();
+
+  /// from: public boolean hasEmojiGlyph(java.lang.CharSequence sequence)
+  ///
+  /// Returns {@code true} if EmojiCompat is capable of rendering an emoji. When used on devices
+  /// running API 18 or below, always returns {@code false}.
+  ///@deprecated use getEmojiMatch which returns more accurate lookup information.
+  ///@param sequence CharSequence representing the emoji
+  ///@return {@code true} if EmojiCompat can render given emoji, cannot be {@code null}
+  ///@throws IllegalStateException if not initialized yet
+  bool hasEmojiGlyph(jni.JObject sequence) =>
+      _hasEmojiGlyph(reference, sequence.reference).boolean;
+
+  static final _hasEmojiGlyph1 = jniLookup<
+          ffi.NativeFunction<
+              jni.JniResult Function(
+                  ffi.Pointer<ffi.Void>,
+                  ffi.Pointer<ffi.Void>,
+                  ffi.Int32)>>("EmojiCompat__hasEmojiGlyph1")
+      .asFunction<
+          jni.JniResult Function(
+              ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>, int)>();
+
+  /// from: public boolean hasEmojiGlyph(java.lang.CharSequence sequence, int metadataVersion)
+  ///
+  /// Returns {@code true} if EmojiCompat is capable of rendering an emoji at the given metadata
+  /// version. When used on devices running API 18 or below, always returns {@code false}.
+  ///@deprecated use getEmojiMatch which returns more accurate lookup information.
+  ///@param sequence CharSequence representing the emoji
+  ///@param metadataVersion the metadata version to check against, should be greater than or
+  ///                        equal to {@code 0},
+  ///@return {@code true} if EmojiCompat can render given emoji, cannot be {@code null}
+  ///@throws IllegalStateException if not initialized yet
+  bool hasEmojiGlyph1(jni.JObject sequence, int metadataVersion) =>
+      _hasEmojiGlyph1(reference, sequence.reference, metadataVersion).boolean;
+
+  static final _getEmojiMatch = jniLookup<
+          ffi.NativeFunction<
+              jni.JniResult Function(
+                  ffi.Pointer<ffi.Void>,
+                  ffi.Pointer<ffi.Void>,
+                  ffi.Int32)>>("EmojiCompat__getEmojiMatch")
+      .asFunction<
+          jni.JniResult Function(
+              ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>, int)>();
+
+  /// from: public int getEmojiMatch(java.lang.CharSequence sequence, int metadataVersion)
+  ///
+  /// Attempts to lookup the entire sequence at the specified metadata version and returns what
+  /// the runtime match behavior would be.
+  ///
+  /// To be used by keyboards to show or hide emoji in response to specific metadata support.
+  ///@see \#EMOJI_SUPPORTED
+  ///@see \#EMOJI_UNSUPPORTED
+  ///@see \#EMOJI_FALLBACK
+  ///@param sequence CharSequence representing an emoji
+  ///@param metadataVersion the metada version to check against, should be greater than or
+  ///                        equal to {@code 0},
+  ///@return A match result, or decomposes if replaceAll would cause partial subsequence matches.
+  int getEmojiMatch(jni.JObject sequence, int metadataVersion) =>
+      _getEmojiMatch(reference, sequence.reference, metadataVersion).integer;
+
+  static final _process = jniLookup<
+          ffi.NativeFunction<
+              jni.JniResult Function(ffi.Pointer<ffi.Void>,
+                  ffi.Pointer<ffi.Void>)>>("EmojiCompat__process")
+      .asFunction<
+          jni.JniResult Function(
+              ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>)>();
+
+  /// from: public java.lang.CharSequence process(java.lang.CharSequence charSequence)
+  /// The returned object must be deleted after use, by calling the `delete` method.
+  ///
+  /// Checks a given CharSequence for emojis, and adds EmojiSpans if any emojis are found. When
+  /// used on devices running API 18 or below, returns the given {@code charSequence} without
+  /// processing it.
+  ///@param charSequence CharSequence to add the EmojiSpans
+  ///@throws IllegalStateException if not initialized yet
+  ///@see \#process(CharSequence, int, int)
+  jni.JObject process(jni.JObject charSequence) => const jni.JObjectType()
+      .fromRef(_process(reference, charSequence.reference).object);
+
+  static final _process1 = jniLookup<
+          ffi.NativeFunction<
+              jni.JniResult Function(
+                  ffi.Pointer<ffi.Void>,
+                  ffi.Pointer<ffi.Void>,
+                  ffi.Int32,
+                  ffi.Int32)>>("EmojiCompat__process1")
+      .asFunction<
+          jni.JniResult Function(
+              ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>, int, int)>();
+
+  /// from: public java.lang.CharSequence process(java.lang.CharSequence charSequence, int start, int end)
+  /// The returned object must be deleted after use, by calling the `delete` method.
+  ///
+  /// Checks a given CharSequence for emojis, and adds EmojiSpans if any emojis are found.
+  ///
+  /// <ul>
+  /// <li>If no emojis are found, {@code charSequence} given as the input is returned without
+  /// any changes. i.e. charSequence is a String, and no emojis are found, the same String is
+  /// returned.</li>
+  /// <li>If the given input is not a Spannable (such as String), and at least one emoji is found
+  /// a new android.text.Spannable instance is returned. </li>
+  /// <li>If the given input is a Spannable, the same instance is returned. </li>
+  /// </ul>
+  /// When used on devices running API 18 or below, returns the given {@code charSequence} without
+  /// processing it.
+  ///@param charSequence CharSequence to add the EmojiSpans, cannot be {@code null}
+  ///@param start start index in the charSequence to look for emojis, should be greater than or
+  ///              equal to {@code 0}, also less than or equal to {@code charSequence.length()}
+  ///@param end end index in the charSequence to look for emojis, should be greater than or equal
+  ///              to {@code start} parameter, also less than or equal to
+  ///              {@code charSequence.length()}
+  ///@throws IllegalStateException if not initialized yet
+  ///@throws IllegalArgumentException in the following cases:
+  ///                                  {@code start < 0}, {@code end < 0}, {@code end < start},
+  ///                                  {@code start > charSequence.length()},
+  ///                                  {@code end > charSequence.length()}
+  jni.JObject process1(jni.JObject charSequence, int start, int end) =>
+      const jni.JObjectType().fromRef(
+          _process1(reference, charSequence.reference, start, end).object);
+
+  static final _process2 = jniLookup<
+          ffi.NativeFunction<
+              jni.JniResult Function(
+                  ffi.Pointer<ffi.Void>,
+                  ffi.Pointer<ffi.Void>,
+                  ffi.Int32,
+                  ffi.Int32,
+                  ffi.Int32)>>("EmojiCompat__process2")
+      .asFunction<
+          jni.JniResult Function(
+              ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>, int, int, int)>();
+
+  /// from: public java.lang.CharSequence process(java.lang.CharSequence charSequence, int start, int end, int maxEmojiCount)
+  /// The returned object must be deleted after use, by calling the `delete` method.
+  ///
+  /// Checks a given CharSequence for emojis, and adds EmojiSpans if any emojis are found.
+  ///
+  /// <ul>
+  /// <li>If no emojis are found, {@code charSequence} given as the input is returned without
+  /// any changes. i.e. charSequence is a String, and no emojis are found, the same String is
+  /// returned.</li>
+  /// <li>If the given input is not a Spannable (such as String), and at least one emoji is found
+  /// a new android.text.Spannable instance is returned. </li>
+  /// <li>If the given input is a Spannable, the same instance is returned. </li>
+  /// </ul>
+  /// When used on devices running API 18 or below, returns the given {@code charSequence} without
+  /// processing it.
+  ///@param charSequence CharSequence to add the EmojiSpans, cannot be {@code null}
+  ///@param start start index in the charSequence to look for emojis, should be greater than or
+  ///              equal to {@code 0}, also less than or equal to {@code charSequence.length()}
+  ///@param end end index in the charSequence to look for emojis, should be greater than or
+  ///            equal to {@code start} parameter, also less than or equal to
+  ///            {@code charSequence.length()}
+  ///@param maxEmojiCount maximum number of emojis in the {@code charSequence}, should be greater
+  ///                      than or equal to {@code 0}
+  ///@throws IllegalStateException if not initialized yet
+  ///@throws IllegalArgumentException in the following cases:
+  ///                                  {@code start < 0}, {@code end < 0}, {@code end < start},
+  ///                                  {@code start > charSequence.length()},
+  ///                                  {@code end > charSequence.length()}
+  ///                                  {@code maxEmojiCount < 0}
+  jni.JObject process2(
+          jni.JObject charSequence, int start, int end, int maxEmojiCount) =>
+      const jni.JObjectType().fromRef(_process2(
+              reference, charSequence.reference, start, end, maxEmojiCount)
+          .object);
+
+  static final _process3 = jniLookup<
+          ffi.NativeFunction<
+              jni.JniResult Function(
+                  ffi.Pointer<ffi.Void>,
+                  ffi.Pointer<ffi.Void>,
+                  ffi.Int32,
+                  ffi.Int32,
+                  ffi.Int32,
+                  ffi.Int32)>>("EmojiCompat__process3")
+      .asFunction<
+          jni.JniResult Function(ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>,
+              int, int, int, int)>();
+
+  /// from: public java.lang.CharSequence process(java.lang.CharSequence charSequence, int start, int end, int maxEmojiCount, int replaceStrategy)
+  /// The returned object must be deleted after use, by calling the `delete` method.
+  ///
+  /// Checks a given CharSequence for emojis, and adds EmojiSpans if any emojis are found.
+  ///
+  /// <ul>
+  /// <li>If no emojis are found, {@code charSequence} given as the input is returned without
+  /// any changes. i.e. charSequence is a String, and no emojis are found, the same String is
+  /// returned.</li>
+  /// <li>If the given input is not a Spannable (such as String), and at least one emoji is found
+  /// a new android.text.Spannable instance is returned. </li>
+  /// <li>If the given input is a Spannable, the same instance is returned. </li>
+  /// </ul>
+  /// When used on devices running API 18 or below, returns the given {@code charSequence} without
+  /// processing it.
+  ///@param charSequence CharSequence to add the EmojiSpans, cannot be {@code null}
+  ///@param start start index in the charSequence to look for emojis, should be greater than or
+  ///              equal to {@code 0}, also less than or equal to {@code charSequence.length()}
+  ///@param end end index in the charSequence to look for emojis, should be greater than or
+  ///            equal to {@code start} parameter, also less than or equal to
+  ///            {@code charSequence.length()}
+  ///@param maxEmojiCount maximum number of emojis in the {@code charSequence}, should be greater
+  ///                      than or equal to {@code 0}
+  ///@param replaceStrategy whether to replace all emoji with EmojiSpans, should be one of
+  ///                        \#REPLACE_STRATEGY_DEFAULT,
+  ///                        \#REPLACE_STRATEGY_NON_EXISTENT,
+  ///                        \#REPLACE_STRATEGY_ALL
+  ///@throws IllegalStateException if not initialized yet
+  ///@throws IllegalArgumentException in the following cases:
+  ///                                  {@code start < 0}, {@code end < 0}, {@code end < start},
+  ///                                  {@code start > charSequence.length()},
+  ///                                  {@code end > charSequence.length()}
+  ///                                  {@code maxEmojiCount < 0}
+  jni.JObject process3(jni.JObject charSequence, int start, int end,
+          int maxEmojiCount, int replaceStrategy) =>
+      const jni.JObjectType().fromRef(_process3(
+              reference,
+              charSequence.reference,
+              start,
+              end,
+              maxEmojiCount,
+              replaceStrategy)
+          .object);
+
+  static final _getAssetSignature = jniLookup<
+          ffi.NativeFunction<
+              jni.JniResult Function(
+                  ffi.Pointer<ffi.Void>)>>("EmojiCompat__getAssetSignature")
+      .asFunction<jni.JniResult Function(ffi.Pointer<ffi.Void>)>();
+
+  /// from: public java.lang.String getAssetSignature()
+  /// The returned object must be deleted after use, by calling the `delete` method.
+  ///
+  /// Returns signature for the currently loaded emoji assets. The signature is a SHA that is
+  /// constructed using emoji assets. Can be used to detect if currently loaded asset is different
+  /// then previous executions. When used on devices running API 18 or below, returns empty string.
+  ///@throws IllegalStateException if not initialized yet
+  jni.JString getAssetSignature() =>
+      const jni.JStringType().fromRef(_getAssetSignature(reference).object);
+
+  static final _updateEditorInfo = jniLookup<
+          ffi.NativeFunction<
+              jni.JniResult Function(ffi.Pointer<ffi.Void>,
+                  ffi.Pointer<ffi.Void>)>>("EmojiCompat__updateEditorInfo")
+      .asFunction<
+          jni.JniResult Function(
+              ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>)>();
+
+  /// from: public void updateEditorInfo(android.view.inputmethod.EditorInfo outAttrs)
+  ///
+  /// Updates the EditorInfo attributes in order to communicate information to Keyboards. When
+  /// used on devices running API 18 or below, does not update EditorInfo attributes.
+  ///
+  /// This is called from EditText integrations that use EmojiEditTextHelper. Custom
+  /// widgets that allow IME not subclassing EditText should call this method when creating an
+  /// input connection.
+  ///
+  /// When EmojiCompat is not in \#LOAD_STATE_SUCCEEDED, this method has no effect.
+  ///
+  /// Calling this method on API levels below API 19 will have no effect, as EmojiCompat may
+  /// never be configured. However, it is always safe to call, even on older API levels.
+  ///@param outAttrs EditorInfo instance passed to
+  ///                 android.widget.TextView\#onCreateInputConnection(EditorInfo)
+  ///@see \#EDITOR_INFO_METAVERSION_KEY
+  ///@see \#EDITOR_INFO_REPLACE_ALL_KEY
+  void updateEditorInfo(jni.JObject outAttrs) =>
+      _updateEditorInfo(reference, outAttrs.reference).check();
+}
+
+class $EmojiCompatType extends jni.JObjType<EmojiCompat> {
+  const $EmojiCompatType();
+
+  @override
+  String get signature => r"Landroidx/emoji2/text/EmojiCompat;";
+
+  @override
+  EmojiCompat fromRef(jni.JObjectPtr ref) => EmojiCompat.fromRef(ref);
+}
+
+/// from: androidx.emoji2.text.EmojiCompat$Config
+///
+/// Configuration class for EmojiCompat. Changes to the values will be ignored after
+/// \#init(Config) is called.
+///@see \#init(EmojiCompat.Config)
+class EmojiCompat_Config extends jni.JObject {
+  late final jni.JObjType? _$type;
+  @override
+  jni.JObjType get $type => _$type ??= type;
+
+  EmojiCompat_Config.fromRef(
+    jni.JObjectPtr ref,
+  ) : super.fromRef(ref);
+
+  /// The type which includes information such as the signature of this class.
+  static const type = $EmojiCompat_ConfigType();
+  static final _ctor = jniLookup<
+          ffi.NativeFunction<
+              jni.JniResult Function(
+                  ffi.Pointer<ffi.Void>)>>("EmojiCompat_Config__ctor")
+      .asFunction<jni.JniResult Function(ffi.Pointer<ffi.Void>)>();
+
+  /// from: protected void <init>(androidx.emoji2.text.EmojiCompat.MetadataRepoLoader metadataLoader)
+  /// The returned object must be deleted after use, by calling the `delete` method.
+  ///
+  /// Default constructor.
+  ///@param metadataLoader MetadataRepoLoader instance, cannot be {@code null}
+  EmojiCompat_Config(EmojiCompat_MetadataRepoLoader metadataLoader)
+      : super.fromRef(_ctor(metadataLoader.reference).object);
+
+  static final _registerInitCallback = jniLookup<
+              ffi.NativeFunction<
+                  jni.JniResult Function(
+                      ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>)>>(
+          "EmojiCompat_Config__registerInitCallback")
+      .asFunction<
+          jni.JniResult Function(
+              ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>)>();
+
+  /// from: public androidx.emoji2.text.EmojiCompat.Config registerInitCallback(androidx.emoji2.text.EmojiCompat.InitCallback initCallback)
+  /// The returned object must be deleted after use, by calling the `delete` method.
+  ///
+  /// Registers an initialization callback.
+  ///@param initCallback the initialization callback to register, cannot be {@code null}
+  ///@return EmojiCompat.Config instance
+  EmojiCompat_Config registerInitCallback(
+          EmojiCompat_InitCallback initCallback) =>
+      const $EmojiCompat_ConfigType().fromRef(
+          _registerInitCallback(reference, initCallback.reference).object);
+
+  static final _unregisterInitCallback = jniLookup<
+              ffi.NativeFunction<
+                  jni.JniResult Function(
+                      ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>)>>(
+          "EmojiCompat_Config__unregisterInitCallback")
+      .asFunction<
+          jni.JniResult Function(
+              ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>)>();
+
+  /// from: public androidx.emoji2.text.EmojiCompat.Config unregisterInitCallback(androidx.emoji2.text.EmojiCompat.InitCallback initCallback)
+  /// The returned object must be deleted after use, by calling the `delete` method.
+  ///
+  /// Unregisters a callback that was added before.
+  ///@param initCallback the initialization callback to be removed, cannot be {@code null}
+  ///@return EmojiCompat.Config instance
+  EmojiCompat_Config unregisterInitCallback(
+          EmojiCompat_InitCallback initCallback) =>
+      const $EmojiCompat_ConfigType().fromRef(
+          _unregisterInitCallback(reference, initCallback.reference).object);
+
+  static final _setReplaceAll = jniLookup<
+          ffi.NativeFunction<
+              jni.JniResult Function(ffi.Pointer<ffi.Void>,
+                  ffi.Uint8)>>("EmojiCompat_Config__setReplaceAll")
+      .asFunction<jni.JniResult Function(ffi.Pointer<ffi.Void>, int)>();
+
+  /// from: public androidx.emoji2.text.EmojiCompat.Config setReplaceAll(boolean replaceAll)
+  /// The returned object must be deleted after use, by calling the `delete` method.
+  ///
+  /// Determines whether EmojiCompat should replace all the emojis it finds with the
+  /// EmojiSpans. By default EmojiCompat tries its best to understand if the system already
+  /// can render an emoji and do not replace those emojis.
+  ///@param replaceAll replace all emojis found with EmojiSpans
+  ///@return EmojiCompat.Config instance
+  EmojiCompat_Config setReplaceAll(bool replaceAll) =>
+      const $EmojiCompat_ConfigType()
+          .fromRef(_setReplaceAll(reference, replaceAll ? 1 : 0).object);
+
+  static final _setUseEmojiAsDefaultStyle = jniLookup<
+          ffi.NativeFunction<
+              jni.JniResult Function(ffi.Pointer<ffi.Void>,
+                  ffi.Uint8)>>("EmojiCompat_Config__setUseEmojiAsDefaultStyle")
+      .asFunction<jni.JniResult Function(ffi.Pointer<ffi.Void>, int)>();
+
+  /// from: public androidx.emoji2.text.EmojiCompat.Config setUseEmojiAsDefaultStyle(boolean useEmojiAsDefaultStyle)
+  /// The returned object must be deleted after use, by calling the `delete` method.
+  ///
+  /// Determines whether EmojiCompat should use the emoji presentation style for emojis
+  /// that have text style as default. By default, the text style would be used, unless these
+  /// are followed by the U+FE0F variation selector.
+  /// Details about emoji presentation and text presentation styles can be found here:
+  /// http://unicode.org/reports/tr51/\#Presentation_Style
+  /// If useEmojiAsDefaultStyle is true, the emoji presentation style will be used for all
+  /// emojis, including potentially unexpected ones (such as digits or other keycap emojis). If
+  /// this is not the expected behaviour, method
+  /// \#setUseEmojiAsDefaultStyle(boolean, List) can be used to specify the
+  /// exception emojis that should be still presented as text style.
+  ///@param useEmojiAsDefaultStyle whether to use the emoji style presentation for all emojis
+  ///                               that would be presented as text style by default
+  EmojiCompat_Config setUseEmojiAsDefaultStyle(bool useEmojiAsDefaultStyle) =>
+      const $EmojiCompat_ConfigType().fromRef(
+          _setUseEmojiAsDefaultStyle(reference, useEmojiAsDefaultStyle ? 1 : 0)
+              .object);
+
+  static final _setUseEmojiAsDefaultStyle1 = jniLookup<
+              ffi.NativeFunction<
+                  jni.JniResult Function(ffi.Pointer<ffi.Void>, ffi.Uint8,
+                      ffi.Pointer<ffi.Void>)>>(
+          "EmojiCompat_Config__setUseEmojiAsDefaultStyle1")
+      .asFunction<
+          jni.JniResult Function(
+              ffi.Pointer<ffi.Void>, int, ffi.Pointer<ffi.Void>)>();
+
+  /// from: public androidx.emoji2.text.EmojiCompat.Config setUseEmojiAsDefaultStyle(boolean useEmojiAsDefaultStyle, java.util.List<java.lang.Integer> emojiAsDefaultStyleExceptions)
+  /// The returned object must be deleted after use, by calling the `delete` method.
+  ///
+  /// @see \#setUseEmojiAsDefaultStyle(boolean)
+  ///@param emojiAsDefaultStyleExceptions Contains the exception emojis which will be still
+  ///                                      presented as text style even if the
+  ///                                      useEmojiAsDefaultStyle flag is set to {@code true}.
+  ///                                      This list will be ignored if useEmojiAsDefaultStyle
+  ///                                      is {@code false}. Note that emojis with default
+  ///                                      emoji style presentation will remain emoji style
+  ///                                      regardless the value of useEmojiAsDefaultStyle or
+  ///                                      whether they are included in the exceptions list or
+  ///                                      not. When no exception is wanted, the method
+  ///                                      \#setUseEmojiAsDefaultStyle(boolean) should
+  ///                                      be used instead.
+  EmojiCompat_Config setUseEmojiAsDefaultStyle1(bool useEmojiAsDefaultStyle,
+          jni.JObject emojiAsDefaultStyleExceptions) =>
+      const $EmojiCompat_ConfigType().fromRef(_setUseEmojiAsDefaultStyle1(
+              reference,
+              useEmojiAsDefaultStyle ? 1 : 0,
+              emojiAsDefaultStyleExceptions.reference)
+          .object);
+
+  static final _setEmojiSpanIndicatorEnabled = jniLookup<
+              ffi.NativeFunction<
+                  jni.JniResult Function(ffi.Pointer<ffi.Void>, ffi.Uint8)>>(
+          "EmojiCompat_Config__setEmojiSpanIndicatorEnabled")
+      .asFunction<jni.JniResult Function(ffi.Pointer<ffi.Void>, int)>();
+
+  /// from: public androidx.emoji2.text.EmojiCompat.Config setEmojiSpanIndicatorEnabled(boolean emojiSpanIndicatorEnabled)
+  /// The returned object must be deleted after use, by calling the `delete` method.
+  ///
+  /// Determines whether a background will be drawn for the emojis that are found and
+  /// replaced by EmojiCompat. Should be used only for debugging purposes. The indicator color
+  /// can be set using \#setEmojiSpanIndicatorColor(int).
+  ///@param emojiSpanIndicatorEnabled when {@code true} a background is drawn for each emoji
+  ///                                  that is replaced
+  EmojiCompat_Config setEmojiSpanIndicatorEnabled(
+          bool emojiSpanIndicatorEnabled) =>
+      const $EmojiCompat_ConfigType().fromRef(_setEmojiSpanIndicatorEnabled(
+              reference, emojiSpanIndicatorEnabled ? 1 : 0)
+          .object);
+
+  static final _setEmojiSpanIndicatorColor = jniLookup<
+          ffi.NativeFunction<
+              jni.JniResult Function(ffi.Pointer<ffi.Void>,
+                  ffi.Int32)>>("EmojiCompat_Config__setEmojiSpanIndicatorColor")
+      .asFunction<jni.JniResult Function(ffi.Pointer<ffi.Void>, int)>();
+
+  /// from: public androidx.emoji2.text.EmojiCompat.Config setEmojiSpanIndicatorColor(int color)
+  /// The returned object must be deleted after use, by calling the `delete` method.
+  ///
+  /// Sets the color used as emoji span indicator. The default value is
+  /// Color\#GREEN Color.GREEN.
+  ///@see \#setEmojiSpanIndicatorEnabled(boolean)
+  EmojiCompat_Config setEmojiSpanIndicatorColor(int color) =>
+      const $EmojiCompat_ConfigType()
+          .fromRef(_setEmojiSpanIndicatorColor(reference, color).object);
+
+  static final _setMetadataLoadStrategy = jniLookup<
+          ffi.NativeFunction<
+              jni.JniResult Function(ffi.Pointer<ffi.Void>,
+                  ffi.Int32)>>("EmojiCompat_Config__setMetadataLoadStrategy")
+      .asFunction<jni.JniResult Function(ffi.Pointer<ffi.Void>, int)>();
+
+  /// from: public androidx.emoji2.text.EmojiCompat.Config setMetadataLoadStrategy(int strategy)
+  /// The returned object must be deleted after use, by calling the `delete` method.
+  ///
+  /// Determines the strategy to start loading the metadata. By default EmojiCompat
+  /// will start loading the metadata during EmojiCompat\#init(Config). When set to
+  /// EmojiCompat\#LOAD_STRATEGY_MANUAL, you should call EmojiCompat\#load() to
+  /// initiate metadata loading.
+  /// <p/>
+  /// Default implementations of EmojiCompat.MetadataRepoLoader start a thread
+  /// during their EmojiCompat.MetadataRepoLoader\#load functions. Just instantiating
+  /// and starting a thread might take time especially in older devices. Since
+  /// EmojiCompat\#init(Config) has to be called before any EmojiCompat widgets are
+  /// inflated, this results in time spent either on your Application.onCreate or Activity
+  /// .onCreate. If you'd like to gain more control on when to start loading the metadata
+  /// and be able to call EmojiCompat\#init(Config) with absolute minimum time cost you
+  /// can use EmojiCompat\#LOAD_STRATEGY_MANUAL.
+  /// <p/>
+  /// When set to EmojiCompat\#LOAD_STRATEGY_MANUAL, EmojiCompat will wait
+  /// for \#load() to be called by the developer in order to start loading metadata,
+  /// therefore you should call EmojiCompat\#load() to initiate metadata loading.
+  /// \#load() can be called from any thread.
+  /// <pre>
+  /// EmojiCompat.Config config = new FontRequestEmojiCompatConfig(context, fontRequest)
+  ///         .setMetadataLoadStrategy(EmojiCompat.LOAD_STRATEGY_MANUAL);
+  ///
+  /// // EmojiCompat will not start loading metadata and MetadataRepoLoader\#load(...)
+  /// // will not be called
+  /// EmojiCompat.init(config);
+  ///
+  /// // At any time (i.e. idle time or executorService is ready)
+  /// // call EmojiCompat\#load() to start loading metadata.
+  /// executorService.execute(() -> EmojiCompat.get().load());
+  /// </pre>
+  ///@param strategy one of EmojiCompat\#LOAD_STRATEGY_DEFAULT,
+  ///                  EmojiCompat\#LOAD_STRATEGY_MANUAL
+  EmojiCompat_Config setMetadataLoadStrategy(int strategy) =>
+      const $EmojiCompat_ConfigType()
+          .fromRef(_setMetadataLoadStrategy(reference, strategy).object);
+
+  static final _setSpanFactory = jniLookup<
+          ffi.NativeFunction<
+              jni.JniResult Function(ffi.Pointer<ffi.Void>,
+                  ffi.Pointer<ffi.Void>)>>("EmojiCompat_Config__setSpanFactory")
+      .asFunction<
+          jni.JniResult Function(
+              ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>)>();
+
+  /// from: public androidx.emoji2.text.EmojiCompat.Config setSpanFactory(androidx.emoji2.text.EmojiCompat.SpanFactory factory)
+  /// The returned object must be deleted after use, by calling the `delete` method.
+  ///
+  /// Set the span factory used to actually draw emoji replacements.
+  ///@param factory custum span factory that can draw the emoji replacements
+  ///@return this
+  EmojiCompat_Config setSpanFactory(EmojiCompat_SpanFactory factory0) =>
+      const $EmojiCompat_ConfigType()
+          .fromRef(_setSpanFactory(reference, factory0.reference).object);
+
+  static final _setGlyphChecker = jniLookup<
+              ffi.NativeFunction<
+                  jni.JniResult Function(
+                      ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>)>>(
+          "EmojiCompat_Config__setGlyphChecker")
+      .asFunction<
+          jni.JniResult Function(
+              ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>)>();
+
+  /// from: public androidx.emoji2.text.EmojiCompat.Config setGlyphChecker(androidx.emoji2.text.EmojiCompat.GlyphChecker glyphChecker)
+  /// The returned object must be deleted after use, by calling the `delete` method.
+  ///
+  /// The interface that is used by EmojiCompat in order to check if a given emoji can be
+  /// rendered by the system.
+  ///@param glyphChecker GlyphChecker instance to be used.
+  EmojiCompat_Config setGlyphChecker(EmojiCompat_GlyphChecker glyphChecker) =>
+      const $EmojiCompat_ConfigType()
+          .fromRef(_setGlyphChecker(reference, glyphChecker.reference).object);
+
+  static final _getMetadataRepoLoader = jniLookup<
+              ffi.NativeFunction<
+                  jni.JniResult Function(ffi.Pointer<ffi.Void>)>>(
+          "EmojiCompat_Config__getMetadataRepoLoader")
+      .asFunction<jni.JniResult Function(ffi.Pointer<ffi.Void>)>();
+
+  /// from: protected final androidx.emoji2.text.EmojiCompat.MetadataRepoLoader getMetadataRepoLoader()
+  /// The returned object must be deleted after use, by calling the `delete` method.
+  ///
+  /// Returns the MetadataRepoLoader.
+  EmojiCompat_MetadataRepoLoader getMetadataRepoLoader() =>
+      const $EmojiCompat_MetadataRepoLoaderType()
+          .fromRef(_getMetadataRepoLoader(reference).object);
+}
+
+class $EmojiCompat_ConfigType extends jni.JObjType<EmojiCompat_Config> {
+  const $EmojiCompat_ConfigType();
+
+  @override
+  String get signature => r"Landroidx/emoji2/text/EmojiCompat$Config;";
+
+  @override
+  EmojiCompat_Config fromRef(jni.JObjectPtr ref) =>
+      EmojiCompat_Config.fromRef(ref);
+}
+
+/// from: androidx.emoji2.text.EmojiCompat$MetadataRepoLoaderCallback
+///
+/// Callback to inform EmojiCompat about the state of the metadata load. Passed to
+/// MetadataRepoLoader during MetadataRepoLoader\#load(MetadataRepoLoaderCallback) call.
+class EmojiCompat_MetadataRepoLoaderCallback extends jni.JObject {
+  late final jni.JObjType? _$type;
+  @override
+  jni.JObjType get $type => _$type ??= type;
+
+  EmojiCompat_MetadataRepoLoaderCallback.fromRef(
+    jni.JObjectPtr ref,
+  ) : super.fromRef(ref);
+
+  /// The type which includes information such as the signature of this class.
+  static const type = $EmojiCompat_MetadataRepoLoaderCallbackType();
+  static final _ctor = jniLookup<ffi.NativeFunction<jni.JniResult Function()>>(
+          "EmojiCompat_MetadataRepoLoaderCallback__ctor")
+      .asFunction<jni.JniResult Function()>();
+
+  /// from: public void <init>()
+  /// The returned object must be deleted after use, by calling the `delete` method.
+  EmojiCompat_MetadataRepoLoaderCallback() : super.fromRef(_ctor().object);
+
+  static final _onLoaded = jniLookup<
+              ffi.NativeFunction<
+                  jni.JniResult Function(
+                      ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>)>>(
+          "EmojiCompat_MetadataRepoLoaderCallback__onLoaded")
+      .asFunction<
+          jni.JniResult Function(
+              ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>)>();
+
+  /// from: public abstract void onLoaded(androidx.emoji2.text.MetadataRepo metadataRepo)
+  ///
+  /// Called by MetadataRepoLoader when metadata is loaded successfully.
+  ///@param metadataRepo MetadataRepo instance, cannot be {@code null}
+  void onLoaded(jni.JObject metadataRepo) =>
+      _onLoaded(reference, metadataRepo.reference).check();
+
+  static final _onFailed = jniLookup<
+              ffi.NativeFunction<
+                  jni.JniResult Function(
+                      ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>)>>(
+          "EmojiCompat_MetadataRepoLoaderCallback__onFailed")
+      .asFunction<
+          jni.JniResult Function(
+              ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>)>();
+
+  /// from: public abstract void onFailed(java.lang.Throwable throwable)
+  ///
+  /// Called by MetadataRepoLoader if an error occurs while loading the metadata.
+  ///@param throwable the exception that caused the failure, {@code nullable}
+  void onFailed(jni.JObject throwable) =>
+      _onFailed(reference, throwable.reference).check();
+}
+
+class $EmojiCompat_MetadataRepoLoaderCallbackType
+    extends jni.JObjType<EmojiCompat_MetadataRepoLoaderCallback> {
+  const $EmojiCompat_MetadataRepoLoaderCallbackType();
+
+  @override
+  String get signature =>
+      r"Landroidx/emoji2/text/EmojiCompat$MetadataRepoLoaderCallback;";
+
+  @override
+  EmojiCompat_MetadataRepoLoaderCallback fromRef(jni.JObjectPtr ref) =>
+      EmojiCompat_MetadataRepoLoaderCallback.fromRef(ref);
+}
+
+/// from: androidx.emoji2.text.EmojiCompat$GlyphChecker
+///
+/// Interface to check if a given emoji exists on the system.
+class EmojiCompat_GlyphChecker extends jni.JObject {
+  late final jni.JObjType? _$type;
+  @override
+  jni.JObjType get $type => _$type ??= type;
+
+  EmojiCompat_GlyphChecker.fromRef(
+    jni.JObjectPtr ref,
+  ) : super.fromRef(ref);
+
+  /// The type which includes information such as the signature of this class.
+  static const type = $EmojiCompat_GlyphCheckerType();
+  static final _hasGlyph = jniLookup<
+          ffi.NativeFunction<
+              jni.JniResult Function(
+                  ffi.Pointer<ffi.Void>,
+                  ffi.Pointer<ffi.Void>,
+                  ffi.Int32,
+                  ffi.Int32,
+                  ffi.Int32)>>("EmojiCompat_GlyphChecker__hasGlyph")
+      .asFunction<
+          jni.JniResult Function(
+              ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>, int, int, int)>();
+
+  /// from: public abstract boolean hasGlyph(java.lang.CharSequence charSequence, int start, int end, int sdkAdded)
+  ///
+  /// Return {@code true} if the emoji that is in {@code charSequence} between
+  /// {@code start}(inclusive) and {@code end}(exclusive) can be rendered on the system
+  /// using the default Typeface.
+  ///
+  /// This function is called after an emoji is identified in the given {@code charSequence}
+  /// and EmojiCompat wants to know if that emoji can be rendered on the system. The result
+  /// of this call will be cached and the same emoji sequence won't be asked for the same
+  /// EmojiCompat instance.
+  ///
+  /// When the function returns {@code true}, it will mean that the system can render the
+  /// emoji. In that case if Config\#setReplaceAll is set to {@code false}, then no
+  /// EmojiSpan will be added in the final emoji processing result.
+  ///
+  /// When the function returns {@code false}, it will mean that the system cannot render
+  /// the given emoji, therefore an EmojiSpan will be added to the final emoji
+  /// processing result.
+  ///
+  /// The default implementation of this class uses
+  /// androidx.core.graphics.PaintCompat\#hasGlyph(Paint, String) function to check
+  /// if the emoji can be rendered on the system. This is required even if EmojiCompat
+  /// knows about the SDK Version that the emoji was added on AOSP. Just the {@code sdkAdded}
+  /// information is not enough to reliably decide if emoji can be rendered since this
+  /// information may not be consistent across all the OEMs and all the Android versions.
+  ///
+  /// With this interface you can apply your own heuristics to check if the emoji can be
+  /// rendered on the system. For example, if you'd like to rely on the {@code sdkAdded}
+  /// information, and some predefined OEMs, it is possible to write the following code
+  /// snippet.
+  ///
+  /// {@sample frameworks/support/samples/SupportEmojiDemos/src/main/java/com/example/android/support/text/emoji/sample/GlyphCheckerSample.java glyphchecker}
+  ///@param charSequence the CharSequence that is being processed
+  ///@param start the inclusive starting offset for the emoji in the {@code charSequence}
+  ///@param end the exclusive end offset for the emoji in the {@code charSequence}
+  ///@param sdkAdded the API version that the emoji was added in AOSP
+  ///@return true if the given sequence can be rendered as a single glyph, otherwise false.
+  bool hasGlyph(jni.JObject charSequence, int start, int end, int sdkAdded) =>
+      _hasGlyph(reference, charSequence.reference, start, end, sdkAdded)
+          .boolean;
+}
+
+class $EmojiCompat_GlyphCheckerType
+    extends jni.JObjType<EmojiCompat_GlyphChecker> {
+  const $EmojiCompat_GlyphCheckerType();
+
+  @override
+  String get signature => r"Landroidx/emoji2/text/EmojiCompat$GlyphChecker;";
+
+  @override
+  EmojiCompat_GlyphChecker fromRef(jni.JObjectPtr ref) =>
+      EmojiCompat_GlyphChecker.fromRef(ref);
+}
+
+/// from: androidx.emoji2.text.EmojiCompat$MetadataRepoLoader
+///
+/// Interface to load emoji metadata.
+class EmojiCompat_MetadataRepoLoader extends jni.JObject {
+  late final jni.JObjType? _$type;
+  @override
+  jni.JObjType get $type => _$type ??= type;
+
+  EmojiCompat_MetadataRepoLoader.fromRef(
+    jni.JObjectPtr ref,
+  ) : super.fromRef(ref);
+
+  /// The type which includes information such as the signature of this class.
+  static const type = $EmojiCompat_MetadataRepoLoaderType();
+  static final _load = jniLookup<
+              ffi.NativeFunction<
+                  jni.JniResult Function(
+                      ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>)>>(
+          "EmojiCompat_MetadataRepoLoader__load")
+      .asFunction<
+          jni.JniResult Function(
+              ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>)>();
+
+  /// from: public abstract void load(androidx.emoji2.text.EmojiCompat.MetadataRepoLoaderCallback loaderCallback)
+  ///
+  /// Start loading the metadata. When the loading operation is finished MetadataRepoLoaderCallback\#onLoaded(MetadataRepo) or
+  /// MetadataRepoLoaderCallback\#onFailed(Throwable) should be called. When used on
+  /// devices running API 18 or below, this function is never called.
+  ///@param loaderCallback callback to signal the loading state
+  void load(EmojiCompat_MetadataRepoLoaderCallback loaderCallback) =>
+      _load(reference, loaderCallback.reference).check();
+}
+
+class $EmojiCompat_MetadataRepoLoaderType
+    extends jni.JObjType<EmojiCompat_MetadataRepoLoader> {
+  const $EmojiCompat_MetadataRepoLoaderType();
+
+  @override
+  String get signature =>
+      r"Landroidx/emoji2/text/EmojiCompat$MetadataRepoLoader;";
+
+  @override
+  EmojiCompat_MetadataRepoLoader fromRef(jni.JObjectPtr ref) =>
+      EmojiCompat_MetadataRepoLoader.fromRef(ref);
+}
+
+/// from: androidx.emoji2.text.EmojiCompat$InitCallback
+///
+/// Listener class for the initialization of the EmojiCompat.
+class EmojiCompat_InitCallback extends jni.JObject {
+  late final jni.JObjType? _$type;
+  @override
+  jni.JObjType get $type => _$type ??= type;
+
+  EmojiCompat_InitCallback.fromRef(
+    jni.JObjectPtr ref,
+  ) : super.fromRef(ref);
+
+  /// The type which includes information such as the signature of this class.
+  static const type = $EmojiCompat_InitCallbackType();
+  static final _ctor = jniLookup<ffi.NativeFunction<jni.JniResult Function()>>(
+          "EmojiCompat_InitCallback__ctor")
+      .asFunction<jni.JniResult Function()>();
+
+  /// from: public void <init>()
+  /// The returned object must be deleted after use, by calling the `delete` method.
+  EmojiCompat_InitCallback() : super.fromRef(_ctor().object);
+
+  static final _onInitialized = jniLookup<
+              ffi.NativeFunction<
+                  jni.JniResult Function(ffi.Pointer<ffi.Void>)>>(
+          "EmojiCompat_InitCallback__onInitialized")
+      .asFunction<jni.JniResult Function(ffi.Pointer<ffi.Void>)>();
+
+  /// from: public void onInitialized()
+  ///
+  /// Called when EmojiCompat is initialized and the emoji data is loaded. When used on devices
+  /// running API 18 or below, this function is always called.
+  void onInitialized() => _onInitialized(reference).check();
+
+  static final _onFailed = jniLookup<
+          ffi.NativeFunction<
+              jni.JniResult Function(ffi.Pointer<ffi.Void>,
+                  ffi.Pointer<ffi.Void>)>>("EmojiCompat_InitCallback__onFailed")
+      .asFunction<
+          jni.JniResult Function(
+              ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>)>();
+
+  /// from: public void onFailed(java.lang.Throwable throwable)
+  ///
+  /// Called when an unrecoverable error occurs during EmojiCompat initialization. When used on
+  /// devices running API 18 or below, this function is never called.
+  void onFailed(jni.JObject throwable) =>
+      _onFailed(reference, throwable.reference).check();
+}
+
+class $EmojiCompat_InitCallbackType
+    extends jni.JObjType<EmojiCompat_InitCallback> {
+  const $EmojiCompat_InitCallbackType();
+
+  @override
+  String get signature => r"Landroidx/emoji2/text/EmojiCompat$InitCallback;";
+
+  @override
+  EmojiCompat_InitCallback fromRef(jni.JObjectPtr ref) =>
+      EmojiCompat_InitCallback.fromRef(ref);
+}
+
+/// from: androidx.emoji2.text.EmojiCompat$DefaultSpanFactory
+///
+/// @hide
+class EmojiCompat_DefaultSpanFactory extends jni.JObject {
+  late final jni.JObjType? _$type;
+  @override
+  jni.JObjType get $type => _$type ??= type;
+
+  EmojiCompat_DefaultSpanFactory.fromRef(
+    jni.JObjectPtr ref,
+  ) : super.fromRef(ref);
+
+  /// The type which includes information such as the signature of this class.
+  static const type = $EmojiCompat_DefaultSpanFactoryType();
+  static final _ctor = jniLookup<ffi.NativeFunction<jni.JniResult Function()>>(
+          "EmojiCompat_DefaultSpanFactory__ctor")
+      .asFunction<jni.JniResult Function()>();
+
+  /// from: public void <init>()
+  /// The returned object must be deleted after use, by calling the `delete` method.
+  EmojiCompat_DefaultSpanFactory() : super.fromRef(_ctor().object);
+
+  static final _createSpan = jniLookup<
+              ffi.NativeFunction<
+                  jni.JniResult Function(
+                      ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>)>>(
+          "EmojiCompat_DefaultSpanFactory__createSpan")
+      .asFunction<
+          jni.JniResult Function(
+              ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>)>();
+
+  /// from: public androidx.emoji2.text.EmojiSpan createSpan(androidx.emoji2.text.TypefaceEmojiRasterizer rasterizer)
+  /// The returned object must be deleted after use, by calling the `delete` method.
+  ///
+  /// Returns a TypefaceEmojiSpan.
+  ///@param rasterizer TypefaceEmojiRasterizer instance, which can draw the emoji onto a
+  ///                   Canvas.
+  ///@return TypefaceEmojiSpan
+  jni.JObject createSpan(jni.JObject rasterizer) => const jni.JObjectType()
+      .fromRef(_createSpan(reference, rasterizer.reference).object);
+}
+
+class $EmojiCompat_DefaultSpanFactoryType
+    extends jni.JObjType<EmojiCompat_DefaultSpanFactory> {
+  const $EmojiCompat_DefaultSpanFactoryType();
+
+  @override
+  String get signature =>
+      r"Landroidx/emoji2/text/EmojiCompat$DefaultSpanFactory;";
+
+  @override
+  EmojiCompat_DefaultSpanFactory fromRef(jni.JObjectPtr ref) =>
+      EmojiCompat_DefaultSpanFactory.fromRef(ref);
+}
+
+/// from: androidx.emoji2.text.EmojiCompat$SpanFactory
+///
+/// Factory class that creates the EmojiSpans.
+///
+/// By default it creates TypefaceEmojiSpan.
+///
+/// Apps should use this only if they want to control the drawing of EmojiSpans for non-standard
+/// emoji display (for example, resizing or repositioning emoji).
+class EmojiCompat_SpanFactory extends jni.JObject {
+  late final jni.JObjType? _$type;
+  @override
+  jni.JObjType get $type => _$type ??= type;
+
+  EmojiCompat_SpanFactory.fromRef(
+    jni.JObjectPtr ref,
+  ) : super.fromRef(ref);
+
+  /// The type which includes information such as the signature of this class.
+  static const type = $EmojiCompat_SpanFactoryType();
+  static final _createSpan = jniLookup<
+              ffi.NativeFunction<
+                  jni.JniResult Function(
+                      ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>)>>(
+          "EmojiCompat_SpanFactory__createSpan")
+      .asFunction<
+          jni.JniResult Function(
+              ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>)>();
+
+  /// from: public abstract androidx.emoji2.text.EmojiSpan createSpan(androidx.emoji2.text.TypefaceEmojiRasterizer rasterizer)
+  /// The returned object must be deleted after use, by calling the `delete` method.
+  ///
+  /// Create EmojiSpan instance.
+  ///@param rasterizer TypefaceEmojiRasterizer instance, which can draw the emoji onto a
+  ///                   Canvas.
+  ///@return EmojiSpan instance that can use TypefaceEmojiRasterizer to draw emoji.
+  jni.JObject createSpan(jni.JObject rasterizer) => const jni.JObjectType()
+      .fromRef(_createSpan(reference, rasterizer.reference).object);
+}
+
+class $EmojiCompat_SpanFactoryType
+    extends jni.JObjType<EmojiCompat_SpanFactory> {
+  const $EmojiCompat_SpanFactoryType();
+
+  @override
+  String get signature => r"Landroidx/emoji2/text/EmojiCompat$SpanFactory;";
+
+  @override
+  EmojiCompat_SpanFactory fromRef(jni.JObjectPtr ref) =>
+      EmojiCompat_SpanFactory.fromRef(ref);
+}
+
+/// from: androidx.emoji2.text.DefaultEmojiCompatConfig
+///
+/// The default config will use downloadable fonts to fetch the emoji compat font file.
+///
+/// It will automatically fetch the emoji compat font from a {@code ContentProvider} that is
+/// installed on the devices system image, if present.
+///
+///
+/// You should use this if you want the default emoji font from a system installed
+/// downloadable fonts provider. This is the recommended behavior for all applications unless
+/// they install a custom emoji font.
+///
+///
+/// You may need to specialize the configuration beyond this default config in some
+/// situations:
+///
+/// <ul>
+///  <li>If you are trying to install a custom emoji font through downloadable fonts use
+///  FontRequestEmojiCompatConfig instead of this method.</li>
+///  <li>If you're trying to bundle an emoji font with your APK use {@code
+///  BundledEmojiCompatConfig} in the {@code emoji2-bundled} artifact.</li>
+///  <li>If you are building an APK that will be installed on devices that won't have a
+///  downloadable fonts provider, use {@code BundledEmojiCompatConfig}.</li>
+/// </ul>
+///
+/// The downloadable font provider used by {@code DefaultEmojiCompatConfig} always satisfies
+/// the following contract:
+///
+/// <ol>
+///  <li>It <i>MUST</i> provide an intent filter for {@code androidx.content.action.LOAD_EMOJI_FONT}.
+///  </li>
+///  <li>It <i>MUST</i> respond to the query {@code emojicompat-emoji-font} with a valid emoji compat
+///  font file including metadata.</li>
+///  <li>It <i>MUST</i> provide fonts via the same contract as downloadable fonts.</li>
+///  <li>It <i>MUST</i> be installed in the system image.</li>
+/// </ol>
+class DefaultEmojiCompatConfig extends jni.JObject {
+  late final jni.JObjType? _$type;
+  @override
+  jni.JObjType get $type => _$type ??= type;
+
+  DefaultEmojiCompatConfig.fromRef(
+    jni.JObjectPtr ref,
+  ) : super.fromRef(ref);
+
+  /// The type which includes information such as the signature of this class.
+  static const type = $DefaultEmojiCompatConfigType();
+  static final _create = jniLookup<
+          ffi.NativeFunction<
+              jni.JniResult Function(
+                  ffi.Pointer<ffi.Void>)>>("DefaultEmojiCompatConfig__create")
+      .asFunction<jni.JniResult Function(ffi.Pointer<ffi.Void>)>();
+
+  /// from: static public androidx.emoji2.text.FontRequestEmojiCompatConfig create(android.content.Context context)
+  /// The returned object must be deleted after use, by calling the `delete` method.
+  ///
+  /// Get the default emoji compat config for this device.
+  ///
+  /// You may further configure the returned config before passing it to EmojiCompat\#init.
+  ///
+  /// Each call to this method will return a new EmojiCompat.Config, so changes to the returned
+  /// object will not modify future return values.
+  ///@param context context for lookup
+  ///@return A valid config for downloading the emoji compat font, or null if no font provider
+  /// could be found.
+  static jni.JObject create(jni.JObject context) =>
+      const jni.JObjectType().fromRef(_create(context.reference).object);
+}
+
+class $DefaultEmojiCompatConfigType
+    extends jni.JObjType<DefaultEmojiCompatConfig> {
+  const $DefaultEmojiCompatConfigType();
+
+  @override
+  String get signature => r"Landroidx/emoji2/text/DefaultEmojiCompatConfig;";
+
+  @override
+  DefaultEmojiCompatConfig fromRef(jni.JObjectPtr ref) =>
+      DefaultEmojiCompatConfig.fromRef(ref);
+}
+
+/// from: androidx.emoji2.text.DefaultEmojiCompatConfig$DefaultEmojiCompatConfigHelper_API28
+///
+/// Helper to lookup signatures in package manager > API 28
+///@hide
+class DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28
+    extends DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19 {
+  late final jni.JObjType? _$type;
+  @override
+  jni.JObjType get $type => _$type ??= type;
+
+  DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28.fromRef(
+    jni.JObjectPtr ref,
+  ) : super.fromRef(ref);
+
+  /// The type which includes information such as the signature of this class.
+  static const type =
+      $DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28Type();
+  static final _ctor = jniLookup<ffi.NativeFunction<jni.JniResult Function()>>(
+          "DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28__ctor")
+      .asFunction<jni.JniResult Function()>();
+
+  /// from: public void <init>()
+  /// The returned object must be deleted after use, by calling the `delete` method.
+  DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28()
+      : super.fromRef(_ctor().object);
+
+  static final _getSigningSignatures1 = jniLookup<
+              ffi.NativeFunction<
+                  jni.JniResult Function(ffi.Pointer<ffi.Void>,
+                      ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>)>>(
+          "DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28__getSigningSignatures1")
+      .asFunction<
+          jni.JniResult Function(ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>,
+              ffi.Pointer<ffi.Void>)>();
+
+  /// from: public android.content.pm.Signature[] getSigningSignatures(android.content.pm.PackageManager packageManager, java.lang.String providerPackage)
+  /// The returned object must be deleted after use, by calling the `delete` method.
+  jni.JArray<jni.JObject> getSigningSignatures1(
+          jni.JObject packageManager, jni.JString providerPackage) =>
+      const jni.JArrayType(jni.JObjectType()).fromRef(_getSigningSignatures1(
+              reference, packageManager.reference, providerPackage.reference)
+          .object);
+}
+
+class $DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28Type
+    extends jni.JObjType<
+        DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28> {
+  const $DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28Type();
+
+  @override
+  String get signature =>
+      r"Landroidx/emoji2/text/DefaultEmojiCompatConfig$DefaultEmojiCompatConfigHelper_API28;";
+
+  @override
+  DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28 fromRef(
+          jni.JObjectPtr ref) =>
+      DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28.fromRef(
+          ref);
+}
+
+/// from: androidx.emoji2.text.DefaultEmojiCompatConfig$DefaultEmojiCompatConfigHelper_API19
+///
+/// Actually do lookups > API 19
+///@hide
+class DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19
+    extends DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper {
+  late final jni.JObjType? _$type;
+  @override
+  jni.JObjType get $type => _$type ??= type;
+
+  DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19.fromRef(
+    jni.JObjectPtr ref,
+  ) : super.fromRef(ref);
+
+  /// The type which includes information such as the signature of this class.
+  static const type =
+      $DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19Type();
+  static final _ctor = jniLookup<ffi.NativeFunction<jni.JniResult Function()>>(
+          "DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19__ctor")
+      .asFunction<jni.JniResult Function()>();
+
+  /// from: public void <init>()
+  /// The returned object must be deleted after use, by calling the `delete` method.
+  DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19()
+      : super.fromRef(_ctor().object);
+
+  static final _queryIntentContentProviders = jniLookup<
+              ffi.NativeFunction<
+                  jni.JniResult Function(
+                      ffi.Pointer<ffi.Void>,
+                      ffi.Pointer<ffi.Void>,
+                      ffi.Pointer<ffi.Void>,
+                      ffi.Int32)>>(
+          "DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19__queryIntentContentProviders")
+      .asFunction<
+          jni.JniResult Function(ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>,
+              ffi.Pointer<ffi.Void>, int)>();
+
+  /// from: public java.util.List<android.content.pm.ResolveInfo> queryIntentContentProviders(android.content.pm.PackageManager packageManager, android.content.Intent intent, int flags)
+  /// The returned object must be deleted after use, by calling the `delete` method.
+  jni.JObject queryIntentContentProviders(
+          jni.JObject packageManager, jni.JObject intent, int flags) =>
+      const jni.JObjectType().fromRef(_queryIntentContentProviders(
+              reference, packageManager.reference, intent.reference, flags)
+          .object);
+
+  static final _getProviderInfo = jniLookup<
+              ffi.NativeFunction<
+                  jni.JniResult Function(
+                      ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>)>>(
+          "DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19__getProviderInfo")
+      .asFunction<
+          jni.JniResult Function(
+              ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>)>();
+
+  /// from: public android.content.pm.ProviderInfo getProviderInfo(android.content.pm.ResolveInfo resolveInfo)
+  /// The returned object must be deleted after use, by calling the `delete` method.
+  jni.JObject getProviderInfo(jni.JObject resolveInfo) =>
+      const jni.JObjectType()
+          .fromRef(_getProviderInfo(reference, resolveInfo.reference).object);
+}
+
+class $DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19Type
+    extends jni.JObjType<
+        DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19> {
+  const $DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19Type();
+
+  @override
+  String get signature =>
+      r"Landroidx/emoji2/text/DefaultEmojiCompatConfig$DefaultEmojiCompatConfigHelper_API19;";
+
+  @override
+  DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19 fromRef(
+          jni.JObjectPtr ref) =>
+      DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19.fromRef(
+          ref);
+}
+
+/// from: androidx.emoji2.text.DefaultEmojiCompatConfig$DefaultEmojiCompatConfigHelper
+///
+/// Helper to lookup signatures in package manager.
+///@hide
+class DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper
+    extends jni.JObject {
+  late final jni.JObjType? _$type;
+  @override
+  jni.JObjType get $type => _$type ??= type;
+
+  DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper.fromRef(
+    jni.JObjectPtr ref,
+  ) : super.fromRef(ref);
+
+  /// The type which includes information such as the signature of this class.
+  static const type =
+      $DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelperType();
+  static final _ctor = jniLookup<ffi.NativeFunction<jni.JniResult Function()>>(
+          "DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper__ctor")
+      .asFunction<jni.JniResult Function()>();
+
+  /// from: public void <init>()
+  /// The returned object must be deleted after use, by calling the `delete` method.
+  DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper()
+      : super.fromRef(_ctor().object);
+
+  static final _getSigningSignatures = jniLookup<
+              ffi.NativeFunction<
+                  jni.JniResult Function(ffi.Pointer<ffi.Void>,
+                      ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>)>>(
+          "DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper__getSigningSignatures")
+      .asFunction<
+          jni.JniResult Function(ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>,
+              ffi.Pointer<ffi.Void>)>();
+
+  /// from: public android.content.pm.Signature[] getSigningSignatures(android.content.pm.PackageManager packageManager, java.lang.String providerPackage)
+  /// The returned object must be deleted after use, by calling the `delete` method.
+  ///
+  /// Get the signing signatures for a package in package manager.
+  jni.JArray<jni.JObject> getSigningSignatures(
+          jni.JObject packageManager, jni.JString providerPackage) =>
+      const jni.JArrayType(jni.JObjectType()).fromRef(_getSigningSignatures(
+              reference, packageManager.reference, providerPackage.reference)
+          .object);
+
+  static final _queryIntentContentProviders = jniLookup<
+              ffi.NativeFunction<
+                  jni.JniResult Function(
+                      ffi.Pointer<ffi.Void>,
+                      ffi.Pointer<ffi.Void>,
+                      ffi.Pointer<ffi.Void>,
+                      ffi.Int32)>>(
+          "DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper__queryIntentContentProviders")
+      .asFunction<
+          jni.JniResult Function(ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>,
+              ffi.Pointer<ffi.Void>, int)>();
+
+  /// from: public java.util.List<android.content.pm.ResolveInfo> queryIntentContentProviders(android.content.pm.PackageManager packageManager, android.content.Intent intent, int flags)
+  /// The returned object must be deleted after use, by calling the `delete` method.
+  ///
+  /// Get the content provider by intent.
+  jni.JObject queryIntentContentProviders(
+          jni.JObject packageManager, jni.JObject intent, int flags) =>
+      const jni.JObjectType().fromRef(_queryIntentContentProviders(
+              reference, packageManager.reference, intent.reference, flags)
+          .object);
+
+  static final _getProviderInfo = jniLookup<
+              ffi.NativeFunction<
+                  jni.JniResult Function(
+                      ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>)>>(
+          "DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper__getProviderInfo")
+      .asFunction<
+          jni.JniResult Function(
+              ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>)>();
+
+  /// from: public android.content.pm.ProviderInfo getProviderInfo(android.content.pm.ResolveInfo resolveInfo)
+  /// The returned object must be deleted after use, by calling the `delete` method.
+  ///
+  /// Get a ProviderInfo, if present, from a ResolveInfo
+  ///@param resolveInfo the subject
+  ///@return resolveInfo.providerInfo above API 19
+  jni.JObject getProviderInfo(jni.JObject resolveInfo) =>
+      const jni.JObjectType()
+          .fromRef(_getProviderInfo(reference, resolveInfo.reference).object);
+}
+
+class $DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelperType extends jni
+    .JObjType<DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper> {
+  const $DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelperType();
+
+  @override
+  String get signature =>
+      r"Landroidx/emoji2/text/DefaultEmojiCompatConfig$DefaultEmojiCompatConfigHelper;";
+
+  @override
+  DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper fromRef(
+          jni.JObjectPtr ref) =>
+      DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper.fromRef(ref);
+}
+
+/// from: androidx.emoji2.text.DefaultEmojiCompatConfig$DefaultEmojiCompatConfigFactory
+///
+/// Actual factory for generating default emoji configs, does service locator lookup internally.
+///@see DefaultEmojiCompatConfig\#create
+///@hide
+class DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactory
+    extends jni.JObject {
+  late final jni.JObjType? _$type;
+  @override
+  jni.JObjType get $type => _$type ??= type;
+
+  DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactory.fromRef(
+    jni.JObjectPtr ref,
+  ) : super.fromRef(ref);
+
+  /// The type which includes information such as the signature of this class.
+  static const type =
+      $DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactoryType();
+  static final _ctor = jniLookup<
+              ffi.NativeFunction<
+                  jni.JniResult Function(ffi.Pointer<ffi.Void>)>>(
+          "DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactory__ctor")
+      .asFunction<jni.JniResult Function(ffi.Pointer<ffi.Void>)>();
+
+  /// from: public void <init>(androidx.emoji2.text.DefaultEmojiCompatConfig.DefaultEmojiCompatConfigHelper helper)
+  /// The returned object must be deleted after use, by calling the `delete` method.
+  ///
+  /// @hide
+  DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactory(
+      DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper helper)
+      : super.fromRef(_ctor(helper.reference).object);
+
+  static final _create = jniLookup<
+              ffi.NativeFunction<
+                  jni.JniResult Function(
+                      ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>)>>(
+          "DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactory__create")
+      .asFunction<
+          jni.JniResult Function(
+              ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>)>();
+
+  /// from: public androidx.emoji2.text.EmojiCompat.Config create(android.content.Context context)
+  /// The returned object must be deleted after use, by calling the `delete` method.
+  ///
+  /// @see DefaultEmojiCompatConfig\#create
+  ///@hide
+  EmojiCompat_Config create(jni.JObject context) =>
+      const $EmojiCompat_ConfigType()
+          .fromRef(_create(reference, context.reference).object);
+}
+
+class $DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactoryType extends jni
+    .JObjType<DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactory> {
+  const $DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactoryType();
+
+  @override
+  String get signature =>
+      r"Landroidx/emoji2/text/DefaultEmojiCompatConfig$DefaultEmojiCompatConfigFactory;";
+
+  @override
+  DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactory fromRef(
+          jni.JObjectPtr ref) =>
+      DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactory.fromRef(ref);
+}
+
 /// from: android.os.Build
 class Build extends jni.JObject {
   late final jni.JObjType? _$type;
diff --git a/pkgs/jnigen/example/in_app_java/lib/main.dart b/pkgs/jnigen/example/in_app_java/lib/main.dart
index 61c9d2b..f435428 100644
--- a/pkgs/jnigen/example/in_app_java/lib/main.dart
+++ b/pkgs/jnigen/example/in_app_java/lib/main.dart
@@ -10,15 +10,20 @@
 import 'android_utils.dart';
 
 JObject activity = JObject.fromRef(Jni.getCurrentActivity());
+JObject context = JObject.fromRef(Jni.getCachedApplicationContext());
 
 final hashmap = HashMap.ctor2(JString.type, JString.type);
 
+final emojiCompat = EmojiCompat.get0();
+
 extension IntX on int {
   JString toJString() {
     return toString().toJString();
   }
 }
 
+const sunglassEmoji = "😎";
+
 /// Display device model number and the number of times this was called
 /// as Toast.
 void showToast() {
@@ -26,12 +31,16 @@
       hashmap.getOrDefault("toastCount".toJString(), 0.toJString());
   final newToastCount = (int.parse(toastCount.toDartString()) + 1).toJString();
   hashmap.put("toastCount".toJString(), newToastCount);
+  final emoji = emojiCompat.hasEmojiGlyph(sunglassEmoji.toJString())
+      ? sunglassEmoji
+      : ':cool:';
   final message =
-      '${newToastCount.toDartString()} - ${Build.MODEL.toDartString()}';
+      '${newToastCount.toDartString()} - ${Build.MODEL.toDartString()} $emoji';
   AndroidUtils.showToast(activity, message.toJString(), 0);
 }
 
 void main() {
+  EmojiCompat.init(context);
   runApp(const MyApp());
 }
 
diff --git a/pkgs/jnigen/example/in_app_java/src/android_utils/android_utils.c b/pkgs/jnigen/example/in_app_java/src/android_utils/android_utils.c
index 1a1cb55..65bbd7b 100644
--- a/pkgs/jnigen/example/in_app_java/src/android_utils/android_utils.c
+++ b/pkgs/jnigen/example/in_app_java/src/android_utils/android_utils.c
@@ -37,6 +37,1351 @@
   return (JniResult){.result = {.j = 0}, .exception = check_exception()};
 }
 
+// androidx.emoji2.text.EmojiCompat
+jclass _c_EmojiCompat = NULL;
+
+jmethodID _m_EmojiCompat__init = NULL;
+FFI_PLUGIN_EXPORT
+JniResult EmojiCompat__init(jobject context) {
+  load_env();
+  load_class_gr(&_c_EmojiCompat, "androidx/emoji2/text/EmojiCompat");
+  if (_c_EmojiCompat == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_static_method(
+      _c_EmojiCompat, &_m_EmojiCompat__init, "init",
+      "(Landroid/content/Context;)Landroidx/emoji2/text/EmojiCompat;");
+  if (_m_EmojiCompat__init == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result = (*jniEnv)->CallStaticObjectMethod(
+      jniEnv, _c_EmojiCompat, _m_EmojiCompat__init, context);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
+
+jmethodID _m_EmojiCompat__init1 = NULL;
+FFI_PLUGIN_EXPORT
+JniResult EmojiCompat__init1(jobject context, jobject defaultFactory) {
+  load_env();
+  load_class_gr(&_c_EmojiCompat, "androidx/emoji2/text/EmojiCompat");
+  if (_c_EmojiCompat == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_static_method(_c_EmojiCompat, &_m_EmojiCompat__init1, "init",
+                     "(Landroid/content/Context;Landroidx/emoji2/text/"
+                     "DefaultEmojiCompatConfig$DefaultEmojiCompatConfigFactory;"
+                     ")Landroidx/emoji2/text/EmojiCompat;");
+  if (_m_EmojiCompat__init1 == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result = (*jniEnv)->CallStaticObjectMethod(
+      jniEnv, _c_EmojiCompat, _m_EmojiCompat__init1, context, defaultFactory);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
+
+jmethodID _m_EmojiCompat__init2 = NULL;
+FFI_PLUGIN_EXPORT
+JniResult EmojiCompat__init2(jobject config) {
+  load_env();
+  load_class_gr(&_c_EmojiCompat, "androidx/emoji2/text/EmojiCompat");
+  if (_c_EmojiCompat == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_static_method(_c_EmojiCompat, &_m_EmojiCompat__init2, "init",
+                     "(Landroidx/emoji2/text/EmojiCompat$Config;)Landroidx/"
+                     "emoji2/text/EmojiCompat;");
+  if (_m_EmojiCompat__init2 == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result = (*jniEnv)->CallStaticObjectMethod(
+      jniEnv, _c_EmojiCompat, _m_EmojiCompat__init2, config);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
+
+jmethodID _m_EmojiCompat__isConfigured = NULL;
+FFI_PLUGIN_EXPORT
+JniResult EmojiCompat__isConfigured() {
+  load_env();
+  load_class_gr(&_c_EmojiCompat, "androidx/emoji2/text/EmojiCompat");
+  if (_c_EmojiCompat == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_static_method(_c_EmojiCompat, &_m_EmojiCompat__isConfigured,
+                     "isConfigured", "()Z");
+  if (_m_EmojiCompat__isConfigured == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  uint8_t _result = (*jniEnv)->CallStaticBooleanMethod(
+      jniEnv, _c_EmojiCompat, _m_EmojiCompat__isConfigured);
+  return (JniResult){.result = {.z = _result}, .exception = check_exception()};
+}
+
+jmethodID _m_EmojiCompat__reset = NULL;
+FFI_PLUGIN_EXPORT
+JniResult EmojiCompat__reset(jobject config) {
+  load_env();
+  load_class_gr(&_c_EmojiCompat, "androidx/emoji2/text/EmojiCompat");
+  if (_c_EmojiCompat == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_static_method(_c_EmojiCompat, &_m_EmojiCompat__reset, "reset",
+                     "(Landroidx/emoji2/text/EmojiCompat$Config;)Landroidx/"
+                     "emoji2/text/EmojiCompat;");
+  if (_m_EmojiCompat__reset == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result = (*jniEnv)->CallStaticObjectMethod(
+      jniEnv, _c_EmojiCompat, _m_EmojiCompat__reset, config);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
+
+jmethodID _m_EmojiCompat__reset1 = NULL;
+FFI_PLUGIN_EXPORT
+JniResult EmojiCompat__reset1(jobject emojiCompat) {
+  load_env();
+  load_class_gr(&_c_EmojiCompat, "androidx/emoji2/text/EmojiCompat");
+  if (_c_EmojiCompat == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_static_method(
+      _c_EmojiCompat, &_m_EmojiCompat__reset1, "reset",
+      "(Landroidx/emoji2/text/EmojiCompat;)Landroidx/emoji2/text/EmojiCompat;");
+  if (_m_EmojiCompat__reset1 == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result = (*jniEnv)->CallStaticObjectMethod(
+      jniEnv, _c_EmojiCompat, _m_EmojiCompat__reset1, emojiCompat);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
+
+jmethodID _m_EmojiCompat__skipDefaultConfigurationLookup = NULL;
+FFI_PLUGIN_EXPORT
+JniResult EmojiCompat__skipDefaultConfigurationLookup(uint8_t shouldSkip) {
+  load_env();
+  load_class_gr(&_c_EmojiCompat, "androidx/emoji2/text/EmojiCompat");
+  if (_c_EmojiCompat == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_static_method(_c_EmojiCompat,
+                     &_m_EmojiCompat__skipDefaultConfigurationLookup,
+                     "skipDefaultConfigurationLookup", "(Z)V");
+  if (_m_EmojiCompat__skipDefaultConfigurationLookup == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  (*jniEnv)->CallStaticVoidMethod(
+      jniEnv, _c_EmojiCompat, _m_EmojiCompat__skipDefaultConfigurationLookup,
+      shouldSkip);
+  return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+}
+
+jmethodID _m_EmojiCompat__get0 = NULL;
+FFI_PLUGIN_EXPORT
+JniResult EmojiCompat__get0() {
+  load_env();
+  load_class_gr(&_c_EmojiCompat, "androidx/emoji2/text/EmojiCompat");
+  if (_c_EmojiCompat == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_static_method(_c_EmojiCompat, &_m_EmojiCompat__get0, "get",
+                     "()Landroidx/emoji2/text/EmojiCompat;");
+  if (_m_EmojiCompat__get0 == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result = (*jniEnv)->CallStaticObjectMethod(jniEnv, _c_EmojiCompat,
+                                                      _m_EmojiCompat__get0);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
+
+jmethodID _m_EmojiCompat__load = NULL;
+FFI_PLUGIN_EXPORT
+JniResult EmojiCompat__load(jobject self_) {
+  load_env();
+  load_class_gr(&_c_EmojiCompat, "androidx/emoji2/text/EmojiCompat");
+  if (_c_EmojiCompat == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(_c_EmojiCompat, &_m_EmojiCompat__load, "load", "()V");
+  if (_m_EmojiCompat__load == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_EmojiCompat__load);
+  return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+}
+
+jmethodID _m_EmojiCompat__registerInitCallback = NULL;
+FFI_PLUGIN_EXPORT
+JniResult EmojiCompat__registerInitCallback(jobject self_,
+                                            jobject initCallback) {
+  load_env();
+  load_class_gr(&_c_EmojiCompat, "androidx/emoji2/text/EmojiCompat");
+  if (_c_EmojiCompat == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(_c_EmojiCompat, &_m_EmojiCompat__registerInitCallback,
+              "registerInitCallback",
+              "(Landroidx/emoji2/text/EmojiCompat$InitCallback;)V");
+  if (_m_EmojiCompat__registerInitCallback == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_EmojiCompat__registerInitCallback,
+                            initCallback);
+  return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+}
+
+jmethodID _m_EmojiCompat__unregisterInitCallback = NULL;
+FFI_PLUGIN_EXPORT
+JniResult EmojiCompat__unregisterInitCallback(jobject self_,
+                                              jobject initCallback) {
+  load_env();
+  load_class_gr(&_c_EmojiCompat, "androidx/emoji2/text/EmojiCompat");
+  if (_c_EmojiCompat == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(_c_EmojiCompat, &_m_EmojiCompat__unregisterInitCallback,
+              "unregisterInitCallback",
+              "(Landroidx/emoji2/text/EmojiCompat$InitCallback;)V");
+  if (_m_EmojiCompat__unregisterInitCallback == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  (*jniEnv)->CallVoidMethod(
+      jniEnv, self_, _m_EmojiCompat__unregisterInitCallback, initCallback);
+  return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+}
+
+jmethodID _m_EmojiCompat__getLoadState = NULL;
+FFI_PLUGIN_EXPORT
+JniResult EmojiCompat__getLoadState(jobject self_) {
+  load_env();
+  load_class_gr(&_c_EmojiCompat, "androidx/emoji2/text/EmojiCompat");
+  if (_c_EmojiCompat == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(_c_EmojiCompat, &_m_EmojiCompat__getLoadState, "getLoadState",
+              "()I");
+  if (_m_EmojiCompat__getLoadState == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  int32_t _result =
+      (*jniEnv)->CallIntMethod(jniEnv, self_, _m_EmojiCompat__getLoadState);
+  return (JniResult){.result = {.i = _result}, .exception = check_exception()};
+}
+
+jmethodID _m_EmojiCompat__isEmojiSpanIndicatorEnabled = NULL;
+FFI_PLUGIN_EXPORT
+JniResult EmojiCompat__isEmojiSpanIndicatorEnabled(jobject self_) {
+  load_env();
+  load_class_gr(&_c_EmojiCompat, "androidx/emoji2/text/EmojiCompat");
+  if (_c_EmojiCompat == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(_c_EmojiCompat, &_m_EmojiCompat__isEmojiSpanIndicatorEnabled,
+              "isEmojiSpanIndicatorEnabled", "()Z");
+  if (_m_EmojiCompat__isEmojiSpanIndicatorEnabled == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  uint8_t _result = (*jniEnv)->CallBooleanMethod(
+      jniEnv, self_, _m_EmojiCompat__isEmojiSpanIndicatorEnabled);
+  return (JniResult){.result = {.z = _result}, .exception = check_exception()};
+}
+
+jmethodID _m_EmojiCompat__getEmojiSpanIndicatorColor = NULL;
+FFI_PLUGIN_EXPORT
+JniResult EmojiCompat__getEmojiSpanIndicatorColor(jobject self_) {
+  load_env();
+  load_class_gr(&_c_EmojiCompat, "androidx/emoji2/text/EmojiCompat");
+  if (_c_EmojiCompat == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(_c_EmojiCompat, &_m_EmojiCompat__getEmojiSpanIndicatorColor,
+              "getEmojiSpanIndicatorColor", "()I");
+  if (_m_EmojiCompat__getEmojiSpanIndicatorColor == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  int32_t _result = (*jniEnv)->CallIntMethod(
+      jniEnv, self_, _m_EmojiCompat__getEmojiSpanIndicatorColor);
+  return (JniResult){.result = {.i = _result}, .exception = check_exception()};
+}
+
+jmethodID _m_EmojiCompat__getEmojiStart = NULL;
+FFI_PLUGIN_EXPORT
+JniResult EmojiCompat__getEmojiStart(jobject self_,
+                                     jobject charSequence,
+                                     int32_t offset) {
+  load_env();
+  load_class_gr(&_c_EmojiCompat, "androidx/emoji2/text/EmojiCompat");
+  if (_c_EmojiCompat == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(_c_EmojiCompat, &_m_EmojiCompat__getEmojiStart, "getEmojiStart",
+              "(Ljava/lang/CharSequence;I)I");
+  if (_m_EmojiCompat__getEmojiStart == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  int32_t _result = (*jniEnv)->CallIntMethod(
+      jniEnv, self_, _m_EmojiCompat__getEmojiStart, charSequence, offset);
+  return (JniResult){.result = {.i = _result}, .exception = check_exception()};
+}
+
+jmethodID _m_EmojiCompat__getEmojiEnd = NULL;
+FFI_PLUGIN_EXPORT
+JniResult EmojiCompat__getEmojiEnd(jobject self_,
+                                   jobject charSequence,
+                                   int32_t offset) {
+  load_env();
+  load_class_gr(&_c_EmojiCompat, "androidx/emoji2/text/EmojiCompat");
+  if (_c_EmojiCompat == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(_c_EmojiCompat, &_m_EmojiCompat__getEmojiEnd, "getEmojiEnd",
+              "(Ljava/lang/CharSequence;I)I");
+  if (_m_EmojiCompat__getEmojiEnd == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  int32_t _result = (*jniEnv)->CallIntMethod(
+      jniEnv, self_, _m_EmojiCompat__getEmojiEnd, charSequence, offset);
+  return (JniResult){.result = {.i = _result}, .exception = check_exception()};
+}
+
+jmethodID _m_EmojiCompat__handleOnKeyDown = NULL;
+FFI_PLUGIN_EXPORT
+JniResult EmojiCompat__handleOnKeyDown(jobject editable,
+                                       int32_t keyCode,
+                                       jobject event) {
+  load_env();
+  load_class_gr(&_c_EmojiCompat, "androidx/emoji2/text/EmojiCompat");
+  if (_c_EmojiCompat == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_static_method(_c_EmojiCompat, &_m_EmojiCompat__handleOnKeyDown,
+                     "handleOnKeyDown",
+                     "(Landroid/text/Editable;ILandroid/view/KeyEvent;)Z");
+  if (_m_EmojiCompat__handleOnKeyDown == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  uint8_t _result = (*jniEnv)->CallStaticBooleanMethod(
+      jniEnv, _c_EmojiCompat, _m_EmojiCompat__handleOnKeyDown, editable,
+      keyCode, event);
+  return (JniResult){.result = {.z = _result}, .exception = check_exception()};
+}
+
+jmethodID _m_EmojiCompat__handleDeleteSurroundingText = NULL;
+FFI_PLUGIN_EXPORT
+JniResult EmojiCompat__handleDeleteSurroundingText(jobject inputConnection,
+                                                   jobject editable,
+                                                   int32_t beforeLength,
+                                                   int32_t afterLength,
+                                                   uint8_t inCodePoints) {
+  load_env();
+  load_class_gr(&_c_EmojiCompat, "androidx/emoji2/text/EmojiCompat");
+  if (_c_EmojiCompat == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_static_method(_c_EmojiCompat,
+                     &_m_EmojiCompat__handleDeleteSurroundingText,
+                     "handleDeleteSurroundingText",
+                     "(Landroid/view/inputmethod/InputConnection;Landroid/text/"
+                     "Editable;IIZ)Z");
+  if (_m_EmojiCompat__handleDeleteSurroundingText == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  uint8_t _result = (*jniEnv)->CallStaticBooleanMethod(
+      jniEnv, _c_EmojiCompat, _m_EmojiCompat__handleDeleteSurroundingText,
+      inputConnection, editable, beforeLength, afterLength, inCodePoints);
+  return (JniResult){.result = {.z = _result}, .exception = check_exception()};
+}
+
+jmethodID _m_EmojiCompat__hasEmojiGlyph = NULL;
+FFI_PLUGIN_EXPORT
+JniResult EmojiCompat__hasEmojiGlyph(jobject self_, jobject sequence) {
+  load_env();
+  load_class_gr(&_c_EmojiCompat, "androidx/emoji2/text/EmojiCompat");
+  if (_c_EmojiCompat == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(_c_EmojiCompat, &_m_EmojiCompat__hasEmojiGlyph, "hasEmojiGlyph",
+              "(Ljava/lang/CharSequence;)Z");
+  if (_m_EmojiCompat__hasEmojiGlyph == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  uint8_t _result = (*jniEnv)->CallBooleanMethod(
+      jniEnv, self_, _m_EmojiCompat__hasEmojiGlyph, sequence);
+  return (JniResult){.result = {.z = _result}, .exception = check_exception()};
+}
+
+jmethodID _m_EmojiCompat__hasEmojiGlyph1 = NULL;
+FFI_PLUGIN_EXPORT
+JniResult EmojiCompat__hasEmojiGlyph1(jobject self_,
+                                      jobject sequence,
+                                      int32_t metadataVersion) {
+  load_env();
+  load_class_gr(&_c_EmojiCompat, "androidx/emoji2/text/EmojiCompat");
+  if (_c_EmojiCompat == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(_c_EmojiCompat, &_m_EmojiCompat__hasEmojiGlyph1, "hasEmojiGlyph",
+              "(Ljava/lang/CharSequence;I)Z");
+  if (_m_EmojiCompat__hasEmojiGlyph1 == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  uint8_t _result = (*jniEnv)->CallBooleanMethod(
+      jniEnv, self_, _m_EmojiCompat__hasEmojiGlyph1, sequence, metadataVersion);
+  return (JniResult){.result = {.z = _result}, .exception = check_exception()};
+}
+
+jmethodID _m_EmojiCompat__getEmojiMatch = NULL;
+FFI_PLUGIN_EXPORT
+JniResult EmojiCompat__getEmojiMatch(jobject self_,
+                                     jobject sequence,
+                                     int32_t metadataVersion) {
+  load_env();
+  load_class_gr(&_c_EmojiCompat, "androidx/emoji2/text/EmojiCompat");
+  if (_c_EmojiCompat == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(_c_EmojiCompat, &_m_EmojiCompat__getEmojiMatch, "getEmojiMatch",
+              "(Ljava/lang/CharSequence;I)I");
+  if (_m_EmojiCompat__getEmojiMatch == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  int32_t _result = (*jniEnv)->CallIntMethod(
+      jniEnv, self_, _m_EmojiCompat__getEmojiMatch, sequence, metadataVersion);
+  return (JniResult){.result = {.i = _result}, .exception = check_exception()};
+}
+
+jmethodID _m_EmojiCompat__process = NULL;
+FFI_PLUGIN_EXPORT
+JniResult EmojiCompat__process(jobject self_, jobject charSequence) {
+  load_env();
+  load_class_gr(&_c_EmojiCompat, "androidx/emoji2/text/EmojiCompat");
+  if (_c_EmojiCompat == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(_c_EmojiCompat, &_m_EmojiCompat__process, "process",
+              "(Ljava/lang/CharSequence;)Ljava/lang/CharSequence;");
+  if (_m_EmojiCompat__process == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result = (*jniEnv)->CallObjectMethod(
+      jniEnv, self_, _m_EmojiCompat__process, charSequence);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
+
+jmethodID _m_EmojiCompat__process1 = NULL;
+FFI_PLUGIN_EXPORT
+JniResult EmojiCompat__process1(jobject self_,
+                                jobject charSequence,
+                                int32_t start,
+                                int32_t end) {
+  load_env();
+  load_class_gr(&_c_EmojiCompat, "androidx/emoji2/text/EmojiCompat");
+  if (_c_EmojiCompat == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(_c_EmojiCompat, &_m_EmojiCompat__process1, "process",
+              "(Ljava/lang/CharSequence;II)Ljava/lang/CharSequence;");
+  if (_m_EmojiCompat__process1 == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result = (*jniEnv)->CallObjectMethod(
+      jniEnv, self_, _m_EmojiCompat__process1, charSequence, start, end);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
+
+jmethodID _m_EmojiCompat__process2 = NULL;
+FFI_PLUGIN_EXPORT
+JniResult EmojiCompat__process2(jobject self_,
+                                jobject charSequence,
+                                int32_t start,
+                                int32_t end,
+                                int32_t maxEmojiCount) {
+  load_env();
+  load_class_gr(&_c_EmojiCompat, "androidx/emoji2/text/EmojiCompat");
+  if (_c_EmojiCompat == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(_c_EmojiCompat, &_m_EmojiCompat__process2, "process",
+              "(Ljava/lang/CharSequence;III)Ljava/lang/CharSequence;");
+  if (_m_EmojiCompat__process2 == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result =
+      (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_EmojiCompat__process2,
+                                  charSequence, start, end, maxEmojiCount);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
+
+jmethodID _m_EmojiCompat__process3 = NULL;
+FFI_PLUGIN_EXPORT
+JniResult EmojiCompat__process3(jobject self_,
+                                jobject charSequence,
+                                int32_t start,
+                                int32_t end,
+                                int32_t maxEmojiCount,
+                                int32_t replaceStrategy) {
+  load_env();
+  load_class_gr(&_c_EmojiCompat, "androidx/emoji2/text/EmojiCompat");
+  if (_c_EmojiCompat == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(_c_EmojiCompat, &_m_EmojiCompat__process3, "process",
+              "(Ljava/lang/CharSequence;IIII)Ljava/lang/CharSequence;");
+  if (_m_EmojiCompat__process3 == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result = (*jniEnv)->CallObjectMethod(
+      jniEnv, self_, _m_EmojiCompat__process3, charSequence, start, end,
+      maxEmojiCount, replaceStrategy);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
+
+jmethodID _m_EmojiCompat__getAssetSignature = NULL;
+FFI_PLUGIN_EXPORT
+JniResult EmojiCompat__getAssetSignature(jobject self_) {
+  load_env();
+  load_class_gr(&_c_EmojiCompat, "androidx/emoji2/text/EmojiCompat");
+  if (_c_EmojiCompat == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(_c_EmojiCompat, &_m_EmojiCompat__getAssetSignature,
+              "getAssetSignature", "()Ljava/lang/String;");
+  if (_m_EmojiCompat__getAssetSignature == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result = (*jniEnv)->CallObjectMethod(
+      jniEnv, self_, _m_EmojiCompat__getAssetSignature);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
+
+jmethodID _m_EmojiCompat__updateEditorInfo = NULL;
+FFI_PLUGIN_EXPORT
+JniResult EmojiCompat__updateEditorInfo(jobject self_, jobject outAttrs) {
+  load_env();
+  load_class_gr(&_c_EmojiCompat, "androidx/emoji2/text/EmojiCompat");
+  if (_c_EmojiCompat == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(_c_EmojiCompat, &_m_EmojiCompat__updateEditorInfo,
+              "updateEditorInfo", "(Landroid/view/inputmethod/EditorInfo;)V");
+  if (_m_EmojiCompat__updateEditorInfo == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_EmojiCompat__updateEditorInfo,
+                            outAttrs);
+  return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+}
+
+// androidx.emoji2.text.EmojiCompat$Config
+jclass _c_EmojiCompat_Config = NULL;
+
+jmethodID _m_EmojiCompat_Config__ctor = NULL;
+FFI_PLUGIN_EXPORT
+JniResult EmojiCompat_Config__ctor(jobject metadataLoader) {
+  load_env();
+  load_class_gr(&_c_EmojiCompat_Config,
+                "androidx/emoji2/text/EmojiCompat$Config");
+  if (_c_EmojiCompat_Config == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(_c_EmojiCompat_Config, &_m_EmojiCompat_Config__ctor, "<init>",
+              "(Landroidx/emoji2/text/EmojiCompat$MetadataRepoLoader;)V");
+  if (_m_EmojiCompat_Config__ctor == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result =
+      (*jniEnv)->NewObject(jniEnv, _c_EmojiCompat_Config,
+                           _m_EmojiCompat_Config__ctor, metadataLoader);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
+
+jmethodID _m_EmojiCompat_Config__registerInitCallback = NULL;
+FFI_PLUGIN_EXPORT
+JniResult EmojiCompat_Config__registerInitCallback(jobject self_,
+                                                   jobject initCallback) {
+  load_env();
+  load_class_gr(&_c_EmojiCompat_Config,
+                "androidx/emoji2/text/EmojiCompat$Config");
+  if (_c_EmojiCompat_Config == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(_c_EmojiCompat_Config,
+              &_m_EmojiCompat_Config__registerInitCallback,
+              "registerInitCallback",
+              "(Landroidx/emoji2/text/EmojiCompat$InitCallback;)Landroidx/"
+              "emoji2/text/EmojiCompat$Config;");
+  if (_m_EmojiCompat_Config__registerInitCallback == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result = (*jniEnv)->CallObjectMethod(
+      jniEnv, self_, _m_EmojiCompat_Config__registerInitCallback, initCallback);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
+
+jmethodID _m_EmojiCompat_Config__unregisterInitCallback = NULL;
+FFI_PLUGIN_EXPORT
+JniResult EmojiCompat_Config__unregisterInitCallback(jobject self_,
+                                                     jobject initCallback) {
+  load_env();
+  load_class_gr(&_c_EmojiCompat_Config,
+                "androidx/emoji2/text/EmojiCompat$Config");
+  if (_c_EmojiCompat_Config == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(_c_EmojiCompat_Config,
+              &_m_EmojiCompat_Config__unregisterInitCallback,
+              "unregisterInitCallback",
+              "(Landroidx/emoji2/text/EmojiCompat$InitCallback;)Landroidx/"
+              "emoji2/text/EmojiCompat$Config;");
+  if (_m_EmojiCompat_Config__unregisterInitCallback == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result = (*jniEnv)->CallObjectMethod(
+      jniEnv, self_, _m_EmojiCompat_Config__unregisterInitCallback,
+      initCallback);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
+
+jmethodID _m_EmojiCompat_Config__setReplaceAll = NULL;
+FFI_PLUGIN_EXPORT
+JniResult EmojiCompat_Config__setReplaceAll(jobject self_, uint8_t replaceAll) {
+  load_env();
+  load_class_gr(&_c_EmojiCompat_Config,
+                "androidx/emoji2/text/EmojiCompat$Config");
+  if (_c_EmojiCompat_Config == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(_c_EmojiCompat_Config, &_m_EmojiCompat_Config__setReplaceAll,
+              "setReplaceAll", "(Z)Landroidx/emoji2/text/EmojiCompat$Config;");
+  if (_m_EmojiCompat_Config__setReplaceAll == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result = (*jniEnv)->CallObjectMethod(
+      jniEnv, self_, _m_EmojiCompat_Config__setReplaceAll, replaceAll);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
+
+jmethodID _m_EmojiCompat_Config__setUseEmojiAsDefaultStyle = NULL;
+FFI_PLUGIN_EXPORT
+JniResult EmojiCompat_Config__setUseEmojiAsDefaultStyle(
+    jobject self_,
+    uint8_t useEmojiAsDefaultStyle) {
+  load_env();
+  load_class_gr(&_c_EmojiCompat_Config,
+                "androidx/emoji2/text/EmojiCompat$Config");
+  if (_c_EmojiCompat_Config == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(_c_EmojiCompat_Config,
+              &_m_EmojiCompat_Config__setUseEmojiAsDefaultStyle,
+              "setUseEmojiAsDefaultStyle",
+              "(Z)Landroidx/emoji2/text/EmojiCompat$Config;");
+  if (_m_EmojiCompat_Config__setUseEmojiAsDefaultStyle == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result = (*jniEnv)->CallObjectMethod(
+      jniEnv, self_, _m_EmojiCompat_Config__setUseEmojiAsDefaultStyle,
+      useEmojiAsDefaultStyle);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
+
+jmethodID _m_EmojiCompat_Config__setUseEmojiAsDefaultStyle1 = NULL;
+FFI_PLUGIN_EXPORT
+JniResult EmojiCompat_Config__setUseEmojiAsDefaultStyle1(
+    jobject self_,
+    uint8_t useEmojiAsDefaultStyle,
+    jobject emojiAsDefaultStyleExceptions) {
+  load_env();
+  load_class_gr(&_c_EmojiCompat_Config,
+                "androidx/emoji2/text/EmojiCompat$Config");
+  if (_c_EmojiCompat_Config == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(_c_EmojiCompat_Config,
+              &_m_EmojiCompat_Config__setUseEmojiAsDefaultStyle1,
+              "setUseEmojiAsDefaultStyle",
+              "(ZLjava/util/List;)Landroidx/emoji2/text/EmojiCompat$Config;");
+  if (_m_EmojiCompat_Config__setUseEmojiAsDefaultStyle1 == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result = (*jniEnv)->CallObjectMethod(
+      jniEnv, self_, _m_EmojiCompat_Config__setUseEmojiAsDefaultStyle1,
+      useEmojiAsDefaultStyle, emojiAsDefaultStyleExceptions);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
+
+jmethodID _m_EmojiCompat_Config__setEmojiSpanIndicatorEnabled = NULL;
+FFI_PLUGIN_EXPORT
+JniResult EmojiCompat_Config__setEmojiSpanIndicatorEnabled(
+    jobject self_,
+    uint8_t emojiSpanIndicatorEnabled) {
+  load_env();
+  load_class_gr(&_c_EmojiCompat_Config,
+                "androidx/emoji2/text/EmojiCompat$Config");
+  if (_c_EmojiCompat_Config == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(_c_EmojiCompat_Config,
+              &_m_EmojiCompat_Config__setEmojiSpanIndicatorEnabled,
+              "setEmojiSpanIndicatorEnabled",
+              "(Z)Landroidx/emoji2/text/EmojiCompat$Config;");
+  if (_m_EmojiCompat_Config__setEmojiSpanIndicatorEnabled == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result = (*jniEnv)->CallObjectMethod(
+      jniEnv, self_, _m_EmojiCompat_Config__setEmojiSpanIndicatorEnabled,
+      emojiSpanIndicatorEnabled);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
+
+jmethodID _m_EmojiCompat_Config__setEmojiSpanIndicatorColor = NULL;
+FFI_PLUGIN_EXPORT
+JniResult EmojiCompat_Config__setEmojiSpanIndicatorColor(jobject self_,
+                                                         int32_t color) {
+  load_env();
+  load_class_gr(&_c_EmojiCompat_Config,
+                "androidx/emoji2/text/EmojiCompat$Config");
+  if (_c_EmojiCompat_Config == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(_c_EmojiCompat_Config,
+              &_m_EmojiCompat_Config__setEmojiSpanIndicatorColor,
+              "setEmojiSpanIndicatorColor",
+              "(I)Landroidx/emoji2/text/EmojiCompat$Config;");
+  if (_m_EmojiCompat_Config__setEmojiSpanIndicatorColor == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result = (*jniEnv)->CallObjectMethod(
+      jniEnv, self_, _m_EmojiCompat_Config__setEmojiSpanIndicatorColor, color);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
+
+jmethodID _m_EmojiCompat_Config__setMetadataLoadStrategy = NULL;
+FFI_PLUGIN_EXPORT
+JniResult EmojiCompat_Config__setMetadataLoadStrategy(jobject self_,
+                                                      int32_t strategy) {
+  load_env();
+  load_class_gr(&_c_EmojiCompat_Config,
+                "androidx/emoji2/text/EmojiCompat$Config");
+  if (_c_EmojiCompat_Config == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(_c_EmojiCompat_Config,
+              &_m_EmojiCompat_Config__setMetadataLoadStrategy,
+              "setMetadataLoadStrategy",
+              "(I)Landroidx/emoji2/text/EmojiCompat$Config;");
+  if (_m_EmojiCompat_Config__setMetadataLoadStrategy == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result = (*jniEnv)->CallObjectMethod(
+      jniEnv, self_, _m_EmojiCompat_Config__setMetadataLoadStrategy, strategy);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
+
+jmethodID _m_EmojiCompat_Config__setSpanFactory = NULL;
+FFI_PLUGIN_EXPORT
+JniResult EmojiCompat_Config__setSpanFactory(jobject self_, jobject factory) {
+  load_env();
+  load_class_gr(&_c_EmojiCompat_Config,
+                "androidx/emoji2/text/EmojiCompat$Config");
+  if (_c_EmojiCompat_Config == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(_c_EmojiCompat_Config, &_m_EmojiCompat_Config__setSpanFactory,
+              "setSpanFactory",
+              "(Landroidx/emoji2/text/EmojiCompat$SpanFactory;)Landroidx/"
+              "emoji2/text/EmojiCompat$Config;");
+  if (_m_EmojiCompat_Config__setSpanFactory == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result = (*jniEnv)->CallObjectMethod(
+      jniEnv, self_, _m_EmojiCompat_Config__setSpanFactory, factory);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
+
+jmethodID _m_EmojiCompat_Config__setGlyphChecker = NULL;
+FFI_PLUGIN_EXPORT
+JniResult EmojiCompat_Config__setGlyphChecker(jobject self_,
+                                              jobject glyphChecker) {
+  load_env();
+  load_class_gr(&_c_EmojiCompat_Config,
+                "androidx/emoji2/text/EmojiCompat$Config");
+  if (_c_EmojiCompat_Config == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(_c_EmojiCompat_Config, &_m_EmojiCompat_Config__setGlyphChecker,
+              "setGlyphChecker",
+              "(Landroidx/emoji2/text/EmojiCompat$GlyphChecker;)Landroidx/"
+              "emoji2/text/EmojiCompat$Config;");
+  if (_m_EmojiCompat_Config__setGlyphChecker == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result = (*jniEnv)->CallObjectMethod(
+      jniEnv, self_, _m_EmojiCompat_Config__setGlyphChecker, glyphChecker);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
+
+jmethodID _m_EmojiCompat_Config__getMetadataRepoLoader = NULL;
+FFI_PLUGIN_EXPORT
+JniResult EmojiCompat_Config__getMetadataRepoLoader(jobject self_) {
+  load_env();
+  load_class_gr(&_c_EmojiCompat_Config,
+                "androidx/emoji2/text/EmojiCompat$Config");
+  if (_c_EmojiCompat_Config == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(_c_EmojiCompat_Config,
+              &_m_EmojiCompat_Config__getMetadataRepoLoader,
+              "getMetadataRepoLoader",
+              "()Landroidx/emoji2/text/EmojiCompat$MetadataRepoLoader;");
+  if (_m_EmojiCompat_Config__getMetadataRepoLoader == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result = (*jniEnv)->CallObjectMethod(
+      jniEnv, self_, _m_EmojiCompat_Config__getMetadataRepoLoader);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
+
+// androidx.emoji2.text.EmojiCompat$MetadataRepoLoaderCallback
+jclass _c_EmojiCompat_MetadataRepoLoaderCallback = NULL;
+
+jmethodID _m_EmojiCompat_MetadataRepoLoaderCallback__ctor = NULL;
+FFI_PLUGIN_EXPORT
+JniResult EmojiCompat_MetadataRepoLoaderCallback__ctor() {
+  load_env();
+  load_class_gr(&_c_EmojiCompat_MetadataRepoLoaderCallback,
+                "androidx/emoji2/text/EmojiCompat$MetadataRepoLoaderCallback");
+  if (_c_EmojiCompat_MetadataRepoLoaderCallback == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(_c_EmojiCompat_MetadataRepoLoaderCallback,
+              &_m_EmojiCompat_MetadataRepoLoaderCallback__ctor, "<init>",
+              "()V");
+  if (_m_EmojiCompat_MetadataRepoLoaderCallback__ctor == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result =
+      (*jniEnv)->NewObject(jniEnv, _c_EmojiCompat_MetadataRepoLoaderCallback,
+                           _m_EmojiCompat_MetadataRepoLoaderCallback__ctor);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
+
+jmethodID _m_EmojiCompat_MetadataRepoLoaderCallback__onLoaded = NULL;
+FFI_PLUGIN_EXPORT
+JniResult EmojiCompat_MetadataRepoLoaderCallback__onLoaded(
+    jobject self_,
+    jobject metadataRepo) {
+  load_env();
+  load_class_gr(&_c_EmojiCompat_MetadataRepoLoaderCallback,
+                "androidx/emoji2/text/EmojiCompat$MetadataRepoLoaderCallback");
+  if (_c_EmojiCompat_MetadataRepoLoaderCallback == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(_c_EmojiCompat_MetadataRepoLoaderCallback,
+              &_m_EmojiCompat_MetadataRepoLoaderCallback__onLoaded, "onLoaded",
+              "(Landroidx/emoji2/text/MetadataRepo;)V");
+  if (_m_EmojiCompat_MetadataRepoLoaderCallback__onLoaded == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  (*jniEnv)->CallVoidMethod(jniEnv, self_,
+                            _m_EmojiCompat_MetadataRepoLoaderCallback__onLoaded,
+                            metadataRepo);
+  return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+}
+
+jmethodID _m_EmojiCompat_MetadataRepoLoaderCallback__onFailed = NULL;
+FFI_PLUGIN_EXPORT
+JniResult EmojiCompat_MetadataRepoLoaderCallback__onFailed(jobject self_,
+                                                           jobject throwable) {
+  load_env();
+  load_class_gr(&_c_EmojiCompat_MetadataRepoLoaderCallback,
+                "androidx/emoji2/text/EmojiCompat$MetadataRepoLoaderCallback");
+  if (_c_EmojiCompat_MetadataRepoLoaderCallback == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(_c_EmojiCompat_MetadataRepoLoaderCallback,
+              &_m_EmojiCompat_MetadataRepoLoaderCallback__onFailed, "onFailed",
+              "(Ljava/lang/Throwable;)V");
+  if (_m_EmojiCompat_MetadataRepoLoaderCallback__onFailed == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  (*jniEnv)->CallVoidMethod(jniEnv, self_,
+                            _m_EmojiCompat_MetadataRepoLoaderCallback__onFailed,
+                            throwable);
+  return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+}
+
+// androidx.emoji2.text.EmojiCompat$GlyphChecker
+jclass _c_EmojiCompat_GlyphChecker = NULL;
+
+jmethodID _m_EmojiCompat_GlyphChecker__hasGlyph = NULL;
+FFI_PLUGIN_EXPORT
+JniResult EmojiCompat_GlyphChecker__hasGlyph(jobject self_,
+                                             jobject charSequence,
+                                             int32_t start,
+                                             int32_t end,
+                                             int32_t sdkAdded) {
+  load_env();
+  load_class_gr(&_c_EmojiCompat_GlyphChecker,
+                "androidx/emoji2/text/EmojiCompat$GlyphChecker");
+  if (_c_EmojiCompat_GlyphChecker == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(_c_EmojiCompat_GlyphChecker,
+              &_m_EmojiCompat_GlyphChecker__hasGlyph, "hasGlyph",
+              "(Ljava/lang/CharSequence;III)Z");
+  if (_m_EmojiCompat_GlyphChecker__hasGlyph == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  uint8_t _result = (*jniEnv)->CallBooleanMethod(
+      jniEnv, self_, _m_EmojiCompat_GlyphChecker__hasGlyph, charSequence, start,
+      end, sdkAdded);
+  return (JniResult){.result = {.z = _result}, .exception = check_exception()};
+}
+
+// androidx.emoji2.text.EmojiCompat$MetadataRepoLoader
+jclass _c_EmojiCompat_MetadataRepoLoader = NULL;
+
+jmethodID _m_EmojiCompat_MetadataRepoLoader__load = NULL;
+FFI_PLUGIN_EXPORT
+JniResult EmojiCompat_MetadataRepoLoader__load(jobject self_,
+                                               jobject loaderCallback) {
+  load_env();
+  load_class_gr(&_c_EmojiCompat_MetadataRepoLoader,
+                "androidx/emoji2/text/EmojiCompat$MetadataRepoLoader");
+  if (_c_EmojiCompat_MetadataRepoLoader == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(
+      _c_EmojiCompat_MetadataRepoLoader,
+      &_m_EmojiCompat_MetadataRepoLoader__load, "load",
+      "(Landroidx/emoji2/text/EmojiCompat$MetadataRepoLoaderCallback;)V");
+  if (_m_EmojiCompat_MetadataRepoLoader__load == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  (*jniEnv)->CallVoidMethod(
+      jniEnv, self_, _m_EmojiCompat_MetadataRepoLoader__load, loaderCallback);
+  return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+}
+
+// androidx.emoji2.text.EmojiCompat$InitCallback
+jclass _c_EmojiCompat_InitCallback = NULL;
+
+jmethodID _m_EmojiCompat_InitCallback__ctor = NULL;
+FFI_PLUGIN_EXPORT
+JniResult EmojiCompat_InitCallback__ctor() {
+  load_env();
+  load_class_gr(&_c_EmojiCompat_InitCallback,
+                "androidx/emoji2/text/EmojiCompat$InitCallback");
+  if (_c_EmojiCompat_InitCallback == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(_c_EmojiCompat_InitCallback, &_m_EmojiCompat_InitCallback__ctor,
+              "<init>", "()V");
+  if (_m_EmojiCompat_InitCallback__ctor == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result = (*jniEnv)->NewObject(jniEnv, _c_EmojiCompat_InitCallback,
+                                         _m_EmojiCompat_InitCallback__ctor);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
+
+jmethodID _m_EmojiCompat_InitCallback__onInitialized = NULL;
+FFI_PLUGIN_EXPORT
+JniResult EmojiCompat_InitCallback__onInitialized(jobject self_) {
+  load_env();
+  load_class_gr(&_c_EmojiCompat_InitCallback,
+                "androidx/emoji2/text/EmojiCompat$InitCallback");
+  if (_c_EmojiCompat_InitCallback == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(_c_EmojiCompat_InitCallback,
+              &_m_EmojiCompat_InitCallback__onInitialized, "onInitialized",
+              "()V");
+  if (_m_EmojiCompat_InitCallback__onInitialized == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  (*jniEnv)->CallVoidMethod(jniEnv, self_,
+                            _m_EmojiCompat_InitCallback__onInitialized);
+  return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+}
+
+jmethodID _m_EmojiCompat_InitCallback__onFailed = NULL;
+FFI_PLUGIN_EXPORT
+JniResult EmojiCompat_InitCallback__onFailed(jobject self_, jobject throwable) {
+  load_env();
+  load_class_gr(&_c_EmojiCompat_InitCallback,
+                "androidx/emoji2/text/EmojiCompat$InitCallback");
+  if (_c_EmojiCompat_InitCallback == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(_c_EmojiCompat_InitCallback,
+              &_m_EmojiCompat_InitCallback__onFailed, "onFailed",
+              "(Ljava/lang/Throwable;)V");
+  if (_m_EmojiCompat_InitCallback__onFailed == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  (*jniEnv)->CallVoidMethod(jniEnv, self_,
+                            _m_EmojiCompat_InitCallback__onFailed, throwable);
+  return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+}
+
+// androidx.emoji2.text.EmojiCompat$DefaultSpanFactory
+jclass _c_EmojiCompat_DefaultSpanFactory = NULL;
+
+jmethodID _m_EmojiCompat_DefaultSpanFactory__ctor = NULL;
+FFI_PLUGIN_EXPORT
+JniResult EmojiCompat_DefaultSpanFactory__ctor() {
+  load_env();
+  load_class_gr(&_c_EmojiCompat_DefaultSpanFactory,
+                "androidx/emoji2/text/EmojiCompat$DefaultSpanFactory");
+  if (_c_EmojiCompat_DefaultSpanFactory == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(_c_EmojiCompat_DefaultSpanFactory,
+              &_m_EmojiCompat_DefaultSpanFactory__ctor, "<init>", "()V");
+  if (_m_EmojiCompat_DefaultSpanFactory__ctor == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result =
+      (*jniEnv)->NewObject(jniEnv, _c_EmojiCompat_DefaultSpanFactory,
+                           _m_EmojiCompat_DefaultSpanFactory__ctor);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
+
+jmethodID _m_EmojiCompat_DefaultSpanFactory__createSpan = NULL;
+FFI_PLUGIN_EXPORT
+JniResult EmojiCompat_DefaultSpanFactory__createSpan(jobject self_,
+                                                     jobject rasterizer) {
+  load_env();
+  load_class_gr(&_c_EmojiCompat_DefaultSpanFactory,
+                "androidx/emoji2/text/EmojiCompat$DefaultSpanFactory");
+  if (_c_EmojiCompat_DefaultSpanFactory == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(_c_EmojiCompat_DefaultSpanFactory,
+              &_m_EmojiCompat_DefaultSpanFactory__createSpan, "createSpan",
+              "(Landroidx/emoji2/text/TypefaceEmojiRasterizer;)Landroidx/"
+              "emoji2/text/EmojiSpan;");
+  if (_m_EmojiCompat_DefaultSpanFactory__createSpan == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result = (*jniEnv)->CallObjectMethod(
+      jniEnv, self_, _m_EmojiCompat_DefaultSpanFactory__createSpan, rasterizer);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
+
+// androidx.emoji2.text.EmojiCompat$SpanFactory
+jclass _c_EmojiCompat_SpanFactory = NULL;
+
+jmethodID _m_EmojiCompat_SpanFactory__createSpan = NULL;
+FFI_PLUGIN_EXPORT
+JniResult EmojiCompat_SpanFactory__createSpan(jobject self_,
+                                              jobject rasterizer) {
+  load_env();
+  load_class_gr(&_c_EmojiCompat_SpanFactory,
+                "androidx/emoji2/text/EmojiCompat$SpanFactory");
+  if (_c_EmojiCompat_SpanFactory == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(_c_EmojiCompat_SpanFactory,
+              &_m_EmojiCompat_SpanFactory__createSpan, "createSpan",
+              "(Landroidx/emoji2/text/TypefaceEmojiRasterizer;)Landroidx/"
+              "emoji2/text/EmojiSpan;");
+  if (_m_EmojiCompat_SpanFactory__createSpan == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result = (*jniEnv)->CallObjectMethod(
+      jniEnv, self_, _m_EmojiCompat_SpanFactory__createSpan, rasterizer);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
+
+// androidx.emoji2.text.DefaultEmojiCompatConfig
+jclass _c_DefaultEmojiCompatConfig = NULL;
+
+jmethodID _m_DefaultEmojiCompatConfig__create = NULL;
+FFI_PLUGIN_EXPORT
+JniResult DefaultEmojiCompatConfig__create(jobject context) {
+  load_env();
+  load_class_gr(&_c_DefaultEmojiCompatConfig,
+                "androidx/emoji2/text/DefaultEmojiCompatConfig");
+  if (_c_DefaultEmojiCompatConfig == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_static_method(_c_DefaultEmojiCompatConfig,
+                     &_m_DefaultEmojiCompatConfig__create, "create",
+                     "(Landroid/content/Context;)Landroidx/emoji2/text/"
+                     "FontRequestEmojiCompatConfig;");
+  if (_m_DefaultEmojiCompatConfig__create == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result = (*jniEnv)->CallStaticObjectMethod(
+      jniEnv, _c_DefaultEmojiCompatConfig, _m_DefaultEmojiCompatConfig__create,
+      context);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
+
+// androidx.emoji2.text.DefaultEmojiCompatConfig$DefaultEmojiCompatConfigHelper_API28
+jclass _c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28 = NULL;
+
+jmethodID
+    _m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28__ctor =
+        NULL;
+FFI_PLUGIN_EXPORT
+JniResult
+DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28__ctor() {
+  load_env();
+  load_class_gr(
+      &_c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28,
+      "androidx/emoji2/text/"
+      "DefaultEmojiCompatConfig$DefaultEmojiCompatConfigHelper_API28");
+  if (_c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28 == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(
+      _c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28,
+      &_m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28__ctor,
+      "<init>", "()V");
+  if (_m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28__ctor ==
+      NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result = (*jniEnv)->NewObject(
+      jniEnv, _c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28,
+      _m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28__ctor);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
+
+jmethodID
+    _m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28__getSigningSignatures1 =
+        NULL;
+FFI_PLUGIN_EXPORT
+JniResult
+DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28__getSigningSignatures1(
+    jobject self_,
+    jobject packageManager,
+    jobject providerPackage) {
+  load_env();
+  load_class_gr(
+      &_c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28,
+      "androidx/emoji2/text/"
+      "DefaultEmojiCompatConfig$DefaultEmojiCompatConfigHelper_API28");
+  if (_c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28 == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(
+      _c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28,
+      &_m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28__getSigningSignatures1,
+      "getSigningSignatures",
+      "(Landroid/content/pm/PackageManager;Ljava/lang/String;)[Landroid/"
+      "content/pm/Signature;");
+  if (_m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28__getSigningSignatures1 ==
+      NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result = (*jniEnv)->CallObjectMethod(
+      jniEnv, self_,
+      _m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28__getSigningSignatures1,
+      packageManager, providerPackage);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
+
+// androidx.emoji2.text.DefaultEmojiCompatConfig$DefaultEmojiCompatConfigHelper_API19
+jclass _c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19 = NULL;
+
+jmethodID
+    _m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19__ctor =
+        NULL;
+FFI_PLUGIN_EXPORT
+JniResult
+DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19__ctor() {
+  load_env();
+  load_class_gr(
+      &_c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19,
+      "androidx/emoji2/text/"
+      "DefaultEmojiCompatConfig$DefaultEmojiCompatConfigHelper_API19");
+  if (_c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19 == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(
+      _c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19,
+      &_m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19__ctor,
+      "<init>", "()V");
+  if (_m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19__ctor ==
+      NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result = (*jniEnv)->NewObject(
+      jniEnv, _c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19,
+      _m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19__ctor);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
+
+jmethodID
+    _m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19__queryIntentContentProviders =
+        NULL;
+FFI_PLUGIN_EXPORT
+JniResult
+DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19__queryIntentContentProviders(
+    jobject self_,
+    jobject packageManager,
+    jobject intent,
+    int32_t flags) {
+  load_env();
+  load_class_gr(
+      &_c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19,
+      "androidx/emoji2/text/"
+      "DefaultEmojiCompatConfig$DefaultEmojiCompatConfigHelper_API19");
+  if (_c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19 == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(
+      _c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19,
+      &_m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19__queryIntentContentProviders,
+      "queryIntentContentProviders",
+      "(Landroid/content/pm/PackageManager;Landroid/content/Intent;I)Ljava/"
+      "util/List;");
+  if (_m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19__queryIntentContentProviders ==
+      NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result = (*jniEnv)->CallObjectMethod(
+      jniEnv, self_,
+      _m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19__queryIntentContentProviders,
+      packageManager, intent, flags);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
+
+jmethodID
+    _m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19__getProviderInfo =
+        NULL;
+FFI_PLUGIN_EXPORT
+JniResult
+DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19__getProviderInfo(
+    jobject self_,
+    jobject resolveInfo) {
+  load_env();
+  load_class_gr(
+      &_c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19,
+      "androidx/emoji2/text/"
+      "DefaultEmojiCompatConfig$DefaultEmojiCompatConfigHelper_API19");
+  if (_c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19 == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(
+      _c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19,
+      &_m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19__getProviderInfo,
+      "getProviderInfo",
+      "(Landroid/content/pm/ResolveInfo;)Landroid/content/pm/ProviderInfo;");
+  if (_m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19__getProviderInfo ==
+      NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result = (*jniEnv)->CallObjectMethod(
+      jniEnv, self_,
+      _m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19__getProviderInfo,
+      resolveInfo);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
+
+// androidx.emoji2.text.DefaultEmojiCompatConfig$DefaultEmojiCompatConfigHelper
+jclass _c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper = NULL;
+
+jmethodID _m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper__ctor =
+    NULL;
+FFI_PLUGIN_EXPORT
+JniResult DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper__ctor() {
+  load_env();
+  load_class_gr(&_c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper,
+                "androidx/emoji2/text/"
+                "DefaultEmojiCompatConfig$DefaultEmojiCompatConfigHelper");
+  if (_c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(_c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper,
+              &_m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper__ctor,
+              "<init>", "()V");
+  if (_m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper__ctor == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result = (*jniEnv)->NewObject(
+      jniEnv, _c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper,
+      _m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper__ctor);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
+
+jmethodID
+    _m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper__getSigningSignatures =
+        NULL;
+FFI_PLUGIN_EXPORT
+JniResult
+DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper__getSigningSignatures(
+    jobject self_,
+    jobject packageManager,
+    jobject providerPackage) {
+  load_env();
+  load_class_gr(&_c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper,
+                "androidx/emoji2/text/"
+                "DefaultEmojiCompatConfig$DefaultEmojiCompatConfigHelper");
+  if (_c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(
+      _c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper,
+      &_m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper__getSigningSignatures,
+      "getSigningSignatures",
+      "(Landroid/content/pm/PackageManager;Ljava/lang/String;)[Landroid/"
+      "content/pm/Signature;");
+  if (_m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper__getSigningSignatures ==
+      NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result = (*jniEnv)->CallObjectMethod(
+      jniEnv, self_,
+      _m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper__getSigningSignatures,
+      packageManager, providerPackage);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
+
+jmethodID
+    _m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper__queryIntentContentProviders =
+        NULL;
+FFI_PLUGIN_EXPORT
+JniResult
+DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper__queryIntentContentProviders(
+    jobject self_,
+    jobject packageManager,
+    jobject intent,
+    int32_t flags) {
+  load_env();
+  load_class_gr(&_c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper,
+                "androidx/emoji2/text/"
+                "DefaultEmojiCompatConfig$DefaultEmojiCompatConfigHelper");
+  if (_c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(
+      _c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper,
+      &_m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper__queryIntentContentProviders,
+      "queryIntentContentProviders",
+      "(Landroid/content/pm/PackageManager;Landroid/content/Intent;I)Ljava/"
+      "util/List;");
+  if (_m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper__queryIntentContentProviders ==
+      NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result = (*jniEnv)->CallObjectMethod(
+      jniEnv, self_,
+      _m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper__queryIntentContentProviders,
+      packageManager, intent, flags);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
+
+jmethodID
+    _m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper__getProviderInfo =
+        NULL;
+FFI_PLUGIN_EXPORT
+JniResult
+DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper__getProviderInfo(
+    jobject self_,
+    jobject resolveInfo) {
+  load_env();
+  load_class_gr(&_c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper,
+                "androidx/emoji2/text/"
+                "DefaultEmojiCompatConfig$DefaultEmojiCompatConfigHelper");
+  if (_c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(
+      _c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper,
+      &_m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper__getProviderInfo,
+      "getProviderInfo",
+      "(Landroid/content/pm/ResolveInfo;)Landroid/content/pm/ProviderInfo;");
+  if (_m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper__getProviderInfo ==
+      NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result = (*jniEnv)->CallObjectMethod(
+      jniEnv, self_,
+      _m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper__getProviderInfo,
+      resolveInfo);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
+
+// androidx.emoji2.text.DefaultEmojiCompatConfig$DefaultEmojiCompatConfigFactory
+jclass _c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactory = NULL;
+
+jmethodID _m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactory__ctor =
+    NULL;
+FFI_PLUGIN_EXPORT
+JniResult DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactory__ctor(
+    jobject helper) {
+  load_env();
+  load_class_gr(&_c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactory,
+                "androidx/emoji2/text/"
+                "DefaultEmojiCompatConfig$DefaultEmojiCompatConfigFactory");
+  if (_c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactory == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(
+      _c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactory,
+      &_m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactory__ctor,
+      "<init>",
+      "(Landroidx/emoji2/text/"
+      "DefaultEmojiCompatConfig$DefaultEmojiCompatConfigHelper;)V");
+  if (_m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactory__ctor == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result = (*jniEnv)->NewObject(
+      jniEnv, _c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactory,
+      _m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactory__ctor,
+      helper);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
+
+jmethodID _m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactory__create =
+    NULL;
+FFI_PLUGIN_EXPORT
+JniResult DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactory__create(
+    jobject self_,
+    jobject context) {
+  load_env();
+  load_class_gr(&_c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactory,
+                "androidx/emoji2/text/"
+                "DefaultEmojiCompatConfig$DefaultEmojiCompatConfigFactory");
+  if (_c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactory == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(
+      _c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactory,
+      &_m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactory__create,
+      "create",
+      "(Landroid/content/Context;)Landroidx/emoji2/text/EmojiCompat$Config;");
+  if (_m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactory__create ==
+      NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result = (*jniEnv)->CallObjectMethod(
+      jniEnv, self_,
+      _m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactory__create,
+      context);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
+
 // android.os.Build
 jclass _c_Build = NULL;
 
diff --git a/pkgs/jnigen/lib/src/config/config_types.dart b/pkgs/jnigen/lib/src/config/config_types.dart
index 48d6ee0..39c198f 100644
--- a/pkgs/jnigen/lib/src/config/config_types.dart
+++ b/pkgs/jnigen/lib/src/config/config_types.dart
@@ -49,8 +49,8 @@
 /// `clean` task was run either through flutter or gradle wrapper. In such case,
 /// it's required to run `flutter build apk` & retry running `jnigen`.
 ///
-/// A configuration is invalid if [versions] is unspecified or empty, and
-/// [addGradleDeps] is also false. If [sdkRoot] is not specified but versions is
+/// A configuration is invalid if [versions] is unspecified or empty, and gradle
+/// options are also false. If [sdkRoot] is not specified but versions is
 /// specified, an attempt is made to find out SDK installation directory using
 /// environment variable `ANDROID_SDK_ROOT` if it's defined, else an error
 /// will be thrown.
@@ -59,13 +59,14 @@
     this.versions,
     this.sdkRoot,
     this.addGradleDeps = false,
+    this.addGradleSources = false,
     this.androidExample,
   }) {
     if (versions != null && sdkRoot == null) {
       throw ConfigException("No SDK Root specified for finding Android SDK "
           "from version priority list $versions");
     }
-    if (versions == null && !addGradleDeps) {
+    if (versions == null && !addGradleDeps && !addGradleSources) {
       throw ConfigException('Neither any SDK versions nor `addGradleDeps` '
           'is specified. Unable to find Android libraries.');
     }
@@ -92,6 +93,14 @@
   /// that case.
   bool addGradleDeps;
 
+  /// Similar to [addGradleDeps], runs a stub to obtain source dependencies of
+  /// the Android project.
+  ///
+  /// This may cause additional source JAR artifacts to be downloaded. Like the
+  /// [addGradleDeps] option, plugins cannot be built so an example should be
+  /// specified.
+  bool addGradleSources;
+
   /// Relative path to example application which will be used to determine
   /// compile time classpath using a gradle stub. For most Android plugin
   /// packages, 'example' will be the name of example application created inside
@@ -430,6 +439,7 @@
                   .toList(),
               sdkRoot: getSdkRoot(),
               addGradleDeps: prov.getBool(_Props.addGradleDeps) ?? false,
+              addGradleSources: prov.getBool(_Props.addGradleSources) ?? false,
               // Leaving this as getString instead of getPath, because
               // it's resolved later in android_sdk_tools.
               androidExample: prov.getString(_Props.androidExample),
@@ -499,5 +509,6 @@
   static const androidSdkRoot = '$androidSdkConfig.sdk_root';
   static const androidSdkVersions = '$androidSdkConfig.versions';
   static const addGradleDeps = '$androidSdkConfig.add_gradle_deps';
+  static const addGradleSources = '$androidSdkConfig.add_gradle_sources';
   static const androidExample = '$androidSdkConfig.android_example';
 }
diff --git a/pkgs/jnigen/lib/src/summary/summary.dart b/pkgs/jnigen/lib/src/summary/summary.dart
index 29e50b7..a2f600e 100644
--- a/pkgs/jnigen/lib/src/summary/summary.dart
+++ b/pkgs/jnigen/lib/src/summary/summary.dart
@@ -131,6 +131,13 @@
     );
     extraJars.addAll(deps.map(Uri.file));
   }
+  if (androidConfig != null && androidConfig.addGradleSources) {
+    final deps = AndroidSdkTools.getGradleSources(
+      configRoot: config.configRoot,
+      androidProject: androidConfig.androidExample ?? '.',
+    );
+    extraSources.addAll(deps.map(Uri.file));
+  }
   if (androidConfig != null && androidConfig.versions != null) {
     final versions = androidConfig.versions!;
     final androidSdkRoot =
diff --git a/pkgs/jnigen/lib/src/tools/android_sdk_tools.dart b/pkgs/jnigen/lib/src/tools/android_sdk_tools.dart
index 48fe3b4..a3f53a3 100644
--- a/pkgs/jnigen/lib/src/tools/android_sdk_tools.dart
+++ b/pkgs/jnigen/lib/src/tools/android_sdk_tools.dart
@@ -58,26 +58,78 @@
     return null;
   }
 
+  static const _gradleCannotFindJars = 'Gradle stub cannot find JAR libraries. '
+      'This might be because no APK build has happened yet.';
+
+  static const _leftOverStubWarning = 'If you are seeing this error in '
+      '`flutter build` output, it is likely that `jnigen` left some stubs in '
+      'the build.gradle file. Please restore that file from your version '
+      'control system or manually remove the stub functions named '
+      '$_gradleGetClasspathTaskName and / or $_gradleGetSourcesTaskName.';
+
   static Future<String?> getAndroidJarPath(
           {required String sdkRoot, required List<int> versionOrder}) async =>
       await _getFile(sdkRoot, 'platforms', versionOrder, 'android.jar');
 
-  static const _gradleListDepsFunction = '''
-task listDependencies(type: Copy) {
+  static const _gradleGetClasspathTaskName = 'getReleaseCompileClasspath';
+
+  static const _gradleGetClasspathStub = '''
+// Gradle stub for listing dependencies in jnigen. If found in
+// android/build.gradle, please delete the following function.
+task $_gradleGetClasspathTaskName(type: Copy) {
   project.afterEvaluate {
-  	def app = project(':app')
-	def android = app.android
-	def cp = [android.getBootClasspath()[0]]
-	android.applicationVariants.each { variant ->
-		if (variant.name.equals('release')) {
-			cp += variant.javaCompile.classpath.getFiles()
-		}
-	}
- 	cp.each { println it }
+    try {
+      def app = project(':app')
+      def android = app.android
+      def cp = [android.getBootClasspath()[0]]
+      android.applicationVariants.each { variant ->
+        if (variant.name.equals('release')) {
+          cp += variant.javaCompile.classpath.getFiles()
+        }
+      }
+      cp.each { println it }
+    } catch (Exception e) {
+      System.err.println("$_gradleCannotFindJars")
+      System.err.println("$_leftOverStubWarning")
+    }
   }
 }
 ''';
 
+  static const _gradleGetSourcesTaskName = 'getSources';
+  // adapted from https://stackoverflow.com/questions/39975780/how-can-i-use-gradle-to-download-dependencies-and-their-source-files-and-place-t/39981143#39981143
+  // Although it appears we can use this same code for getting JAR artifacts,
+  // there is no JAR equivalent for `org.gradle.language.base.Artifact`.
+  // So it appears different methods should be used for JAR artifacts.
+  static const _gradleGetSourcesStub = '''
+// Gradle stub for fetching source dependencies in jnigen. If found in
+// android/build.gradle, please delete the following function.
+task $_gradleGetSourcesTaskName(type: Copy) {
+  project.afterEvaluate {
+    def componentIds = project(':app').configurations.releaseCompileClasspath.incoming
+      .resolutionResult.allDependencies.collect { it.selected.id }
+
+    ArtifactResolutionResult result = dependencies.createArtifactResolutionQuery()
+      .forComponents(componentIds)
+      .withArtifacts(JvmLibrary, SourcesArtifact)
+      .execute()
+
+    def sourceArtifacts = []
+
+    result.resolvedComponents.each { ComponentArtifactsResult component ->
+      Set<ArtifactResult> sources = component.getArtifacts(SourcesArtifact)
+      sources.each { ArtifactResult ar ->
+        if (ar instanceof ResolvedArtifactResult) {
+          sourceArtifacts << ar.file
+        }
+      }
+    }
+    sourceArtifacts.forEach { println it }
+  }
+  System.err.println("$_leftOverStubWarning")
+}
+''';
+
   /// Get release compile classpath used by Gradle for android build.
   ///
   /// This function temporarily overwrites the build.gradle file by a stub with
@@ -87,10 +139,42 @@
   /// If current project is not directly buildable by gradle, eg: a plugin,
   /// a relative path to other project can be specified using [androidProject].
   static List<String> getGradleClasspaths(
+          {Uri? configRoot, String androidProject = '.'}) =>
+      _runGradleStub(
+        stubName: _gradleGetClasspathTaskName,
+        stubCode: _gradleGetClasspathStub,
+        androidProject: androidProject,
+        configRoot: configRoot,
+      );
+
+  /// Get source paths for all gradle dependencies.
+  ///
+  /// This function temporarily overwrites the build.gradle file by a stub with
+  /// function to list all dependency paths for release variant.
+  /// This function fails if no gradle build is attempted before.
+  static List<String> getGradleSources(
       {Uri? configRoot, String androidProject = '.'}) {
-    log.info('trying to obtain gradle classpaths...');
+    return _runGradleStub(
+      stubName: _gradleGetSourcesTaskName,
+      stubCode: _gradleGetSourcesStub,
+      androidProject: androidProject,
+      configRoot: configRoot,
+    );
+  }
+
+  static String _appendStub(String script, String stub) {
+    return script.contains(stub) ? script : script + stub;
+  }
+
+  static List<String> _runGradleStub({
+    required String stubName,
+    required String stubCode,
+    Uri? configRoot,
+    String androidProject = '.',
+  }) {
+    log.info('trying to obtain gradle dependencies [$stubName]...');
     if (configRoot != null) {
-      androidProject = join(configRoot.toFilePath(), androidProject);
+      androidProject = configRoot.resolve(androidProject).toFilePath();
     }
     final android = join(androidProject, 'android');
     final buildGradle = join(android, 'build.gradle');
@@ -99,31 +183,40 @@
     final script = origBuild.readAsStringSync();
     origBuild.renameSync(buildGradleOld);
     origBuild.createSync();
-    log.finer('Writing temporary gradle script with stub function...');
-    origBuild.writeAsStringSync('$script\n$_gradleListDepsFunction\n');
+    log.finer('Writing temporary gradle script with stub "$stubName"...');
+    origBuild.writeAsStringSync(_appendStub(script, stubCode));
     log.finer('Running gradle wrapper...');
     final gradleCommand = Platform.isWindows ? '.\\gradlew.bat' : './gradlew';
     ProcessResult procRes;
     try {
-      procRes = Process.runSync(gradleCommand, ['-q', 'listDependencies'],
+      procRes = Process.runSync(gradleCommand, ['-q', stubName],
           workingDirectory: android, runInShell: true);
     } finally {
-      log.finer('Restoring build scripts');
-      origBuild.writeAsStringSync(script);
+      log.info('Restoring build scripts');
+      origBuild.writeAsStringSync(
+        script
+            .replaceAll(_gradleGetClasspathStub, "")
+            .replaceAll(_gradleGetSourcesStub, ""),
+      );
       File(buildGradleOld).deleteSync();
     }
     if (procRes.exitCode != 0) {
       final inAndroidProject =
           (androidProject == '.') ? '' : ' in $androidProject';
-      throw GradleException('\n\ngradle exited with exit code '
-          '${procRes.exitCode}\n. This can be related to a known issue with '
-          'gradle. Please run `flutter build apk`$inAndroidProject and try '
+      throw GradleException('\n\ngradle exited with status '
+          '${procRes.exitCode}\n. This can be because the Android build is not '
+          'yet cached. Please run `flutter build apk`$inAndroidProject and try '
           'again\n');
     }
-    final classpaths = (procRes.stdout as String)
+    final output = procRes.stdout as String;
+    if (output.isEmpty) {
+      printError(procRes.stderr);
+      throw Exception("Gradle stub exited without output.");
+    }
+    final paths = (procRes.stdout as String)
         .trim()
         .split(Platform.isWindows ? '\r\n' : '\n');
-    log.info('Found release build classpath with ${classpaths.length} entries');
-    return classpaths;
+    log.fine('Found ${paths.length} entries');
+    return paths;
   }
 }
diff --git a/pkgs/jnigen/lib/src/tools/maven_tools.dart b/pkgs/jnigen/lib/src/tools/maven_tools.dart
index 82ebdc7..74cb3a1 100644
--- a/pkgs/jnigen/lib/src/tools/maven_tools.dart
+++ b/pkgs/jnigen/lib/src/tools/maven_tools.dart
@@ -101,6 +101,13 @@
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
   http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <repositories>
+      <repository>
+        <id>google-maven-repo</id>
+        <name>Google Maven Repository</name>
+        <url>https://maven.google.com</url>
+      </repository>
+    </repositories>
     <modelVersion>4.0.0</modelVersion>
     <groupId>com.mycompany.app</groupId>
     <artifactId>jnigen_maven_stub</artifactId>
diff --git a/pkgs/jnigen/lib/src/writers/bindings_writer.dart b/pkgs/jnigen/lib/src/writers/bindings_writer.dart
index a31b3d7..190a90c 100644
--- a/pkgs/jnigen/lib/src/writers/bindings_writer.dart
+++ b/pkgs/jnigen/lib/src/writers/bindings_writer.dart
@@ -80,7 +80,7 @@
     final clangFormat = Process.runSync('clang-format', ['-i', cFile.path]);
     if (clangFormat.exitCode != 0) {
       printError(clangFormat.stderr);
-      log.warning('clang-format exited with $exitCode');
+      log.warning('clang-format exited with ${clangFormat.exitCode}');
     }
   } on ProcessException catch (e) {
     log.warning('cannot run clang-format: $e');