From 702a66950f96eca8cff95d0da83829c24b77ab66 Mon Sep 17 00:00:00 2001 From: Kirill Zyusko Date: Tue, 19 Dec 2023 08:18:22 +0100 Subject: [PATCH] fix: ignore non-keyboard animations (#300) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 📜 Description Check that current animation is a keyboard one. If not, then do not send any events to JS. ## 💡 Motivation and Context Since we add generic `WindowInsetsAnimationCompat.Callback` -> its callbacks (`onStart`/`onProgress`/`onEnd`) can be called even when keyboard is not performing an animation. Thus it's important to filter out which events are keyboard-related and which one are not. Initially I copied an example from [Google samples](https://github.com/android/platform-samples/tree/main/samples/user-interface/window-insets), but their example code didn't have these checks. I assume it's because they had only one screen and it wasn't possible to run other insets animation. However in [Android documentation](https://developer.android.com/develop/ui/views/layout/sw-keyboard#synchronize-animation) in code sample they added a check to filter out non-keyboard animations. So taking all the information from above I decided to add these checks and add early return statements to react only on keyboard animation events. The similar approach was added in next projects: - [Telegram](https://github.com/DrKLO/Telegram/blob/33a48d8945654afdb99df778647251cc2fca4bcc/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/AdjustPanLayoutHelper.java#L411-L423) - [Signal](https://github.com/signalapp/Signal-Android/blob/10a363248ea7bba0cacac3385bee5cc2fff280cd/app/src/main/java/org/thoughtcrime/securesms/components/InsetAwareConstraintLayout.kt#L244-L247) ## 📢 Changelog ### Android - added `WindowInsetsAnimationCompat` extension (new `isKeyboardAnimation` field); - return from `onStart`/`onProgress`/`onEnd` callbacks if provided animation is not keyboard animation. ## 🤔 How Has This Been Tested? Tested on: - e2e ## 📸 Screenshots (if appropriate): No visual difference 🤷‍♂️ ## 📝 Checklist - [x] CI successfully passed --- .../extensions/WindowInsetsAnimationCompat.kt | 7 +++++++ .../listeners/KeyboardAnimationCallback.kt | 12 ++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 android/src/main/java/com/reactnativekeyboardcontroller/extensions/WindowInsetsAnimationCompat.kt diff --git a/android/src/main/java/com/reactnativekeyboardcontroller/extensions/WindowInsetsAnimationCompat.kt b/android/src/main/java/com/reactnativekeyboardcontroller/extensions/WindowInsetsAnimationCompat.kt new file mode 100644 index 000000000..9be782732 --- /dev/null +++ b/android/src/main/java/com/reactnativekeyboardcontroller/extensions/WindowInsetsAnimationCompat.kt @@ -0,0 +1,7 @@ +package com.reactnativekeyboardcontroller.extensions + +import androidx.core.view.WindowInsetsAnimationCompat +import androidx.core.view.WindowInsetsCompat + +val WindowInsetsAnimationCompat.isKeyboardAnimation: Boolean + get() = typeMask and WindowInsetsCompat.Type.ime() != 0 diff --git a/android/src/main/java/com/reactnativekeyboardcontroller/listeners/KeyboardAnimationCallback.kt b/android/src/main/java/com/reactnativekeyboardcontroller/listeners/KeyboardAnimationCallback.kt index 1bb4f0101..7451cb5e5 100644 --- a/android/src/main/java/com/reactnativekeyboardcontroller/listeners/KeyboardAnimationCallback.kt +++ b/android/src/main/java/com/reactnativekeyboardcontroller/listeners/KeyboardAnimationCallback.kt @@ -22,6 +22,7 @@ import com.reactnativekeyboardcontroller.InteractiveKeyboardProvider import com.reactnativekeyboardcontroller.events.KeyboardTransitionEvent import com.reactnativekeyboardcontroller.extensions.dispatchEvent import com.reactnativekeyboardcontroller.extensions.dp +import com.reactnativekeyboardcontroller.extensions.isKeyboardAnimation import kotlin.math.abs private val TAG = KeyboardAnimationCallback::class.qualifiedName @@ -142,6 +143,10 @@ class KeyboardAnimationCallback( animation: WindowInsetsAnimationCompat, bounds: WindowInsetsAnimationCompat.BoundsCompat, ): WindowInsetsAnimationCompat.BoundsCompat { + if (!animation.isKeyboardAnimation) { + return bounds + } + isTransitioning = true isKeyboardVisible = isKeyboardVisible() duration = animation.durationMillis.toInt() @@ -181,6 +186,9 @@ class KeyboardAnimationCallback( ): WindowInsetsCompat { // onProgress() is called when any of the running animations progress... + // ignore non-keyboard animation + runningAnimations.find { it.isKeyboardAnimation } ?: return insets + // First we get the insets which are potentially deferred val typesInset = insets.getInsets(deferredInsetTypes) // Then we get the persistent inset types which are applied as padding during layout @@ -226,6 +234,10 @@ class KeyboardAnimationCallback( override fun onEnd(animation: WindowInsetsAnimationCompat) { super.onEnd(animation) + if (!animation.isKeyboardAnimation) { + return + } + isTransitioning = false duration = animation.durationMillis.toInt()