From 20ad2b3fbb036132d53be250a197cf977622c8f9 Mon Sep 17 00:00:00 2001 From: desmondyao Date: Mon, 27 Feb 2017 04:20:51 -0800 Subject: [PATCH] support api 15 (use Handler-backed ui driven). Summary: Android API 15 still have 1.5~2.0% distribution (refer: [Dashboard - Android Developer](https://developer.android.com/ndk/guides/standalone_toolchain.html#creating_the_toolchain)). React Native is a good tec but many companies cannot endure loose their consumer. [Choreographer](https://developer.android.com/reference/android/view/Choreographer.html) triggered UI operation is the only reason that React Native Android sdk use minSdkVersion 16, so we can use a backward solution **only in API 15**: [Handler](https://developer.android.com/reference/android/os/Handler.html). In this PR, the biggest change is : - Make core operation of ReactChoreographer to an interface: ReactUIDriver; - Impl ReactUIDriver by Handler => UIDriverHandlerImpl, refactor ReactChoreographer to UIDriverChoreographerImpl; - Let UIDriverFactory to choose which one impl would be in use. (Only use handler in api 15). Closes https://github.com/facebook/react-native/pull/12396 Reviewed By: AaaChiuuu Differential Revision: D4588399 Pulled By: astreet fbshipit-source-id: 76408e53664314dd926e6a553cde6bafbd37779e --- .../react/testing/ReactIdleDetectionUtil.java | 8 +- .../react/animated/NativeAnimatedModule.java | 6 +- .../java/com/facebook/react/devsupport/BUCK | 1 + .../facebook/react/devsupport/FpsView.java | 4 +- .../modules/core/ChoreographerCompat.java | 131 ++++++++++++++++++ .../modules/core/ReactChoreographer.java | 16 +-- .../facebook/react/modules/core/Timing.java | 25 ++-- .../modules/debug/AnimationsDebugModule.java | 14 +- .../com/facebook/react/modules/debug/BUCK | 1 + .../DidJSUpdateUiDuringFrameDetector.java | 7 +- .../modules/debug/FpsDebugFrameCallback.java | 13 +- ...allback.java => GuardedFrameCallback.java} | 7 +- .../react/uimanager/UIViewOperationQueue.java | 5 +- .../uimanager/events/EventDispatcher.java | 4 +- .../modules/timing/TimingModuleTest.java | 57 ++++---- .../react/uimanager/UIManagerModuleTest.java | 63 ++++----- .../react/views/text/ReactTextTest.java | 32 ++--- .../react/views/textinput/TextInputTest.java | 15 +- 18 files changed, 260 insertions(+), 149 deletions(-) create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/core/ChoreographerCompat.java rename ReactAndroid/src/main/java/com/facebook/react/uimanager/{GuardedChoreographerFrameCallback.java => GuardedFrameCallback.java} (84%) diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactIdleDetectionUtil.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactIdleDetectionUtil.java index 340dec834..49e221932 100644 --- a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactIdleDetectionUtil.java +++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactIdleDetectionUtil.java @@ -14,10 +14,10 @@ import java.util.concurrent.TimeUnit; import android.app.Instrumentation; import android.os.SystemClock; import android.support.test.InstrumentationRegistry; -import android.view.Choreographer; import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.UiThreadUtil; +import com.facebook.react.modules.core.ChoreographerCompat; public class ReactIdleDetectionUtil { @@ -56,8 +56,8 @@ public class ReactIdleDetectionUtil { new Runnable() { @Override public void run() { - Choreographer.getInstance().postFrameCallback( - new Choreographer.FrameCallback() { + ChoreographerCompat.getInstance().postFrameCallback( + new ChoreographerCompat.FrameCallback() { private int frameCount = 0; @@ -67,7 +67,7 @@ public class ReactIdleDetectionUtil { if (frameCount == waitFrameCount) { latch.countDown(); } else { - Choreographer.getInstance().postFrameCallback(this); + ChoreographerCompat.getInstance().postFrameCallback(this); } } }); diff --git a/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.java b/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.java index 8d61ae560..c5e2aa04f 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.java @@ -23,8 +23,8 @@ import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.WritableMap; import com.facebook.react.module.annotations.ReactModule; import com.facebook.react.modules.core.DeviceEventManagerModule; -import com.facebook.react.uimanager.GuardedChoreographerFrameCallback; import com.facebook.react.modules.core.ReactChoreographer; +import com.facebook.react.uimanager.GuardedFrameCallback; import com.facebook.react.uimanager.UIManagerModule; import java.util.ArrayList; @@ -79,7 +79,7 @@ public class NativeAnimatedModule extends ReactContextBaseJavaModule implements } private final Object mOperationsCopyLock = new Object(); - private @Nullable GuardedChoreographerFrameCallback mAnimatedFrameCallback; + private @Nullable GuardedFrameCallback mAnimatedFrameCallback; private @Nullable ReactChoreographer mReactChoreographer; private ArrayList mOperations = new ArrayList<>(); private volatile @Nullable ArrayList mReadyOperations = null; @@ -97,7 +97,7 @@ public class NativeAnimatedModule extends ReactContextBaseJavaModule implements UIManagerModule uiManager = reactCtx.getNativeModule(UIManagerModule.class); final NativeAnimatedNodesManager nodesManager = new NativeAnimatedNodesManager(uiManager); - mAnimatedFrameCallback = new GuardedChoreographerFrameCallback(reactCtx) { + mAnimatedFrameCallback = new GuardedFrameCallback(reactCtx) { @Override protected void doFrameGuarded(final long frameTimeNanos) { diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/BUCK b/ReactAndroid/src/main/java/com/facebook/react/devsupport/BUCK index 98de38d6e..b20d067bc 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/BUCK @@ -19,6 +19,7 @@ android_library( react_native_target("java/com/facebook/react/common/network:network"), react_native_target("java/com/facebook/react/devsupport:interfaces"), react_native_target("java/com/facebook/react/module/annotations:annotations"), + react_native_target('java/com/facebook/react/modules/core:core'), react_native_target("java/com/facebook/react/modules/debug:debug"), react_native_target("java/com/facebook/react/modules/debug:interfaces"), react_native_target("java/com/facebook/react/modules/systeminfo:systeminfo"), diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/FpsView.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/FpsView.java index 47d340b05..75dea0a30 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/FpsView.java +++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/FpsView.java @@ -12,7 +12,6 @@ package com.facebook.react.devsupport; import java.util.Locale; import android.annotation.TargetApi; -import android.view.Choreographer; import android.widget.FrameLayout; import android.widget.TextView; @@ -20,6 +19,7 @@ import com.facebook.common.logging.FLog; import com.facebook.react.R; import com.facebook.react.bridge.ReactContext; import com.facebook.react.common.ReactConstants; +import com.facebook.react.modules.core.ChoreographerCompat; import com.facebook.react.modules.debug.FpsDebugFrameCallback; /** @@ -41,7 +41,7 @@ public class FpsView extends FrameLayout { super(reactContext); inflate(reactContext, R.layout.fps_view, this); mTextView = (TextView) findViewById(R.id.fps_text); - mFrameCallback = new FpsDebugFrameCallback(Choreographer.getInstance(), reactContext); + mFrameCallback = new FpsDebugFrameCallback(ChoreographerCompat.getInstance(), reactContext); mFPSMonitorRunnable = new FPSMonitorRunnable(); setCurrentFPS(0, 0, 0, 0); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/core/ChoreographerCompat.java b/ReactAndroid/src/main/java/com/facebook/react/modules/core/ChoreographerCompat.java new file mode 100644 index 000000000..bfad94996 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/core/ChoreographerCompat.java @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2013, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * This file was pulled from the facebook/rebound repository. + */ +package com.facebook.react.modules.core; + +import android.annotation.TargetApi; +import android.os.Build; +import android.os.Handler; +import android.os.Looper; +import android.view.Choreographer; + +/** + * Wrapper class for abstracting away availability of the JellyBean Choreographer. If Choreographer + * is unavailable we fallback to using a normal Handler. + */ +public class ChoreographerCompat { + + private static final long ONE_FRAME_MILLIS = 17; + private static final boolean IS_JELLYBEAN_OR_HIGHER = + Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN; + private static final ChoreographerCompat INSTANCE = new ChoreographerCompat(); + + private Handler mHandler; + private Choreographer mChoreographer; + + public static ChoreographerCompat getInstance() { + return INSTANCE; + } + + private ChoreographerCompat() { + if (IS_JELLYBEAN_OR_HIGHER) { + mChoreographer = getChoreographer(); + } else { + mHandler = new Handler(Looper.getMainLooper()); + } + } + + public void postFrameCallback(FrameCallback callbackWrapper) { + if (IS_JELLYBEAN_OR_HIGHER) { + choreographerPostFrameCallback(callbackWrapper.getFrameCallback()); + } else { + mHandler.postDelayed(callbackWrapper.getRunnable(), 0); + } + } + + public void postFrameCallbackDelayed(FrameCallback callbackWrapper, long delayMillis) { + if (IS_JELLYBEAN_OR_HIGHER) { + choreographerPostFrameCallbackDelayed(callbackWrapper.getFrameCallback(), delayMillis); + } else { + mHandler.postDelayed(callbackWrapper.getRunnable(), delayMillis + ONE_FRAME_MILLIS); + } + } + + public void removeFrameCallback(FrameCallback callbackWrapper) { + if (IS_JELLYBEAN_OR_HIGHER) { + choreographerRemoveFrameCallback(callbackWrapper.getFrameCallback()); + } else { + mHandler.removeCallbacks(callbackWrapper.getRunnable()); + } + } + + @TargetApi(Build.VERSION_CODES.JELLY_BEAN) + private Choreographer getChoreographer() { + return Choreographer.getInstance(); + } + + @TargetApi(Build.VERSION_CODES.JELLY_BEAN) + private void choreographerPostFrameCallback(Choreographer.FrameCallback frameCallback) { + mChoreographer.postFrameCallback(frameCallback); + } + + @TargetApi(Build.VERSION_CODES.JELLY_BEAN) + private void choreographerPostFrameCallbackDelayed( + Choreographer.FrameCallback frameCallback, + long delayMillis) { + mChoreographer.postFrameCallbackDelayed(frameCallback, delayMillis); + } + + @TargetApi(Build.VERSION_CODES.JELLY_BEAN) + private void choreographerRemoveFrameCallback(Choreographer.FrameCallback frameCallback) { + mChoreographer.removeFrameCallback(frameCallback); + } + + /** + * This class provides a compatibility wrapper around the JellyBean FrameCallback with methods + * to access cached wrappers for submitting a real FrameCallback to a Choreographer or a Runnable + * to a Handler. + */ + public static abstract class FrameCallback { + + private Runnable mRunnable; + private Choreographer.FrameCallback mFrameCallback; + + @TargetApi(Build.VERSION_CODES.JELLY_BEAN) + Choreographer.FrameCallback getFrameCallback() { + if (mFrameCallback == null) { + mFrameCallback = new Choreographer.FrameCallback() { + @Override + public void doFrame(long frameTimeNanos) { + FrameCallback.this.doFrame(frameTimeNanos); + } + }; + } + return mFrameCallback; + } + + Runnable getRunnable() { + if (mRunnable == null) { + mRunnable = new Runnable() { + @Override + public void run() { + doFrame(System.nanoTime()); + } + }; + } + return mRunnable; + } + + /** + * Just a wrapper for frame callback, see {@link android.view.Choreographer.FrameCallback#doFrame(long)}. + */ + public abstract void doFrame(long frameTimeNanos); + } +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/core/ReactChoreographer.java b/ReactAndroid/src/main/java/com/facebook/react/modules/core/ReactChoreographer.java index c3d94e837..71aecde75 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/core/ReactChoreographer.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/core/ReactChoreographer.java @@ -11,8 +11,6 @@ package com.facebook.react.modules.core; import java.util.ArrayDeque; -import android.view.Choreographer; - import com.facebook.common.logging.FLog; import com.facebook.react.bridge.UiThreadUtil; import com.facebook.infer.annotation.Assertions; @@ -25,7 +23,7 @@ import com.facebook.react.common.ReactConstants; */ public class ReactChoreographer { - public static enum CallbackType { + public enum CallbackType { /** * For use by perf markers that need to happen immediately after draw @@ -75,15 +73,15 @@ public class ReactChoreographer { return sInstance; } - private final Choreographer mChoreographer; + private final ChoreographerCompat mChoreographer; private final ReactChoreographerDispatcher mReactChoreographerDispatcher; - private final ArrayDeque[] mCallbackQueues; + private final ArrayDeque[] mCallbackQueues; private int mTotalCallbacks = 0; private boolean mHasPostedCallback = false; private ReactChoreographer() { - mChoreographer = Choreographer.getInstance(); + mChoreographer = ChoreographerCompat.getInstance(); mReactChoreographerDispatcher = new ReactChoreographerDispatcher(); mCallbackQueues = new ArrayDeque[CallbackType.values().length]; for (int i = 0; i < mCallbackQueues.length; i++) { @@ -91,7 +89,7 @@ public class ReactChoreographer { } } - public void postFrameCallback(CallbackType type, Choreographer.FrameCallback frameCallback) { + public void postFrameCallback(CallbackType type, ChoreographerCompat.FrameCallback frameCallback) { UiThreadUtil.assertOnUiThread(); mCallbackQueues[type.getOrder()].addLast(frameCallback); mTotalCallbacks++; @@ -102,7 +100,7 @@ public class ReactChoreographer { } } - public void removeFrameCallback(CallbackType type, Choreographer.FrameCallback frameCallback) { + public void removeFrameCallback(CallbackType type, ChoreographerCompat.FrameCallback frameCallback) { UiThreadUtil.assertOnUiThread(); if (mCallbackQueues[type.getOrder()].removeFirstOccurrence(frameCallback)) { mTotalCallbacks--; @@ -120,7 +118,7 @@ public class ReactChoreographer { } } - private class ReactChoreographerDispatcher implements Choreographer.FrameCallback { + private class ReactChoreographerDispatcher extends ChoreographerCompat.FrameCallback { @Override public void doFrame(long frameTimeNanos) { diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/core/Timing.java b/ReactAndroid/src/main/java/com/facebook/react/modules/core/Timing.java index dca177c3a..c6da41a84 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/core/Timing.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/core/Timing.java @@ -22,7 +22,6 @@ import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; import android.util.SparseArray; -import android.view.Choreographer; import com.facebook.infer.annotation.Assertions; import com.facebook.react.bridge.Arguments; @@ -81,7 +80,7 @@ public final class Timing extends ReactContextBaseJavaModule implements Lifecycl } } - private class TimerFrameCallback implements Choreographer.FrameCallback { + private class TimerFrameCallback extends ChoreographerCompat.FrameCallback { // Temporary map for constructing the individual arrays of timers per ExecutorToken private final HashMap mTimersToCall = new HashMap<>(); @@ -131,7 +130,7 @@ public final class Timing extends ReactContextBaseJavaModule implements Lifecycl } } - private class IdleFrameCallback implements Choreographer.FrameCallback { + private class IdleFrameCallback extends ChoreographerCompat.FrameCallback { @Override public void doFrame(long frameTimeNanos) { @@ -248,14 +247,14 @@ public final class Timing extends ReactContextBaseJavaModule implements Lifecycl @Override public void onHostPause() { isPaused.set(true); - clearChoreographerCallback(); - maybeClearChoreographerIdleCallback(); + clearFrameCallback(); + maybeIdleCallback(); } @Override public void onHostDestroy() { - clearChoreographerCallback(); - maybeClearChoreographerIdleCallback(); + clearFrameCallback(); + maybeIdleCallback(); } @Override @@ -281,14 +280,14 @@ public final class Timing extends ReactContextBaseJavaModule implements Lifecycl HeadlessJsTaskContext.getInstance(getReactApplicationContext()); if (!headlessJsTaskContext.hasActiveTasks()) { isRunningTasks.set(false); - clearChoreographerCallback(); - maybeClearChoreographerIdleCallback(); + clearFrameCallback(); + maybeIdleCallback(); } } @Override public void onCatalystInstanceDestroy() { - clearChoreographerCallback(); + clearFrameCallback(); clearChoreographerIdleCallback(); HeadlessJsTaskContext headlessJsTaskContext = HeadlessJsTaskContext.getInstance(getReactApplicationContext()); @@ -303,9 +302,9 @@ public final class Timing extends ReactContextBaseJavaModule implements Lifecycl } } - private void maybeClearChoreographerIdleCallback() { + private void maybeIdleCallback() { if (isPaused.get() && !isRunningTasks.get()) { - clearChoreographerCallback(); + clearFrameCallback(); } } @@ -318,7 +317,7 @@ public final class Timing extends ReactContextBaseJavaModule implements Lifecycl } } - private void clearChoreographerCallback() { + private void clearFrameCallback() { HeadlessJsTaskContext headlessJsTaskContext = HeadlessJsTaskContext.getInstance(getReactApplicationContext()); if (mFrameCallbackPosted && isPaused.get() && diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/debug/AnimationsDebugModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/debug/AnimationsDebugModule.java index fffc74efd..5e991d4c4 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/debug/AnimationsDebugModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/debug/AnimationsDebugModule.java @@ -13,8 +13,6 @@ import javax.annotation.Nullable; import java.util.Locale; -import android.os.Build; -import android.view.Choreographer; import android.widget.Toast; import com.facebook.common.logging.FLog; @@ -24,6 +22,7 @@ import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactMethod; import com.facebook.react.common.ReactConstants; import com.facebook.react.module.annotations.ReactModule; +import com.facebook.react.modules.core.ChoreographerCompat; import com.facebook.react.modules.debug.interfaces.DeveloperSettings; /** @@ -60,10 +59,9 @@ public class AnimationsDebugModule extends ReactContextBaseJavaModule { if (mFrameCallback != null) { throw new JSApplicationCausedNativeException("Already recording FPS!"); } - checkAPILevel(); mFrameCallback = new FpsDebugFrameCallback( - Choreographer.getInstance(), + ChoreographerCompat.getInstance(), getReactApplicationContext()); mFrameCallback.startAndRecordFpsAtEachFrame(); } @@ -78,7 +76,6 @@ public class AnimationsDebugModule extends ReactContextBaseJavaModule { if (mFrameCallback == null) { return; } - checkAPILevel(); mFrameCallback.stop(); @@ -116,11 +113,4 @@ public class AnimationsDebugModule extends ReactContextBaseJavaModule { mFrameCallback = null; } } - - private static void checkAPILevel() { - if (Build.VERSION.SDK_INT < 16) { - throw new JSApplicationCausedNativeException( - "Animation debugging is not supported in API <16"); - } - } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/debug/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/debug/BUCK index 7888f4b27..ef375d657 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/debug/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/debug/BUCK @@ -13,6 +13,7 @@ android_library( react_native_target("java/com/facebook/react/bridge:bridge"), react_native_target("java/com/facebook/react/common:common"), react_native_target("java/com/facebook/react/module/annotations:annotations"), + react_native_target('java/com/facebook/react/modules/core:core'), react_native_target("java/com/facebook/react/modules/debug:interfaces"), react_native_target("java/com/facebook/react/uimanager:uimanager"), ], diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/debug/DidJSUpdateUiDuringFrameDetector.java b/ReactAndroid/src/main/java/com/facebook/react/modules/debug/DidJSUpdateUiDuringFrameDetector.java index f15a143df..3f5876a4c 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/debug/DidJSUpdateUiDuringFrameDetector.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/debug/DidJSUpdateUiDuringFrameDetector.java @@ -9,11 +9,10 @@ package com.facebook.react.modules.debug; -import android.view.Choreographer; - import com.facebook.react.bridge.ReactBridge; import com.facebook.react.bridge.NotThreadSafeBridgeIdleDebugListener; import com.facebook.react.common.LongArray; +import com.facebook.react.modules.core.ChoreographerCompat; import com.facebook.react.uimanager.UIManagerModule; import com.facebook.react.uimanager.debug.NotThreadSafeViewHierarchyUpdateDebugListener; @@ -22,7 +21,7 @@ import com.facebook.react.uimanager.debug.NotThreadSafeViewHierarchyUpdateDebugL * to calculate whether JS was able to update the UI during a given frame. After being installed * on a {@link ReactBridge} and a {@link UIManagerModule}, * {@link #getDidJSHitFrameAndCleanup} should be called once per frame via a - * {@link Choreographer.FrameCallback}. + * {@link ChoreographerCompat.FrameCallback}. */ public class DidJSUpdateUiDuringFrameDetector implements NotThreadSafeBridgeIdleDebugListener, NotThreadSafeViewHierarchyUpdateDebugListener { @@ -56,7 +55,7 @@ public class DidJSUpdateUiDuringFrameDetector implements NotThreadSafeBridgeIdle } /** - * Designed to be called from a {@link Choreographer.FrameCallback#doFrame} call. + * Designed to be called from a {@link ChoreographerCompat.FrameCallback#doFrame} call. * * There are two 'success' cases that will cause {@link #getDidJSHitFrameAndCleanup} to * return true for a given frame: diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/debug/FpsDebugFrameCallback.java b/ReactAndroid/src/main/java/com/facebook/react/modules/debug/FpsDebugFrameCallback.java index 1eac40fae..eda077bab 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/debug/FpsDebugFrameCallback.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/debug/FpsDebugFrameCallback.java @@ -14,10 +14,8 @@ import javax.annotation.Nullable; import java.util.Map; import java.util.TreeMap; -import android.annotation.TargetApi; -import android.view.Choreographer; - import com.facebook.react.bridge.ReactContext; +import com.facebook.react.modules.core.ChoreographerCompat; import com.facebook.react.uimanager.UIManagerModule; import com.facebook.infer.annotation.Assertions; @@ -30,11 +28,8 @@ import com.facebook.infer.annotation.Assertions; * Also records the JS FPS, i.e. the frames per second with which either JS updated the UI or was * idle and not trying to update the UI. This is different from the FPS above since JS rendering is * async. - * - * TargetApi 16 for use of Choreographer. */ -@TargetApi(16) -public class FpsDebugFrameCallback implements Choreographer.FrameCallback { +public class FpsDebugFrameCallback extends ChoreographerCompat.FrameCallback { public static class FpsInfo { @@ -66,7 +61,7 @@ public class FpsDebugFrameCallback implements Choreographer.FrameCallback { private static final double EXPECTED_FRAME_TIME = 16.9; - private final Choreographer mChoreographer; + private final ChoreographerCompat mChoreographer; private final ReactContext mReactContext; private final UIManagerModule mUIManagerModule; private final DidJSUpdateUiDuringFrameDetector mDidJSUpdateUiDuringFrameDetector; @@ -81,7 +76,7 @@ public class FpsDebugFrameCallback implements Choreographer.FrameCallback { private boolean mIsRecordingFpsInfoAtEachFrame = false; private @Nullable TreeMap mTimeToFps; - public FpsDebugFrameCallback(Choreographer choreographer, ReactContext reactContext) { + public FpsDebugFrameCallback(ChoreographerCompat choreographer, ReactContext reactContext) { mChoreographer = choreographer; mReactContext = reactContext; mUIManagerModule = reactContext.getNativeModule(UIManagerModule.class); diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/GuardedChoreographerFrameCallback.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/GuardedFrameCallback.java similarity index 84% rename from ReactAndroid/src/main/java/com/facebook/react/uimanager/GuardedChoreographerFrameCallback.java rename to ReactAndroid/src/main/java/com/facebook/react/uimanager/GuardedFrameCallback.java index 7abbdae89..60ea1ddc9 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/GuardedChoreographerFrameCallback.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/GuardedFrameCallback.java @@ -9,20 +9,19 @@ package com.facebook.react.uimanager; -import android.view.Choreographer; - import com.facebook.react.bridge.ReactContext; +import com.facebook.react.modules.core.ChoreographerCompat; /** * Abstract base for a Choreographer FrameCallback that should have any RuntimeExceptions it throws * handled by the {@link com.facebook.react.bridge.NativeModuleCallExceptionHandler} registered if * the app is in dev mode. */ -public abstract class GuardedChoreographerFrameCallback implements Choreographer.FrameCallback { +public abstract class GuardedFrameCallback extends ChoreographerCompat.FrameCallback { private final ReactContext mReactContext; - protected GuardedChoreographerFrameCallback(ReactContext reactContext) { + protected GuardedFrameCallback(ReactContext reactContext) { mReactContext = reactContext; } diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java index 92780b042..7098bf057 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java @@ -722,8 +722,7 @@ public class UIViewOperationQueue { final int reactTag, final Callback callback) { mOperations.add( - new MeasureInWindowOperation(reactTag, callback) - ); + new MeasureInWindowOperation(reactTag, callback)); } public void enqueueFindTargetForTouch( @@ -862,7 +861,7 @@ public class UIViewOperationQueue { * Using a Choreographer callback (which runs immediately before traversals), we guarantee we run * before the next traversal. */ - private class DispatchUIFrameCallback extends GuardedChoreographerFrameCallback { + private class DispatchUIFrameCallback extends GuardedFrameCallback { private static final int MIN_TIME_LEFT_IN_FRAME_TO_SCHEDULE_MORE_WORK_MS = 8; private static final int FRAME_TIME_MS = 16; diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/EventDispatcher.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/EventDispatcher.java index 756786f91..d00d14c38 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/EventDispatcher.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/EventDispatcher.java @@ -17,13 +17,13 @@ import java.util.Comparator; import java.util.Map; import android.util.LongSparseArray; -import android.view.Choreographer; import com.facebook.infer.annotation.Assertions; import com.facebook.react.bridge.LifecycleEventListener; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.UiThreadUtil; import com.facebook.react.common.MapBuilder; +import com.facebook.react.modules.core.ChoreographerCompat; import com.facebook.react.modules.core.ReactChoreographer; import com.facebook.systrace.Systrace; @@ -251,7 +251,7 @@ public class EventDispatcher implements LifecycleEventListener { (((long) coalescingKey) & 0xffff) << 48; } - private class ScheduleDispatchFrameCallback implements Choreographer.FrameCallback { + private class ScheduleDispatchFrameCallback extends ChoreographerCompat.FrameCallback { private volatile boolean mIsPosted = false; private boolean mShouldStop = false; diff --git a/ReactAndroid/src/test/java/com/facebook/react/modules/timing/TimingModuleTest.java b/ReactAndroid/src/test/java/com/facebook/react/modules/timing/TimingModuleTest.java index b7686b3f0..649f906b7 100644 --- a/ReactAndroid/src/test/java/com/facebook/react/modules/timing/TimingModuleTest.java +++ b/ReactAndroid/src/test/java/com/facebook/react/modules/timing/TimingModuleTest.java @@ -9,8 +9,6 @@ package com.facebook.react.modules.timing; -import android.view.Choreographer; - import com.facebook.react.bridge.Arguments; import com.facebook.react.bridge.ExecutorToken; import com.facebook.react.bridge.ReactApplicationContext; @@ -18,6 +16,7 @@ import com.facebook.react.bridge.CatalystInstance; import com.facebook.react.bridge.JavaOnlyArray; import com.facebook.react.devsupport.interfaces.DevSupportManager; import com.facebook.react.common.SystemClock; +import com.facebook.react.modules.core.ChoreographerCompat; import com.facebook.react.modules.core.JSTimersExecution; import com.facebook.react.modules.core.ReactChoreographer; import com.facebook.react.modules.core.Timing; @@ -39,8 +38,8 @@ import static org.mockito.Mockito.*; /** * Tests for {@link Timing}. */ - // DISABLED, BROKEN https://circleci.com/gh/facebook/react-native/12068 - // t=13905097 +// DISABLED, BROKEN https://circleci.com/gh/facebook/react-native/12068 +// t=13905097 @PrepareForTest({Arguments.class, SystemClock.class, ReactChoreographer.class}) @PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"}) @RunWith(RobolectricTestRunner.class) @@ -63,12 +62,12 @@ public class TimingModuleTest { public void prepareModules() { PowerMockito.mockStatic(Arguments.class); when(Arguments.createArray()).thenAnswer( - new Answer() { - @Override - public Object answer(InvocationOnMock invocation) throws Throwable { - return new JavaOnlyArray(); - } - }); + new Answer() { + @Override + public Object answer(InvocationOnMock invocation) throws Throwable { + return new JavaOnlyArray(); + } + }); PowerMockito.mockStatic(SystemClock.class); when(SystemClock.uptimeMillis()).thenReturn(mCurrentTimeNs / 1000000); @@ -88,16 +87,16 @@ public class TimingModuleTest { mIdlePostFrameCallbackHandler = new PostFrameIdleCallbackHandler(); doAnswer(mPostFrameCallbackHandler) - .when(mReactChoreographerMock) - .postFrameCallback( - eq(ReactChoreographer.CallbackType.TIMERS_EVENTS), - any(Choreographer.FrameCallback.class)); + .when(mReactChoreographerMock) + .postFrameCallback( + eq(ReactChoreographer.CallbackType.TIMERS_EVENTS), + any(ChoreographerCompat.FrameCallback.class)); doAnswer(mIdlePostFrameCallbackHandler) - .when(mReactChoreographerMock) - .postFrameCallback( - eq(ReactChoreographer.CallbackType.IDLE_EVENT), - any(Choreographer.FrameCallback.class)); + .when(mReactChoreographerMock) + .postFrameCallback( + eq(ReactChoreographer.CallbackType.IDLE_EVENT), + any(ChoreographerCompat.FrameCallback.class)); mTiming = new Timing(reactContext, mock(DevSupportManager.class)); mJSTimersMock = mock(JSTimersExecution.class); @@ -107,7 +106,7 @@ public class TimingModuleTest { doAnswer(new Answer() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { - ((Runnable)invocation.getArguments()[0]).run(); + ((Runnable) invocation.getArguments()[0]).run(); return null; } }).when(reactContext).runOnJSQueueThread(any(Runnable.class)); @@ -116,8 +115,8 @@ public class TimingModuleTest { } private void stepChoreographerFrame() { - Choreographer.FrameCallback callback = mPostFrameCallbackHandler.getAndResetFrameCallback(); - Choreographer.FrameCallback idleCallback = mIdlePostFrameCallbackHandler.getAndResetFrameCallback(); + ChoreographerCompat.FrameCallback callback = mPostFrameCallbackHandler.getAndResetFrameCallback(); + ChoreographerCompat.FrameCallback idleCallback = mIdlePostFrameCallbackHandler.getAndResetFrameCallback(); mCurrentTimeNs += FRAME_TIME_NS; when(SystemClock.uptimeMillis()).thenReturn(mCurrentTimeNs / 1000000); @@ -259,17 +258,17 @@ public class TimingModuleTest { private static class PostFrameIdleCallbackHandler implements Answer { - private Choreographer.FrameCallback mFrameCallback; + private ChoreographerCompat.FrameCallback mFrameCallback; @Override public Void answer(InvocationOnMock invocation) throws Throwable { Object[] args = invocation.getArguments(); - mFrameCallback = (Choreographer.FrameCallback) args[1]; + mFrameCallback = (ChoreographerCompat.FrameCallback) args[1]; return null; } - public Choreographer.FrameCallback getAndResetFrameCallback() { - Choreographer.FrameCallback callback = mFrameCallback; + public ChoreographerCompat.FrameCallback getAndResetFrameCallback() { + ChoreographerCompat.FrameCallback callback = mFrameCallback; mFrameCallback = null; return callback; } @@ -277,17 +276,17 @@ public class TimingModuleTest { private static class PostFrameCallbackHandler implements Answer { - private Choreographer.FrameCallback mFrameCallback; + private ChoreographerCompat.FrameCallback mFrameCallback; @Override public Void answer(InvocationOnMock invocation) throws Throwable { Object[] args = invocation.getArguments(); - mFrameCallback = (Choreographer.FrameCallback) args[1]; + mFrameCallback = (ChoreographerCompat.FrameCallback) args[1]; return null; } - public Choreographer.FrameCallback getAndResetFrameCallback() { - Choreographer.FrameCallback callback = mFrameCallback; + public ChoreographerCompat.FrameCallback getAndResetFrameCallback() { + ChoreographerCompat.FrameCallback callback = mFrameCallback; mFrameCallback = null; return callback; } diff --git a/ReactAndroid/src/test/java/com/facebook/react/uimanager/UIManagerModuleTest.java b/ReactAndroid/src/test/java/com/facebook/react/uimanager/UIManagerModuleTest.java index e11caf3e7..a54f5c2a6 100644 --- a/ReactAndroid/src/test/java/com/facebook/react/uimanager/UIManagerModuleTest.java +++ b/ReactAndroid/src/test/java/com/facebook/react/uimanager/UIManagerModuleTest.java @@ -14,7 +14,6 @@ import java.util.Arrays; import java.util.List; import android.graphics.Color; -import android.view.Choreographer; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; @@ -29,6 +28,8 @@ import com.facebook.react.bridge.JavaOnlyArray; import com.facebook.react.bridge.JavaOnlyMap; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactTestHelper; +import com.facebook.react.modules.core.ChoreographerCompat; +import com.facebook.react.modules.core.ReactChoreographer; import com.facebook.react.views.text.ReactRawTextManager; import com.facebook.react.views.text.ReactTextShadowNode; import com.facebook.react.views.text.ReactTextViewManager; @@ -70,7 +71,7 @@ public class UIManagerModuleTest { private ReactApplicationContext mReactContext; private CatalystInstance mCatalystInstanceMock; - private ArrayList mPendingChoreographerCallbacks; + private ArrayList mPendingFrameCallbacks; @Before public void setUp() { @@ -91,17 +92,17 @@ public class UIManagerModuleTest { }); PowerMockito.when(ReactChoreographer.getInstance()).thenReturn(choreographerMock); - mPendingChoreographerCallbacks = new ArrayList<>(); + mPendingFrameCallbacks = new ArrayList<>(); doAnswer(new Answer() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { - mPendingChoreographerCallbacks - .add((Choreographer.FrameCallback) invocation.getArguments()[1]); + mPendingFrameCallbacks + .add((ChoreographerCompat.FrameCallback) invocation.getArguments()[1]); return null; } }).when(choreographerMock).postFrameCallback( any(ReactChoreographer.CallbackType.class), - any(Choreographer.FrameCallback.class)); + any(ChoreographerCompat.FrameCallback.class)); mCatalystInstanceMock = ReactTestHelper.createMockCatalystInstance(); mReactContext = new ReactApplicationContext(RuntimeEnvironment.application); @@ -139,7 +140,7 @@ public class UIManagerModuleTest { JavaOnlyMap.of(ReactTextShadowNode.PROP_TEXT, "New text")); uiManager.onBatchComplete(); - executePendingChoreographerCallbacks(); + executePendingFrameCallbacks(); assertThat(textView.getText().toString()).isEqualTo("New text"); } @@ -182,7 +183,7 @@ public class UIManagerModuleTest { null); uiManager.onBatchComplete(); - executePendingChoreographerCallbacks(); + executePendingFrameCallbacks(); assertThat(rootView.getChildCount()).isEqualTo(1); @@ -213,7 +214,7 @@ public class UIManagerModuleTest { null); uiManager.onBatchComplete(); - executePendingChoreographerCallbacks(); + executePendingFrameCallbacks(); assertChildrenAreExactly( hierarchy.nativeRootView, @@ -240,7 +241,7 @@ public class UIManagerModuleTest { JavaOnlyArray.of(0, 3)); uiManager.onBatchComplete(); - executePendingChoreographerCallbacks(); + executePendingFrameCallbacks(); assertChildrenAreExactly( hierarchy.nativeRootView, @@ -266,7 +267,7 @@ public class UIManagerModuleTest { JavaOnlyArray.of(1)); uiManager.onBatchComplete(); - executePendingChoreographerCallbacks(); + executePendingFrameCallbacks(); assertChildrenAreExactly( hierarchy.nativeRootView, @@ -289,7 +290,7 @@ public class UIManagerModuleTest { JavaOnlyArray.of(3)); uiManager.onBatchComplete(); - executePendingChoreographerCallbacks(); + executePendingFrameCallbacks(); } @Test(expected = IllegalViewOperationException.class) @@ -306,7 +307,7 @@ public class UIManagerModuleTest { JavaOnlyArray.of(3, 3)); uiManager.onBatchComplete(); - executePendingChoreographerCallbacks(); + executePendingFrameCallbacks(); } @Test @@ -335,7 +336,7 @@ public class UIManagerModuleTest { null); uiManager.onBatchComplete(); - executePendingChoreographerCallbacks(); + executePendingFrameCallbacks(); assertThat(hierarchy.nativeRootView.getChildCount()).isEqualTo(5); assertThat(hierarchy.nativeRootView.getChildAt(0)).isEqualTo(expectedViewAt0); @@ -363,7 +364,7 @@ public class UIManagerModuleTest { null); uiManager.onBatchComplete(); - executePendingChoreographerCallbacks(); + executePendingFrameCallbacks(); assertChildrenAreExactly( hierarchy.nativeRootView, @@ -392,7 +393,7 @@ public class UIManagerModuleTest { JavaOnlyArray.of(1)); uiManager.onBatchComplete(); - executePendingChoreographerCallbacks(); + executePendingFrameCallbacks(); assertChildrenAreExactly( hierarchy.nativeRootView, @@ -424,7 +425,7 @@ public class UIManagerModuleTest { null); uiManager.onBatchComplete(); - executePendingChoreographerCallbacks(); + executePendingFrameCallbacks(); View newView = hierarchy.nativeRootView.getChildAt(4); assertThat(newView.getLeft()).isEqualTo(10); @@ -472,7 +473,7 @@ public class UIManagerModuleTest { JavaOnlyArray.of(4)); uiManager.onBatchComplete(); - executePendingChoreographerCallbacks(); + executePendingFrameCallbacks(); assertThat(hierarchy.nativeRootView.getChildCount()).isEqualTo(4); } @@ -518,7 +519,7 @@ public class UIManagerModuleTest { ReactViewManager.REACT_CLASS, JavaOnlyMap.of("left", 10.0, "top", 20.0, "width", 30.0, "height", 40.0)); uiManager.onBatchComplete(); - executePendingChoreographerCallbacks(); + executePendingFrameCallbacks(); assertThat(view0.getLeft()).isGreaterThan(2); // verify that the layout doesn't get updated when we update style property not affecting the @@ -529,7 +530,7 @@ public class UIManagerModuleTest { ReactViewManager.REACT_CLASS, JavaOnlyMap.of("backgroundColor", Color.RED)); uiManager.onBatchComplete(); - executePendingChoreographerCallbacks(); + executePendingFrameCallbacks(); assertThat(view0.getLeft()).isEqualTo(1); } @@ -565,7 +566,7 @@ public class UIManagerModuleTest { uiManagerModule.removeAnimation(hierarchy.rootView, 1000); uiManagerModule.onBatchComplete(); - executePendingChoreographerCallbacks(); + executePendingFrameCallbacks(); verify(callbackMock, times(1)).invoke(false); verify(mockAnimation).run(); @@ -591,7 +592,7 @@ public class UIManagerModuleTest { uiManager.replaceExistingNonRootView(hierarchy.view2, newViewTag); uiManager.onBatchComplete(); - executePendingChoreographerCallbacks(); + executePendingFrameCallbacks(); assertThat(hierarchy.nativeRootView.getChildCount()).isEqualTo(4); assertThat(hierarchy.nativeRootView.getChildAt(2)).isInstanceOf(ReactViewGroup.class); @@ -640,7 +641,7 @@ public class UIManagerModuleTest { addChild(uiManager, containerTag, containerTag + 3, 1); uiManager.onBatchComplete(); - executePendingChoreographerCallbacks(); + executePendingFrameCallbacks(); assertThat(rootView.getChildCount()).isEqualTo(2); assertThat(((ViewGroup) rootView.getChildAt(0)).getChildCount()).isEqualTo(2); @@ -648,7 +649,7 @@ public class UIManagerModuleTest { uiManager.removeSubviewsFromContainerWithID(containerTag); uiManager.onBatchComplete(); - executePendingChoreographerCallbacks(); + executePendingFrameCallbacks(); assertThat(rootView.getChildCount()).isEqualTo(2); assertThat(((ViewGroup) rootView.getChildAt(0)).getChildCount()).isEqualTo(0); @@ -693,7 +694,7 @@ public class UIManagerModuleTest { null); uiManager.onBatchComplete(); - executePendingChoreographerCallbacks(); + executePendingFrameCallbacks(); return rootView; } @@ -744,7 +745,7 @@ public class UIManagerModuleTest { addChild(uiManager, hierarchy.viewWithChildren1, hierarchy.childView1, 1); uiManager.onBatchComplete(); - executePendingChoreographerCallbacks(); + executePendingFrameCallbacks(); return hierarchy; } @@ -803,11 +804,11 @@ public class UIManagerModuleTest { } } - private void executePendingChoreographerCallbacks() { - ArrayList callbacks = - new ArrayList<>(mPendingChoreographerCallbacks); - mPendingChoreographerCallbacks.clear(); - for (Choreographer.FrameCallback frameCallback : callbacks) { + private void executePendingFrameCallbacks() { + ArrayList callbacks = + new ArrayList<>(mPendingFrameCallbacks); + mPendingFrameCallbacks.clear(); + for (ChoreographerCompat.FrameCallback frameCallback : callbacks) { frameCallback.doFrame(0); } } diff --git a/ReactAndroid/src/test/java/com/facebook/react/views/text/ReactTextTest.java b/ReactAndroid/src/test/java/com/facebook/react/views/text/ReactTextTest.java index ad0721e4e..cf7d860a9 100644 --- a/ReactAndroid/src/test/java/com/facebook/react/views/text/ReactTextTest.java +++ b/ReactAndroid/src/test/java/com/facebook/react/views/text/ReactTextTest.java @@ -23,7 +23,6 @@ import android.text.TextUtils; import android.text.style.AbsoluteSizeSpan; import android.text.style.StrikethroughSpan; import android.text.style.UnderlineSpan; -import android.view.Choreographer; import android.widget.TextView; import com.facebook.react.ReactRootView; @@ -32,7 +31,8 @@ import com.facebook.react.bridge.JavaOnlyArray; import com.facebook.react.bridge.JavaOnlyMap; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactTestHelper; -import com.facebook.react.uimanager.ReactChoreographer; +import com.facebook.react.modules.core.ChoreographerCompat; +import com.facebook.react.modules.core.ReactChoreographer; import com.facebook.react.uimanager.UIImplementationProvider; import com.facebook.react.uimanager.UIManagerModule; import com.facebook.react.uimanager.ViewManager; @@ -68,32 +68,32 @@ public class ReactTextTest { @Rule public PowerMockRule rule = new PowerMockRule(); - private ArrayList mPendingChoreographerCallbacks; + private ArrayList mPendingFrameCallbacks; @Before public void setUp() { PowerMockito.mockStatic(Arguments.class, ReactChoreographer.class); - ReactChoreographer choreographerMock = mock(ReactChoreographer.class); + ReactChoreographer uiDriverMock = mock(ReactChoreographer.class); PowerMockito.when(Arguments.createMap()).thenAnswer(new Answer() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { return new JavaOnlyMap(); } }); - PowerMockito.when(ReactChoreographer.getInstance()).thenReturn(choreographerMock); + PowerMockito.when(ReactChoreographer.getInstance()).thenReturn(uiDriverMock); - mPendingChoreographerCallbacks = new ArrayList<>(); + mPendingFrameCallbacks = new ArrayList<>(); doAnswer(new Answer() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { - mPendingChoreographerCallbacks - .add((Choreographer.FrameCallback) invocation.getArguments()[1]); + mPendingFrameCallbacks + .add((ChoreographerCompat.FrameCallback) invocation.getArguments()[1]); return null; } - }).when(choreographerMock).postFrameCallback( + }).when(uiDriverMock).postFrameCallback( any(ReactChoreographer.CallbackType.class), - any(Choreographer.FrameCallback.class)); + any(ChoreographerCompat.FrameCallback.class)); } @Test @@ -411,15 +411,15 @@ public class ReactTextTest { null); uiManager.onBatchComplete(); - executePendingChoreographerCallbacks(); + executePendingFrameCallbacks(); return rootView; } - private void executePendingChoreographerCallbacks() { - ArrayList callbacks = - new ArrayList<>(mPendingChoreographerCallbacks); - mPendingChoreographerCallbacks.clear(); - for (Choreographer.FrameCallback frameCallback : callbacks) { + private void executePendingFrameCallbacks() { + ArrayList callbacks = + new ArrayList<>(mPendingFrameCallbacks); + mPendingFrameCallbacks.clear(); + for (ChoreographerCompat.FrameCallback frameCallback : callbacks) { frameCallback.doFrame(0); } } diff --git a/ReactAndroid/src/test/java/com/facebook/react/views/textinput/TextInputTest.java b/ReactAndroid/src/test/java/com/facebook/react/views/textinput/TextInputTest.java index 2105d8f90..9b189414e 100644 --- a/ReactAndroid/src/test/java/com/facebook/react/views/textinput/TextInputTest.java +++ b/ReactAndroid/src/test/java/com/facebook/react/views/textinput/TextInputTest.java @@ -13,7 +13,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import android.view.Choreographer; import android.widget.EditText; import com.facebook.react.ReactRootView; @@ -22,8 +21,8 @@ import com.facebook.react.bridge.JavaOnlyArray; import com.facebook.react.bridge.JavaOnlyMap; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactTestHelper; -import com.facebook.react.uimanager.ReactChoreographer; -import com.facebook.react.uimanager.UIImplementation; +import com.facebook.react.modules.core.ChoreographerCompat; +import com.facebook.react.modules.core.ReactChoreographer; import com.facebook.react.uimanager.UIImplementationProvider; import com.facebook.react.uimanager.UIManagerModule; import com.facebook.react.uimanager.ViewManager; @@ -58,7 +57,7 @@ public class TextInputTest { @Rule public PowerMockRule rule = new PowerMockRule(); - private ArrayList mPendingChoreographerCallbacks; + private ArrayList mPendingChoreographerCallbacks; @Before public void setUp() { @@ -78,12 +77,12 @@ public class TextInputTest { @Override public Object answer(InvocationOnMock invocation) throws Throwable { mPendingChoreographerCallbacks - .add((Choreographer.FrameCallback) invocation.getArguments()[1]); + .add((ChoreographerCompat.FrameCallback) invocation.getArguments()[1]); return null; } }).when(choreographerMock).postFrameCallback( any(ReactChoreographer.CallbackType.class), - any(Choreographer.FrameCallback.class)); + any(ChoreographerCompat.FrameCallback.class)); } @Test @@ -169,10 +168,10 @@ public class TextInputTest { } private void executePendingChoreographerCallbacks() { - ArrayList callbacks = + ArrayList callbacks = new ArrayList<>(mPendingChoreographerCallbacks); mPendingChoreographerCallbacks.clear(); - for (Choreographer.FrameCallback frameCallback : callbacks) { + for (ChoreographerCompat.FrameCallback frameCallback : callbacks) { frameCallback.doFrame(0); } }