Fix timestamps on android touch events to use milliseconds, to be consistent with iOS

Summary:
So `PanReponder.onPanResponderRelease/onPanResponderTerminate` receive a `gestureState` object containing a `onPanResponderTerminate.vx/vy` property. On Android and iOS, they appear to be orders of magnitude different, which appear to be due to the different scale of timestamps that are used when generating touch events.

This pull request fixes the timestamps to be milliseconds on both platforms (since I assume iOS is the more authoritative one, and is the one that `react-native-viewpager`'s vx thresholds written written to compare against.)

As far as I can tell, the RN code doesn't use the `vx/vy` properties, so they should be okay. And looks like the RN code only cares about relative values of `startTimestamp/currentTimestamp/previousTimestamp` though, so should be fine too. it's quite possible there will be downstream android breakage with this change, particularly for those who are already compensating for the RN discrepancy.
Closes https://github.com/facebook/react-native/pull/8199

Differential Revision: D3528215

Pulled By: dmmiller

fbshipit-source-id: cbd25bb7e7bb87fa77b661a057643a6ea97bc3f1
This commit is contained in:
Mike Lambert 2016-07-07 05:50:58 -07:00 committed by Facebook Github Bot 2
parent f5345601d9
commit 4f5c2b48fe
20 changed files with 57 additions and 53 deletions

View File

@ -116,7 +116,7 @@ public class TextInputTestCase extends ReactAppInstrumentationTestCase {
eventDispatcher.dispatchEvent(
new ReactTextChangedEvent(
reactEditText.getId(),
SystemClock.nanoTime(),
SystemClock.elapsedRealtime(),
newText.toString(),
(int) PixelUtil.toDIPFromPixel(contentWidth),
(int) PixelUtil.toDIPFromPixel(contentHeight),
@ -125,7 +125,7 @@ public class TextInputTestCase extends ReactAppInstrumentationTestCase {
eventDispatcher.dispatchEvent(
new ReactTextInputEvent(
reactEditText.getId(),
SystemClock.nanoTime(),
SystemClock.elapsedRealtime(),
newText.toString(),
"",
start,
@ -150,7 +150,7 @@ public class TextInputTestCase extends ReactAppInstrumentationTestCase {
eventDispatcher.dispatchEvent(
new ReactTextChangedEvent(
reactEditText.getId(),
SystemClock.nanoTime(),
SystemClock.elapsedRealtime(),
newText.toString(),
(int) PixelUtil.toDIPFromPixel(contentWidth),
(int) PixelUtil.toDIPFromPixel(contentHeight),
@ -159,7 +159,7 @@ public class TextInputTestCase extends ReactAppInstrumentationTestCase {
eventDispatcher.dispatchEvent(
new ReactTextInputEvent(
reactEditText.getId(),
SystemClock.nanoTime(),
SystemClock.elapsedRealtime(),
moreText,
"",
start,
@ -184,7 +184,7 @@ public class TextInputTestCase extends ReactAppInstrumentationTestCase {
eventDispatcher.dispatchEvent(
new ReactTextChangedEvent(
reactEditText.getId(),
SystemClock.nanoTime(),
SystemClock.elapsedRealtime(),
newText.toString(),
(int) PixelUtil.toDIPFromPixel(contentWidth),
(int) PixelUtil.toDIPFromPixel(contentHeight),
@ -193,7 +193,7 @@ public class TextInputTestCase extends ReactAppInstrumentationTestCase {
eventDispatcher.dispatchEvent(
new ReactTextInputEvent(
reactEditText.getId(),
SystemClock.nanoTime(),
SystemClock.elapsedRealtime(),
moreText,
"",
start,

View File

@ -22,4 +22,8 @@ public class SystemClock {
public static long nanoTime() {
return System.nanoTime();
}
public static long elapsedRealtime() {
return android.os.SystemClock.elapsedRealtime();
}
}

View File

@ -244,7 +244,7 @@ public final class Timing extends ReactContextBaseJavaModule implements Lifecycl
return;
}
long initialTargetTime = SystemClock.nanoTime() / 1000000 + adjustedDuration;
long initialTargetTime = SystemClock.elapsedRealtime() + adjustedDuration;
Timer timer = new Timer(executorToken, callbackID, initialTargetTime, duration, repeat);
synchronized (mTimerGuard) {
mTimers.add(timer);

View File

@ -82,7 +82,7 @@ public class JSTouchDispatcher {
eventDispatcher.dispatchEvent(
TouchEvent.obtain(
mTargetTag,
SystemClock.nanoTime(),
SystemClock.elapsedRealtime(),
TouchEventType.START,
ev,
mTargetCoordinates[0],
@ -105,7 +105,7 @@ public class JSTouchDispatcher {
eventDispatcher.dispatchEvent(
TouchEvent.obtain(
mTargetTag,
SystemClock.nanoTime(),
SystemClock.elapsedRealtime(),
TouchEventType.END,
ev,
mTargetCoordinates[0],
@ -117,7 +117,7 @@ public class JSTouchDispatcher {
eventDispatcher.dispatchEvent(
TouchEvent.obtain(
mTargetTag,
SystemClock.nanoTime(),
SystemClock.elapsedRealtime(),
TouchEventType.MOVE,
ev,
mTargetCoordinates[0],
@ -128,7 +128,7 @@ public class JSTouchDispatcher {
eventDispatcher.dispatchEvent(
TouchEvent.obtain(
mTargetTag,
SystemClock.nanoTime(),
SystemClock.elapsedRealtime(),
TouchEventType.START,
ev,
mTargetCoordinates[0],
@ -139,7 +139,7 @@ public class JSTouchDispatcher {
eventDispatcher.dispatchEvent(
TouchEvent.obtain(
mTargetTag,
SystemClock.nanoTime(),
SystemClock.elapsedRealtime(),
TouchEventType.END,
ev,
mTargetCoordinates[0],
@ -180,7 +180,7 @@ public class JSTouchDispatcher {
Assertions.assertNotNull(eventDispatcher).dispatchEvent(
TouchEvent.obtain(
mTargetTag,
SystemClock.nanoTime(),
SystemClock.elapsedRealtime(),
TouchEventType.CANCEL,
androidEvent,
mTargetCoordinates[0],

View File

@ -45,7 +45,7 @@ public class OnLayoutEvent extends Event<OnLayoutEvent> {
}
protected void init(int viewTag, int x, int y, int width, int height) {
super.init(viewTag, SystemClock.nanoTime());
super.init(viewTag, SystemClock.elapsedRealtime());
mX = x;
mY = y;
mWidth = width;

View File

@ -188,25 +188,25 @@ public class ReactDrawerLayoutManager extends ViewGroupManager<ReactDrawerLayout
@Override
public void onDrawerSlide(View view, float v) {
mEventDispatcher.dispatchEvent(
new DrawerSlideEvent(mDrawerLayout.getId(), SystemClock.nanoTime(), v));
new DrawerSlideEvent(mDrawerLayout.getId(), SystemClock.elapsedRealtime(), v));
}
@Override
public void onDrawerOpened(View view) {
mEventDispatcher.dispatchEvent(
new DrawerOpenedEvent(mDrawerLayout.getId(), SystemClock.nanoTime()));
new DrawerOpenedEvent(mDrawerLayout.getId(), SystemClock.elapsedRealtime()));
}
@Override
public void onDrawerClosed(View view) {
mEventDispatcher.dispatchEvent(
new DrawerClosedEvent(mDrawerLayout.getId(), SystemClock.nanoTime()));
new DrawerClosedEvent(mDrawerLayout.getId(), SystemClock.elapsedRealtime()));
}
@Override
public void onDrawerStateChanged(int i) {
mEventDispatcher.dispatchEvent(
new DrawerStateChangedEvent(mDrawerLayout.getId(), SystemClock.nanoTime(), i));
new DrawerStateChangedEvent(mDrawerLayout.getId(), SystemClock.elapsedRealtime(), i));
}
}
}

View File

@ -192,7 +192,7 @@ public class ReactImageView extends GenericDraweeView {
@Override
public void onSubmit(String id, Object callerContext) {
mEventDispatcher.dispatchEvent(
new ImageLoadEvent(getId(), SystemClock.nanoTime(), ImageLoadEvent.ON_LOAD_START));
new ImageLoadEvent(getId(), SystemClock.elapsedRealtime(), ImageLoadEvent.ON_LOAD_START));
}
@Override
@ -202,18 +202,18 @@ public class ReactImageView extends GenericDraweeView {
@Nullable Animatable animatable) {
if (imageInfo != null) {
mEventDispatcher.dispatchEvent(
new ImageLoadEvent(getId(), SystemClock.nanoTime(), ImageLoadEvent.ON_LOAD));
new ImageLoadEvent(getId(), SystemClock.elapsedRealtime(), ImageLoadEvent.ON_LOAD));
mEventDispatcher.dispatchEvent(
new ImageLoadEvent(getId(), SystemClock.nanoTime(), ImageLoadEvent.ON_LOAD_END));
new ImageLoadEvent(getId(), SystemClock.elapsedRealtime(), ImageLoadEvent.ON_LOAD_END));
}
}
@Override
public void onFailure(String id, Throwable throwable) {
mEventDispatcher.dispatchEvent(
new ImageLoadEvent(getId(), SystemClock.nanoTime(), ImageLoadEvent.ON_ERROR));
new ImageLoadEvent(getId(), SystemClock.elapsedRealtime(), ImageLoadEvent.ON_ERROR));
mEventDispatcher.dispatchEvent(
new ImageLoadEvent(getId(), SystemClock.nanoTime(), ImageLoadEvent.ON_LOAD_END));
new ImageLoadEvent(getId(), SystemClock.elapsedRealtime(), ImageLoadEvent.ON_LOAD_END));
}
};
}

View File

@ -85,14 +85,14 @@ public class ReactModalHostManager extends ViewGroupManager<ReactModalHostView>
new ReactModalHostView.OnRequestCloseListener() {
@Override
public void onRequestClose(DialogInterface dialog) {
dispatcher.dispatchEvent(new RequestCloseEvent(view.getId(), SystemClock.nanoTime()));
dispatcher.dispatchEvent(new RequestCloseEvent(view.getId(), SystemClock.elapsedRealtime()));
}
});
view.setOnShowListener(
new DialogInterface.OnShowListener() {
@Override
public void onShow(DialogInterface dialog) {
dispatcher.dispatchEvent(new ShowEvent(view.getId(), SystemClock.nanoTime()));
dispatcher.dispatchEvent(new ShowEvent(view.getId(), SystemClock.elapsedRealtime()));
}
});
}

View File

@ -157,7 +157,7 @@ public abstract class ReactPickerManager extends SimpleViewManager<ReactPicker>
@Override
public void onItemSelected(int position) {
mEventDispatcher.dispatchEvent( new PickerItemSelectEvent(
mReactPicker.getId(), SystemClock.nanoTime(), position));
mReactPicker.getId(), SystemClock.elapsedRealtime(), position));
}
}
}

View File

@ -344,7 +344,7 @@ public class RecyclerViewBackedScrollView extends RecyclerView {
((ReactContext) getContext()).getNativeModule(UIManagerModule.class).getEventDispatcher()
.dispatchEvent(ScrollEvent.obtain(
getId(),
SystemClock.nanoTime(),
SystemClock.elapsedRealtime(),
ScrollEventType.SCROLL,
0, /* offsetX = 0, horizontal scrolling only */
calculateAbsoluteOffset(),
@ -359,7 +359,7 @@ public class RecyclerViewBackedScrollView extends RecyclerView {
((ReactContext) getContext()).getNativeModule(UIManagerModule.class).getEventDispatcher()
.dispatchEvent(new ContentSizeChangeEvent(
getId(),
SystemClock.nanoTime(),
SystemClock.elapsedRealtime(),
getWidth(),
newTotalChildrenHeight));
}

View File

@ -57,7 +57,7 @@ public class ReactScrollViewHelper {
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(
ScrollEvent.obtain(
scrollView.getId(),
SystemClock.nanoTime(),
SystemClock.elapsedRealtime(),
scrollEventType,
scrollView.getScrollX(),
scrollView.getScrollY(),

View File

@ -81,7 +81,7 @@ public class ReactSliderManager extends SimpleViewManager<ReactSlider> {
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(
new ReactSliderEvent(
seekbar.getId(),
SystemClock.nanoTime(),
SystemClock.elapsedRealtime(),
((ReactSlider)seekbar).toRealProgress(progress),
fromUser));
}
@ -96,7 +96,7 @@ public class ReactSliderManager extends SimpleViewManager<ReactSlider> {
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(
new ReactSlidingCompleteEvent(
seekbar.getId(),
SystemClock.nanoTime(),
SystemClock.elapsedRealtime(),
((ReactSlider)seekbar).toRealProgress(seekbar.getProgress())));
}
};

View File

@ -89,7 +89,7 @@ public class SwipeRefreshLayoutManager extends ViewGroupManager<ReactSwipeRefres
@Override
public void onRefresh() {
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher()
.dispatchEvent(new RefreshEvent(view.getId(), SystemClock.nanoTime()));
.dispatchEvent(new RefreshEvent(view.getId(), SystemClock.elapsedRealtime()));
}
});
}

View File

@ -78,7 +78,7 @@ public class ReactSwitchManager extends SimpleViewManager<ReactSwitch> {
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(
new ReactSwitchEvent(
buttonView.getId(),
SystemClock.nanoTime(),
SystemClock.elapsedRealtime(),
isChecked));
}
};

View File

@ -567,7 +567,7 @@ public class ReactTextInputManager extends BaseViewManager<ReactEditText, Layout
mEventDispatcher.dispatchEvent(
new ReactTextChangedEvent(
mEditText.getId(),
SystemClock.nanoTime(),
SystemClock.elapsedRealtime(),
s.toString(),
(int) PixelUtil.toDIPFromPixel(contentWidth),
(int) PixelUtil.toDIPFromPixel(contentHeight),
@ -576,7 +576,7 @@ public class ReactTextInputManager extends BaseViewManager<ReactEditText, Layout
mEventDispatcher.dispatchEvent(
new ReactTextInputEvent(
mEditText.getId(),
SystemClock.nanoTime(),
SystemClock.elapsedRealtime(),
newText,
oldText,
start,
@ -602,17 +602,17 @@ public class ReactTextInputManager extends BaseViewManager<ReactEditText, Layout
eventDispatcher.dispatchEvent(
new ReactTextInputFocusEvent(
editText.getId(),
SystemClock.nanoTime()));
SystemClock.elapsedRealtime()));
} else {
eventDispatcher.dispatchEvent(
new ReactTextInputBlurEvent(
editText.getId(),
SystemClock.nanoTime()));
SystemClock.elapsedRealtime()));
eventDispatcher.dispatchEvent(
new ReactTextInputEndEditingEvent(
editText.getId(),
SystemClock.nanoTime(),
SystemClock.elapsedRealtime(),
editText.getText().toString()));
}
}
@ -630,7 +630,7 @@ public class ReactTextInputManager extends BaseViewManager<ReactEditText, Layout
eventDispatcher.dispatchEvent(
new ReactTextInputSubmitEditingEvent(
editText.getId(),
SystemClock.nanoTime(),
SystemClock.elapsedRealtime(),
editText.getText().toString()));
}
if (actionId == EditorInfo.IME_ACTION_NEXT ||
@ -667,7 +667,7 @@ public class ReactTextInputManager extends BaseViewManager<ReactEditText, Layout
mEventDispatcher.dispatchEvent(
new ReactTextInputSelectionEvent(
mReactEditText.getId(),
SystemClock.nanoTime(),
SystemClock.elapsedRealtime(),
start,
end
)

View File

@ -131,7 +131,7 @@ public class ReactToolbarManager extends ViewGroupManager<ReactToolbar> {
@Override
public void onClick(View v) {
mEventDispatcher.dispatchEvent(
new ToolbarClickEvent(view.getId(), SystemClock.nanoTime(), -1));
new ToolbarClickEvent(view.getId(), SystemClock.elapsedRealtime(), -1));
}
});
@ -142,7 +142,7 @@ public class ReactToolbarManager extends ViewGroupManager<ReactToolbar> {
mEventDispatcher.dispatchEvent(
new ToolbarClickEvent(
view.getId(),
SystemClock.nanoTime(),
SystemClock.elapsedRealtime(),
menuItem.getOrder()));
return true;
}

View File

@ -91,14 +91,14 @@ import com.facebook.react.uimanager.events.NativeGestureUtil;
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
mEventDispatcher.dispatchEvent(
new PageScrollEvent(getId(), SystemClock.nanoTime(), position, positionOffset));
new PageScrollEvent(getId(), SystemClock.elapsedRealtime(), position, positionOffset));
}
@Override
public void onPageSelected(int position) {
if (!mIsCurrentItemFromJs) {
mEventDispatcher.dispatchEvent(
new PageSelectedEvent(getId(), SystemClock.nanoTime(), position));
new PageSelectedEvent(getId(), SystemClock.elapsedRealtime(), position));
}
}
@ -119,7 +119,7 @@ import com.facebook.react.uimanager.events.NativeGestureUtil;
throw new IllegalStateException("Unsupported pageScrollState");
}
mEventDispatcher.dispatchEvent(
new PageScrollStateChangedEvent(getId(), SystemClock.nanoTime(), pageScrollState));
new PageScrollStateChangedEvent(getId(), SystemClock.elapsedRealtime(), pageScrollState));
}
}

View File

@ -107,7 +107,7 @@ public class ReactWebViewManager extends SimpleViewManager<WebView> {
webView,
new TopLoadingStartEvent(
webView.getId(),
SystemClock.nanoTime(),
SystemClock.elapsedRealtime(),
createWebViewEvent(webView, url)));
}
@ -130,7 +130,7 @@ public class ReactWebViewManager extends SimpleViewManager<WebView> {
dispatchEvent(
webView,
new TopLoadingErrorEvent(webView.getId(), SystemClock.nanoTime(), eventData));
new TopLoadingErrorEvent(webView.getId(), SystemClock.elapsedRealtime(), eventData));
}
@Override
@ -141,7 +141,7 @@ public class ReactWebViewManager extends SimpleViewManager<WebView> {
webView,
new TopLoadingStartEvent(
webView.getId(),
SystemClock.nanoTime(),
SystemClock.elapsedRealtime(),
createWebViewEvent(webView, url)));
}
@ -150,7 +150,7 @@ public class ReactWebViewManager extends SimpleViewManager<WebView> {
webView,
new TopLoadingFinishEvent(
webView.getId(),
SystemClock.nanoTime(),
SystemClock.elapsedRealtime(),
createWebViewEvent(webView, url)));
}

View File

@ -65,7 +65,7 @@ public class RootViewTest {
@Before
public void setUp() {
final long ts = SystemClock.nanoTime();
final long ts = SystemClock.elapsedRealtime();
PowerMockito.mockStatic(Arguments.class);
PowerMockito.when(Arguments.createArray()).thenAnswer(new Answer<Object>() {
@Override
@ -80,7 +80,7 @@ public class RootViewTest {
}
});
PowerMockito.mockStatic(SystemClock.class);
PowerMockito.when(SystemClock.nanoTime()).thenAnswer(new Answer<Object>() {
PowerMockito.when(SystemClock.elapsedRealtime()).thenAnswer(new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
return ts;
@ -116,7 +116,7 @@ public class RootViewTest {
rootView.startReactApplication(instanceManager, "");
rootView.simulateAttachForTesting();
long ts = SystemClock.nanoTime();
long ts = SystemClock.elapsedRealtime();
// Test ACTION_DOWN event
rootView.onTouchEvent(

View File

@ -74,7 +74,7 @@ public class TimingModuleTest {
PowerMockito.mockStatic(SystemClock.class);
when(SystemClock.currentTimeMillis()).thenReturn(mCurrentTimeNs / 1000000);
when(SystemClock.nanoTime()).thenReturn(mCurrentTimeNs);
when(SystemClock.elapsedRealtime()).thenReturn(mCurrentTimeNs / 1000000);
mChoreographerMock = mock(ReactChoreographer.class);
PowerMockito.mockStatic(ReactChoreographer.class);