From 1b6d83dda8bb68f68de35bce8e2658e27f892fbf Mon Sep 17 00:00:00 2001 From: M66B Date: Fri, 6 Sep 2024 08:08:22 +0200 Subject: [PATCH] Updated AndroidX --- app/build.gradle | 23 +- .../emoji2/text/ConcurrencyHelpers.java | 12 +- .../emoji2/text/DefaultEmojiCompatConfig.java | 56 +--- .../androidx/emoji2/text/EmojiCompat.java | 274 +++++++----------- .../emoji2/text/EmojiCompatInitializer.java | 15 +- .../androidx/emoji2/text/EmojiExclusions.java | 2 - .../androidx/emoji2/text/EmojiProcessor.java | 3 - .../java/androidx/emoji2/text/EmojiSpan.java | 2 - .../text/FontRequestEmojiCompatConfig.java | 5 - .../emoji2/text/MetadataListReader.java | 2 - .../androidx/emoji2/text/MetadataRepo.java | 2 - .../emoji2/text/TypefaceEmojiRasterizer.java | 2 - .../emoji2/text/TypefaceEmojiSpan.java | 2 - patches/emoji.patch | 13 + 14 files changed, 158 insertions(+), 255 deletions(-) create mode 100644 patches/emoji.patch diff --git a/app/build.gradle b/app/build.gradle index 64380ac4de..ab8b36d31c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -535,7 +535,7 @@ configurations.configureEach { } else if (details.requested.group == "androidx.lifecycle" && details.requested.name != "lifecycle-extensions") { //print("Pinning " + details.requested.group + ":" + details.requested.name + "\n") - details.useVersion "2.8.4" + details.useVersion "2.8.5" } else if (details.requested.group == "org.apache.poi") { //print("Pinning " + details.requested.group + ":" + details.requested.name + "\n") details.useVersion "3.17" @@ -557,12 +557,12 @@ dependencies { def annotation_version_experimental = "1.4.1" // 1.5.0-alpha01 def core_version = "1.13.1" // 1.15.0-alpha01 def appcompat_version = "1.7.0" - def emoji_version = "1.4.0" // 1.5.0-rc01 + def emoji_version = "1.5.0" def flatbuffers_version = "2.0.0" - def activity_version = " 1.9.1" // 1.10.0-alpha01 - def fragment_version = "1.8.2" - def windows_version = "1.3.0" // 1.4.0-alpha01 - def webkit_version = "1.10.0" // 1.11.0/1.12.0-beta01 + def activity_version = " 1.9.2" // 1.10.0-alpha02 + def fragment_version = "1.8.3" + def windows_version = "1.3.0" // 1.4.0-alpha02 + def webkit_version = "1.10.0" // 1.11.0/1.12.0-rc01 def recyclerview_version = "1.3.2" // 1.4.0-beta01 def coordinatorlayout_version = "1.2.0" // 1.3.0-alpha02 def constraintlayout_version = "2.1.4" // 2.2.0-alpha14 @@ -571,14 +571,14 @@ dependencies { def lbm_version = "1.1.0" def swiperefresh_version = "1.2.0-alpha01" def documentfile_version = "1.1.0-alpha01" - def lifecycle_version = "2.8.4" + def lifecycle_version = "2.8.5" // 2.9.0-alpha02 def lifecycle_extensions_version = "2.2.0" def room_version = "2.4.3" // 2.5.2/2.6.1/2.7.0-alpha07 def sqlite_version = "2.4.0" // 2.5.0-alpha07 def requery_version = "3.39.2" def paging_version = "2.1.2" // 3.3.0-rc01 def preference_version = "1.2.1" - def work_version = "2.9.1" // 2.10.0-alpha02 + def work_version = "2.9.1" // 2.10.0-alpha03 def exif_version = "1.3.7" def biometric_version = "1.2.0-alpha05" // 1.4.0-alpha02 def billingclient_version = "6.0.1" // 6.2.0 @@ -632,17 +632,18 @@ dependencies { implementation "androidx.core:core:$core_version" // https://mvnrepository.com/artifact/androidx.appcompat/appcompat - // https://mvnrepository.com/artifact/androidx.emoji2/emoji2 // https://mvnrepository.com/artifact/androidx.activity/activity // https://mvnrepository.com/artifact/androidx.fragment/fragment // https://mvnrepository.com/artifact/androidx.window/window-java implementation "androidx.appcompat:appcompat:$appcompat_version" - //implementation "androidx.emoji2:emoji2:$emoji_version" - implementation "com.google.flatbuffers:flatbuffers-java:$flatbuffers_version" implementation "androidx.activity:activity:$activity_version" implementation "androidx.fragment:fragment:$fragment_version" implementation "androidx.window:window-java:$windows_version" + // https://mvnrepository.com/artifact/androidx.emoji2/emoji2 + implementation "androidx.emoji2:emoji2:$emoji_version" + implementation "com.google.flatbuffers:flatbuffers-java:$flatbuffers_version" + // https://developer.android.com/jetpack/androidx/releases/webkit // https://mvnrepository.com/artifact/androidx.webkit/webkit implementation "androidx.webkit:webkit:$webkit_version" diff --git a/app/src/main/java/androidx/emoji2/text/ConcurrencyHelpers.java b/app/src/main/java/androidx/emoji2/text/ConcurrencyHelpers.java index d394ea8b44..060086e5a3 100644 --- a/app/src/main/java/androidx/emoji2/text/ConcurrencyHelpers.java +++ b/app/src/main/java/androidx/emoji2/text/ConcurrencyHelpers.java @@ -21,7 +21,6 @@ import android.os.Handler; import android.os.Looper; import android.os.Process; -import androidx.annotation.DoNotInline; import androidx.annotation.NonNull; import androidx.annotation.RequiresApi; @@ -81,15 +80,19 @@ class ConcurrencyHelpers { } } + static Executor mainThreadExecutor() { + return convertHandlerToExecutor(mainHandlerAsync()); + } + /** - * @deprecated Exists only for upgrade path, remove with - * {@link FontRequestEmojiCompatConfig#setHandler(Handler)} + * Convert a handler to an executor. + * + * We need to do this in places where Context is not available, and cannot use ContextCompat. * * @param handler a background thread handler * @return an executor that posts all work to that handler */ @NonNull - @Deprecated static Executor convertHandlerToExecutor(@NonNull Handler handler) { return handler::post; } @@ -100,7 +103,6 @@ class ConcurrencyHelpers { // Non-instantiable. } - @DoNotInline public static Handler createAsync(Looper looper) { return Handler.createAsync(looper); } diff --git a/app/src/main/java/androidx/emoji2/text/DefaultEmojiCompatConfig.java b/app/src/main/java/androidx/emoji2/text/DefaultEmojiCompatConfig.java index f9ca1031a0..c0bb50e9b4 100644 --- a/app/src/main/java/androidx/emoji2/text/DefaultEmojiCompatConfig.java +++ b/app/src/main/java/androidx/emoji2/text/DefaultEmojiCompatConfig.java @@ -241,8 +241,6 @@ public final class DefaultEmojiCompatConfig { private static DefaultEmojiCompatConfigHelper getHelperForApi() { if (Build.VERSION.SDK_INT >= 28) { return new DefaultEmojiCompatConfigHelper_API28(); - } else if (Build.VERSION.SDK_INT >= 19) { - return new DefaultEmojiCompatConfigHelper_API19(); } else { return new DefaultEmojiCompatConfigHelper(); } @@ -250,30 +248,17 @@ public final class DefaultEmojiCompatConfig { } /** - * Helper to lookup signatures in package manager. - * */ @RestrictTo(RestrictTo.Scope.LIBRARY) public static class DefaultEmojiCompatConfigHelper { - /** - * Get the signing signatures for a package in package manager. - */ - @SuppressWarnings("deprecation") // replaced in API 28 - @NonNull - public Signature[] getSigningSignatures(@NonNull PackageManager packageManager, - @NonNull String providerPackage) throws PackageManager.NameNotFoundException { - PackageInfo packageInfoForSignatures = packageManager.getPackageInfo(providerPackage, - PackageManager.GET_SIGNATURES); - return packageInfoForSignatures.signatures; - } - /** * Get the content provider by intent. */ @NonNull + @SuppressWarnings("deprecation") public List queryIntentContentProviders(@NonNull PackageManager packageManager, @NonNull Intent intent, int flags) { - return Collections.emptyList(); + return packageManager.queryIntentContentProviders(intent, flags); } /** @@ -282,32 +267,21 @@ public final class DefaultEmojiCompatConfig { * @return resolveInfo.providerInfo above API 19 */ @Nullable - public ProviderInfo getProviderInfo(@NonNull ResolveInfo resolveInfo) { - throw new IllegalStateException("Unable to get provider info prior to API 19"); - } - } - - /** - * Actually do lookups > API 19 - * - */ - @RestrictTo(RestrictTo.Scope.LIBRARY) - @RequiresApi(19) - public static class DefaultEmojiCompatConfigHelper_API19 - extends DefaultEmojiCompatConfigHelper { - @NonNull - @Override - @SuppressWarnings("deprecation") - public List queryIntentContentProviders(@NonNull PackageManager packageManager, - @NonNull Intent intent, int flags) { - return packageManager.queryIntentContentProviders(intent, flags); - } - - @Nullable - @Override public ProviderInfo getProviderInfo(@NonNull ResolveInfo resolveInfo) { return resolveInfo.providerInfo; } + + /** + * Get the signing signatures for a package in package manager. + */ + @SuppressWarnings("deprecation") // using deprecated API to match exact behavior in core + @NonNull + public Signature[] getSigningSignatures(@NonNull PackageManager packageManager, + @NonNull String providerPackage) throws PackageManager.NameNotFoundException { + PackageInfo packageInfoForSignatures = packageManager.getPackageInfo(providerPackage, + PackageManager.GET_SIGNATURES); + return packageInfoForSignatures.signatures; + } } /** @@ -316,7 +290,7 @@ public final class DefaultEmojiCompatConfig { @RestrictTo(RestrictTo.Scope.LIBRARY) @RequiresApi(28) public static class DefaultEmojiCompatConfigHelper_API28 - extends DefaultEmojiCompatConfigHelper_API19 { + extends DefaultEmojiCompatConfigHelper { @SuppressWarnings("deprecation") // using deprecated API to match exact behavior in core @Override @NonNull diff --git a/app/src/main/java/androidx/emoji2/text/EmojiCompat.java b/app/src/main/java/androidx/emoji2/text/EmojiCompat.java index af41c890e3..d1f869fa5c 100644 --- a/app/src/main/java/androidx/emoji2/text/EmojiCompat.java +++ b/app/src/main/java/androidx/emoji2/text/EmojiCompat.java @@ -22,10 +22,7 @@ import android.app.Application; import android.content.Context; import android.graphics.Color; import android.graphics.Paint; -import android.os.Build; import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; import android.text.Editable; import android.text.method.KeyListener; import android.view.KeyEvent; @@ -40,7 +37,6 @@ import androidx.annotation.IntDef; import androidx.annotation.IntRange; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.annotation.RequiresApi; import androidx.annotation.RestrictTo; import androidx.annotation.VisibleForTesting; import androidx.collection.ArraySet; @@ -50,9 +46,9 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.List; import java.util.Set; +import java.util.concurrent.Executor; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; @@ -352,17 +348,12 @@ public class EmojiCompat { private final @NonNull ReadWriteLock mInitLock; @GuardedBy("mInitLock") - private final @NonNull Set mInitCallbacks; + private final @NonNull Set mInitCallbacks; @GuardedBy("mInitLock") @LoadState private volatile int mLoadState; - /** - * Handler with main looper to run the callbacks on. - */ - private final @NonNull Handler mMainHandler; - /** * Helper class for pre 19 compatibility. */ @@ -464,15 +455,13 @@ public class EmojiCompat { mMetadataLoader = config.mMetadataLoader; mMetadataLoadStrategy = config.mMetadataLoadStrategy; mGlyphChecker = config.mGlyphChecker; - mMainHandler = new Handler(Looper.getMainLooper()); mInitCallbacks = new ArraySet<>(); SpanFactory localSpanFactory = config.mSpanFactory; mSpanFactory = localSpanFactory != null ? localSpanFactory : new DefaultSpanFactory(); if (config.mInitCallbacks != null && !config.mInitCallbacks.isEmpty()) { mInitCallbacks.addAll(config.mInitCallbacks); } - mHelper = Build.VERSION.SDK_INT < 19 ? new CompatInternal(this) : new CompatInternal19( - this); + mHelper = new CompatInternal(this); loadMetadata(); } @@ -699,31 +688,37 @@ public class EmojiCompat { @SuppressWarnings("WeakerAccess") /* synthetic access */ void onMetadataLoadSuccess() { - final Collection initCallbacks = new ArrayList<>(); + Set localRefCbs = mInitCallbacks; + final ArrayList initCallbacks = new ArrayList<>(localRefCbs.size()); mInitLock.writeLock().lock(); try { mLoadState = LOAD_STATE_SUCCEEDED; - initCallbacks.addAll(mInitCallbacks); - mInitCallbacks.clear(); + initCallbacks.addAll(localRefCbs); + localRefCbs.clear(); } finally { mInitLock.writeLock().unlock(); } - mMainHandler.post(new ListenerDispatcher(initCallbacks, mLoadState)); + for (int i = 0; i < initCallbacks.size(); i++) { + initCallbacks.get(i).dispatchInitialized(); + } } @SuppressWarnings("WeakerAccess") /* synthetic access */ - void onMetadataLoadFailed(@Nullable final Throwable throwable) { - final Collection initCallbacks = new ArrayList<>(); + void onMetadataLoadFailed(@NonNull final Throwable throwable) { + Set localRefCbs = mInitCallbacks; + final ArrayList initCallbacks = new ArrayList<>(localRefCbs.size()); mInitLock.writeLock().lock(); try { mLoadState = LOAD_STATE_FAILED; - initCallbacks.addAll(mInitCallbacks); - mInitCallbacks.clear(); + initCallbacks.addAll(localRefCbs); + localRefCbs.clear(); } finally { mInitLock.writeLock().unlock(); } - mMainHandler.post(new ListenerDispatcher(initCallbacks, mLoadState, throwable)); + for (int i = 0; i < initCallbacks.size(); i++) { + initCallbacks.get(i).dispatchFailed(throwable); + } } /** @@ -741,14 +736,38 @@ public class EmojiCompat { */ @SuppressWarnings("ExecutorRegistration") public void registerInitCallback(@NonNull InitCallback initCallback) { - Preconditions.checkNotNull(initCallback, "initCallback cannot be null"); + registerInitCallback(ConcurrencyHelpers.mainThreadExecutor(), initCallback); + } + /** + * Registers an initialization callback. If the initialization is already completed by the time + * the listener is added, the callback functions are called immediately. + *

+ * When used on devices running API 18 or below, {@link InitCallback#onInitialized()} is called + * without loading any metadata. In such cases {@link InitCallback#onFailed(Throwable)} is never + * called. + * + * @param executor executor to dispatch callback on + * @param initCallback the initialization callback to register, cannot be {@code null} + * + * @see #unregisterInitCallback(InitCallback) + */ + public void registerInitCallback(@NonNull Executor executor, + @NonNull InitCallback initCallback) { + Preconditions.checkNotNull(initCallback, "initCallback cannot be null"); + Preconditions.checkNotNull(executor, "executor cannot be null"); + + InitWithExecutor newCb = new InitWithExecutor(executor, initCallback); mInitLock.writeLock().lock(); try { - if (mLoadState == LOAD_STATE_SUCCEEDED || mLoadState == LOAD_STATE_FAILED) { - mMainHandler.post(new ListenerDispatcher(initCallback, mLoadState)); + if (mLoadState == LOAD_STATE_SUCCEEDED) { + newCb.dispatchInitialized(); + } else if (mLoadState == LOAD_STATE_FAILED) { + newCb.dispatchFailed(new IllegalStateException("Initialization failed prior to " + + "registering this callback, please add an initialization callback to " + + "the EmojiCompat.Config instead to see the cause.")); } else { - mInitCallbacks.add(initCallback); + mInitCallbacks.add(newCb); } } finally { mInitLock.writeLock().unlock(); @@ -764,7 +783,15 @@ public class EmojiCompat { Preconditions.checkNotNull(initCallback, "initCallback cannot be null"); mInitLock.writeLock().lock(); try { - mInitCallbacks.remove(initCallback); + ArrayList toRemove = new ArrayList<>(); + for (InitWithExecutor item : mInitCallbacks) { + if (item.mInitCallback == initCallback) { + toRemove.add(item); + } + } + for (InitWithExecutor item : toRemove) { + mInitCallbacks.remove(item); + } } finally { mInitLock.writeLock().unlock(); } @@ -859,11 +886,7 @@ public class EmojiCompat { */ public static boolean handleOnKeyDown(@NonNull final Editable editable, final int keyCode, @NonNull final KeyEvent event) { - if (Build.VERSION.SDK_INT >= 19) { - return EmojiProcessor.handleOnKeyDown(editable, keyCode, event); - } else { - return false; - } + return EmojiProcessor.handleOnKeyDown(editable, keyCode, event); } /** @@ -888,12 +911,8 @@ public class EmojiCompat { @NonNull final InputConnection inputConnection, @NonNull final Editable editable, @IntRange(from = 0) final int beforeLength, @IntRange(from = 0) final int afterLength, final boolean inCodePoints) { - if (Build.VERSION.SDK_INT >= 19) { - return EmojiProcessor.handleDeleteSurroundingText(inputConnection, editable, - beforeLength, afterLength, inCodePoints); - } else { - return false; - } + return EmojiProcessor.handleDeleteSurroundingText(inputConnection, editable, + beforeLength, afterLength, inCodePoints); } /** @@ -1190,7 +1209,6 @@ public class EmojiCompat { * * @return EmojiSpan instance that can use TypefaceEmojiRasterizer to draw emoji. */ - @RequiresApi(19) @NonNull EmojiSpan createSpan(@NonNull TypefaceEmojiRasterizer rasterizer); } @@ -1209,7 +1227,6 @@ public class EmojiCompat { * * @return {@link TypefaceEmojiSpan} */ - @RequiresApi(19) @NonNull @Override public EmojiSpan createSpan(@NonNull TypefaceEmojiRasterizer rasterizer) { @@ -1252,6 +1269,24 @@ public class EmojiCompat { void load(@NonNull MetadataRepoLoaderCallback loaderCallback); } + private static final class InitWithExecutor { + InitCallback mInitCallback; + Executor mExecutor; + + InitWithExecutor(@NonNull Executor executor, @NonNull InitCallback initCallback) { + mInitCallback = initCallback; + mExecutor = executor; + } + + void dispatchInitialized() { + mExecutor.execute(() -> mInitCallback.onInitialized()); + } + + void dispatchFailed(Throwable throwable) { + mExecutor.execute(() -> mInitCallback.onFailed(throwable)); + } + } + /** * Interface to check if a given emoji exists on the system. */ @@ -1286,7 +1321,7 @@ public class EmojiCompat { * 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} + * {@sample 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} @@ -1349,7 +1384,7 @@ public class EmojiCompat { int[] mEmojiAsDefaultStyleExceptions; @SuppressWarnings("WeakerAccess") /* synthetic access */ @Nullable - Set mInitCallbacks; + Set mInitCallbacks; @SuppressWarnings("WeakerAccess") /* synthetic access */ boolean mEmojiSpanIndicatorEnabled; @SuppressWarnings("WeakerAccess") /* synthetic access */ @@ -1380,13 +1415,27 @@ public class EmojiCompat { @SuppressWarnings("ExecutorRegistration") @NonNull public Config registerInitCallback(@NonNull InitCallback initCallback) { + registerInitCallback(ConcurrencyHelpers.mainThreadExecutor(), initCallback); + return this; + } + + /** + * Registers an initialization callback. + * + * @param executor executor to dispatch callback on + * @param initCallback the initialization callback to register, cannot be {@code null} + * + * @return EmojiCompat.Config instance + */ + @NonNull + public Config registerInitCallback(@NonNull Executor executor, + @NonNull InitCallback initCallback) { Preconditions.checkNotNull(initCallback, "initCallback cannot be null"); + Preconditions.checkNotNull(executor, "executor cannot be null"); if (mInitCallbacks == null) { mInitCallbacks = new ArraySet<>(); } - - mInitCallbacks.add(initCallback); - + mInitCallbacks.add(new InitWithExecutor(executor, initCallback)); return this; } @@ -1401,7 +1450,15 @@ public class EmojiCompat { public Config unregisterInitCallback(@NonNull InitCallback initCallback) { Preconditions.checkNotNull(initCallback, "initCallback cannot be null"); if (mInitCallbacks != null) { - mInitCallbacks.remove(initCallback); + ArrayList toRemove = new ArrayList<>(); + for (InitWithExecutor item : mInitCallbacks) { + if (item.mInitCallback == initCallback) { + toRemove.add(item); + } + } + for (InitWithExecutor item : toRemove) { + mInitCallbacks.remove(item); + } } return this; } @@ -1576,112 +1633,7 @@ public class EmojiCompat { } } - /** - * Runnable to call success/failure case for the listeners. - */ - private static class ListenerDispatcher implements Runnable { - private final List mInitCallbacks; - private final Throwable mThrowable; - private final int mLoadState; - - @SuppressWarnings("ArraysAsListWithZeroOrOneArgument") - ListenerDispatcher(@NonNull final InitCallback initCallback, - @LoadState final int loadState) { - this(Arrays.asList(Preconditions.checkNotNull(initCallback, - "initCallback cannot be null")), loadState, null); - } - - ListenerDispatcher(@NonNull final Collection initCallbacks, - @LoadState final int loadState) { - this(initCallbacks, loadState, null); - } - - ListenerDispatcher(@NonNull final Collection initCallbacks, - @LoadState final int loadState, - @Nullable final Throwable throwable) { - Preconditions.checkNotNull(initCallbacks, "initCallbacks cannot be null"); - mInitCallbacks = new ArrayList<>(initCallbacks); - mLoadState = loadState; - mThrowable = throwable; - } - - @Override - public void run() { - final int size = mInitCallbacks.size(); - switch (mLoadState) { - case LOAD_STATE_SUCCEEDED: - for (int i = 0; i < size; i++) { - mInitCallbacks.get(i).onInitialized(); - } - break; - case LOAD_STATE_FAILED: - default: - for (int i = 0; i < size; i++) { - mInitCallbacks.get(i).onFailed(mThrowable); - } - break; - } - } - } - - /** - * Internal helper class to behave no-op for certain functions. - */ - private static class CompatInternal { - final EmojiCompat mEmojiCompat; - - CompatInternal(EmojiCompat emojiCompat) { - mEmojiCompat = emojiCompat; - } - - void loadMetadata() { - // Moves into LOAD_STATE_SUCCESS state immediately. - mEmojiCompat.onMetadataLoadSuccess(); - } - - boolean hasEmojiGlyph(@NonNull final CharSequence sequence) { - // Since no metadata is loaded, EmojiCompat cannot detect or render any emojis. - return false; - } - - boolean hasEmojiGlyph(@NonNull final CharSequence sequence, final int metadataVersion) { - // Since no metadata is loaded, EmojiCompat cannot detect or render any emojis. - return false; - } - - int getEmojiStart(@NonNull final CharSequence cs, @IntRange(from = 0) final int offset) { - // Since no metadata is loaded, EmojiCompat cannot detect any emojis. - return -1; - } - - int getEmojiEnd(@NonNull final CharSequence cs, @IntRange(from = 0) final int offset) { - // Since no metadata is loaded, EmojiCompat cannot detect any emojis. - return -1; - } - - CharSequence process(@NonNull final CharSequence charSequence, - @IntRange(from = 0) final int start, @IntRange(from = 0) final int end, - @IntRange(from = 0) final int maxEmojiCount, boolean replaceAll) { - // Returns the given charSequence as it is. - return charSequence; - } - - void updateEditorInfoAttrs(@NonNull final EditorInfo outAttrs) { - // Does not add any EditorInfo attributes. - } - - String getAssetSignature() { - return ""; - } - - @CodepointSequenceMatchResult - public int getEmojiMatch(CharSequence sequence, int metadataVersion) { - return EMOJI_UNSUPPORTED; - } - } - - @RequiresApi(19) - private static final class CompatInternal19 extends CompatInternal { + private static final class CompatInternal { /** * Responsible to process a CharSequence and add the spans. @{code Null} until the time the * metadata is loaded. @@ -1692,13 +1644,12 @@ public class EmojiCompat { * Keeps the information about emojis. Null until the time the data is loaded. */ private volatile MetadataRepo mMetadataRepo; + private final EmojiCompat mEmojiCompat; - - CompatInternal19(EmojiCompat emojiCompat) { - super(emojiCompat); + CompatInternal(EmojiCompat emojiCompat) { + mEmojiCompat = emojiCompat; } - @Override void loadMetadata() { try { final MetadataRepoLoaderCallback callback = new MetadataRepoLoaderCallback() { @@ -1718,7 +1669,6 @@ public class EmojiCompat { } } - @SuppressWarnings("SyntheticAccessor") void onMetadataLoadSuccess(@NonNull final MetadataRepo metadataRepo) { //noinspection ConstantConditions if (metadataRepo == null) { @@ -1740,45 +1690,37 @@ public class EmojiCompat { mEmojiCompat.onMetadataLoadSuccess(); } - @Override boolean hasEmojiGlyph(@NonNull CharSequence sequence) { return mProcessor.getEmojiMatch(sequence) == EMOJI_SUPPORTED; } - @Override boolean hasEmojiGlyph(@NonNull CharSequence sequence, int metadataVersion) { int emojiMatch = mProcessor.getEmojiMatch(sequence, metadataVersion); return emojiMatch == EMOJI_SUPPORTED; } - @Override public int getEmojiMatch(CharSequence sequence, int metadataVersion) { return mProcessor.getEmojiMatch(sequence, metadataVersion); } - @Override int getEmojiStart(@NonNull final CharSequence sequence, final int offset) { return mProcessor.getEmojiStart(sequence, offset); } - @Override int getEmojiEnd(@NonNull final CharSequence sequence, final int offset) { return mProcessor.getEmojiEnd(sequence, offset); } - @Override CharSequence process(@NonNull CharSequence charSequence, int start, int end, int maxEmojiCount, boolean replaceAll) { return mProcessor.process(charSequence, start, end, maxEmojiCount, replaceAll); } - @Override void updateEditorInfoAttrs(@NonNull EditorInfo outAttrs) { outAttrs.extras.putInt(EDITOR_INFO_METAVERSION_KEY, mMetadataRepo.getMetadataVersion()); outAttrs.extras.putBoolean(EDITOR_INFO_REPLACE_ALL_KEY, mEmojiCompat.mReplaceAll); } - @Override String getAssetSignature() { final String sha = mMetadataRepo.getMetadataList().sourceSha(); return sha == null ? "" : sha; diff --git a/app/src/main/java/androidx/emoji2/text/EmojiCompatInitializer.java b/app/src/main/java/androidx/emoji2/text/EmojiCompatInitializer.java index f4823bf095..806f76aab8 100644 --- a/app/src/main/java/androidx/emoji2/text/EmojiCompatInitializer.java +++ b/app/src/main/java/androidx/emoji2/text/EmojiCompatInitializer.java @@ -17,12 +17,10 @@ package androidx.emoji2.text; import android.content.Context; -import android.os.Build; import android.os.Handler; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.annotation.RequiresApi; import androidx.annotation.WorkerThread; import androidx.core.os.TraceCompat; import androidx.lifecycle.DefaultLifecycleObserver; @@ -84,12 +82,9 @@ public class EmojiCompatInitializer implements Initializer { @NonNull @Override public Boolean create(@NonNull Context context) { - if (Build.VERSION.SDK_INT >= 19) { - EmojiCompat.init(new BackgroundDefaultConfig(context)); - delayUntilFirstResume(context); - return true; - } - return false; + EmojiCompat.init(new BackgroundDefaultConfig(context)); + delayUntilFirstResume(context); + return true; } /** @@ -97,7 +92,6 @@ public class EmojiCompatInitializer implements Initializer { * * This allows startup code to run before the delay is scheduled. */ - @RequiresApi(19) void delayUntilFirstResume(@NonNull Context context) { // schedule delay after first Activity resumes AppInitializer appInitializer = AppInitializer.getInstance(context); @@ -113,7 +107,6 @@ public class EmojiCompatInitializer implements Initializer { }); } - @RequiresApi(19) void loadEmojiCompatAfterDelay() { final Handler mainHandler = ConcurrencyHelpers.mainHandlerAsync(); mainHandler.postDelayed(new LoadEmojiCompatRunnable(), STARTUP_THREAD_CREATION_DELAY_MS); @@ -144,7 +137,6 @@ public class EmojiCompatInitializer implements Initializer { } } - @RequiresApi(19) static class BackgroundDefaultConfig extends EmojiCompat.Config { protected BackgroundDefaultConfig(Context context) { super(new BackgroundDefaultLoader(context)); @@ -152,7 +144,6 @@ public class EmojiCompatInitializer implements Initializer { } } - @RequiresApi(19) static class BackgroundDefaultLoader implements EmojiCompat.MetadataRepoLoader { private final Context mContext; diff --git a/app/src/main/java/androidx/emoji2/text/EmojiExclusions.java b/app/src/main/java/androidx/emoji2/text/EmojiExclusions.java index f93959c831..bfe58068cd 100644 --- a/app/src/main/java/androidx/emoji2/text/EmojiExclusions.java +++ b/app/src/main/java/androidx/emoji2/text/EmojiExclusions.java @@ -19,7 +19,6 @@ package androidx.emoji2.text; import android.annotation.SuppressLint; import android.os.Build; -import androidx.annotation.DoNotInline; import androidx.annotation.NonNull; import androidx.annotation.RequiresApi; @@ -44,7 +43,6 @@ class EmojiExclusions { private EmojiExclusions_Api34() { /* cannot instantiate */ } @NonNull - @DoNotInline static Set getExclusions() { // TODO: Call directly when API34 is published return EmojiExclusions_Reflections.getExclusions(); diff --git a/app/src/main/java/androidx/emoji2/text/EmojiProcessor.java b/app/src/main/java/androidx/emoji2/text/EmojiProcessor.java index 7b388fb528..8021d42aa1 100644 --- a/app/src/main/java/androidx/emoji2/text/EmojiProcessor.java +++ b/app/src/main/java/androidx/emoji2/text/EmojiProcessor.java @@ -33,7 +33,6 @@ import androidx.annotation.IntDef; import androidx.annotation.IntRange; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.annotation.RequiresApi; import androidx.annotation.RestrictTo; import java.lang.annotation.Retention; @@ -48,7 +47,6 @@ import java.util.Set; */ @AnyThread @RestrictTo(LIBRARY) -@RequiresApi(19) final class EmojiProcessor { /** @@ -781,7 +779,6 @@ final class EmojiProcessor { /** * Copy of BaseInputConnection findIndexBackward and findIndexForward functions. */ - @RequiresApi(19) private static final class CodepointIndexFinder { private static final int INVALID_INDEX = -1; diff --git a/app/src/main/java/androidx/emoji2/text/EmojiSpan.java b/app/src/main/java/androidx/emoji2/text/EmojiSpan.java index d106a87d9f..dcbec1aa69 100644 --- a/app/src/main/java/androidx/emoji2/text/EmojiSpan.java +++ b/app/src/main/java/androidx/emoji2/text/EmojiSpan.java @@ -23,7 +23,6 @@ import android.text.style.ReplacementSpan; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.annotation.RequiresApi; import androidx.annotation.RestrictTo; import androidx.annotation.VisibleForTesting; import androidx.core.util.Preconditions; @@ -32,7 +31,6 @@ import androidx.core.util.Preconditions; * Base span class for the emoji replacement. When an emoji is found and needs to be replaced in a * CharSequence, an instance of this class is added to the CharSequence. */ -@RequiresApi(19) public abstract class EmojiSpan extends ReplacementSpan { /** diff --git a/app/src/main/java/androidx/emoji2/text/FontRequestEmojiCompatConfig.java b/app/src/main/java/androidx/emoji2/text/FontRequestEmojiCompatConfig.java index 62a55d075c..35e6b5874a 100644 --- a/app/src/main/java/androidx/emoji2/text/FontRequestEmojiCompatConfig.java +++ b/app/src/main/java/androidx/emoji2/text/FontRequestEmojiCompatConfig.java @@ -27,7 +27,6 @@ import android.os.SystemClock; import androidx.annotation.GuardedBy; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.annotation.RequiresApi; import androidx.annotation.RestrictTo; import androidx.annotation.WorkerThread; import androidx.core.graphics.TypefaceCompatUtil; @@ -252,7 +251,6 @@ public class FontRequestEmojiCompatConfig extends EmojiCompat.Config { } @Override - @RequiresApi(19) public void load(@NonNull final EmojiCompat.MetadataRepoLoaderCallback loaderCallback) { Preconditions.checkNotNull(loaderCallback, "LoaderCallback cannot be null"); synchronized (mLock) { @@ -261,7 +259,6 @@ public class FontRequestEmojiCompatConfig extends EmojiCompat.Config { loadInternal(); } - @RequiresApi(19) void loadInternal() { synchronized (mLock) { if (mCallback == null) { @@ -295,7 +292,6 @@ public class FontRequestEmojiCompatConfig extends EmojiCompat.Config { return fonts[0]; // Assuming the GMS Core provides only one font file. } - @RequiresApi(19) @WorkerThread private void scheduleRetry(Uri uri, long waitMs) { synchronized (mLock) { @@ -342,7 +338,6 @@ public class FontRequestEmojiCompatConfig extends EmojiCompat.Config { } // Must be called on the mHandler. - @RequiresApi(19) @SuppressWarnings("WeakerAccess") /* synthetic access */ @WorkerThread void createMetadata() { diff --git a/app/src/main/java/androidx/emoji2/text/MetadataListReader.java b/app/src/main/java/androidx/emoji2/text/MetadataListReader.java index f9fde4bb9a..2f40123d60 100644 --- a/app/src/main/java/androidx/emoji2/text/MetadataListReader.java +++ b/app/src/main/java/androidx/emoji2/text/MetadataListReader.java @@ -20,7 +20,6 @@ import android.content.res.AssetManager; import androidx.annotation.AnyThread; import androidx.annotation.IntRange; import androidx.annotation.NonNull; -import androidx.annotation.RequiresApi; import androidx.annotation.RestrictTo; import androidx.emoji2.text.flatbuffer.MetadataList; @@ -35,7 +34,6 @@ import java.nio.ByteOrder; */ @RestrictTo(RestrictTo.Scope.LIBRARY) @AnyThread -@RequiresApi(19) class MetadataListReader { /** diff --git a/app/src/main/java/androidx/emoji2/text/MetadataRepo.java b/app/src/main/java/androidx/emoji2/text/MetadataRepo.java index 5835cb348c..7077619887 100644 --- a/app/src/main/java/androidx/emoji2/text/MetadataRepo.java +++ b/app/src/main/java/androidx/emoji2/text/MetadataRepo.java @@ -23,7 +23,6 @@ import android.util.SparseArray; import androidx.annotation.AnyThread; import androidx.annotation.NonNull; -import androidx.annotation.RequiresApi; import androidx.annotation.RestrictTo; import androidx.annotation.VisibleForTesting; import androidx.core.os.TraceCompat; @@ -38,7 +37,6 @@ import java.nio.ByteBuffer; * Class to hold the emoji metadata required to process and draw emojis. */ @AnyThread -@RequiresApi(19) public final class MetadataRepo { /** * The default children size of the root node. diff --git a/app/src/main/java/androidx/emoji2/text/TypefaceEmojiRasterizer.java b/app/src/main/java/androidx/emoji2/text/TypefaceEmojiRasterizer.java index cd45cd2d1d..7a42118d22 100644 --- a/app/src/main/java/androidx/emoji2/text/TypefaceEmojiRasterizer.java +++ b/app/src/main/java/androidx/emoji2/text/TypefaceEmojiRasterizer.java @@ -27,7 +27,6 @@ import androidx.annotation.AnyThread; import androidx.annotation.IntDef; import androidx.annotation.IntRange; import androidx.annotation.NonNull; -import androidx.annotation.RequiresApi; import androidx.annotation.RestrictTo; import androidx.annotation.VisibleForTesting; import androidx.emoji2.text.flatbuffer.MetadataItem; @@ -50,7 +49,6 @@ import java.lang.annotation.RetentionPolicy; * */ @AnyThread -@RequiresApi(19) public class TypefaceEmojiRasterizer { /** * Defines whether the system can render the emoji. diff --git a/app/src/main/java/androidx/emoji2/text/TypefaceEmojiSpan.java b/app/src/main/java/androidx/emoji2/text/TypefaceEmojiSpan.java index 7595fd53b3..09655364c4 100644 --- a/app/src/main/java/androidx/emoji2/text/TypefaceEmojiSpan.java +++ b/app/src/main/java/androidx/emoji2/text/TypefaceEmojiSpan.java @@ -26,7 +26,6 @@ import android.text.style.MetricAffectingSpan; import androidx.annotation.IntRange; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.annotation.RequiresApi; import androidx.annotation.RestrictTo; /** @@ -34,7 +33,6 @@ import androidx.annotation.RestrictTo; * */ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) -@RequiresApi(19) public final class TypefaceEmojiSpan extends EmojiSpan { /** diff --git a/patches/emoji.patch b/patches/emoji.patch new file mode 100644 index 0000000000..b523bd5108 --- /dev/null +++ b/patches/emoji.patch @@ -0,0 +1,13 @@ +diff --git a/app/src/main/java/androidx/emoji2/text/SpannableBuilder.java b/app/src/main/java/androidx/emoji2/text/SpannableBuilder.java +index 366c7b3629..e6fef5cddb 100644 +--- a/app/src/main/java/androidx/emoji2/text/SpannableBuilder.java ++++ b/app/src/main/java/androidx/emoji2/text/SpannableBuilder.java +@@ -46,7 +46,7 @@ import java.util.concurrent.atomic.AtomicInteger; + * + */ + @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) +-public final class SpannableBuilder extends SpannableStringBuilder { ++public final class SpannableBuilder extends eu.faircode.email.SpannableStringBuilderEx { + /** + * DynamicLayout$ChangeWatcher class. + */