/**
* Copyright (c) 2015-present, 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.
*/
package com.facebook.react.uimanager.events;
import android.util.SparseIntArray;
/**
* Utility for determining coalescing keys for TouchEvents. To preserve proper ordering of events,
* move events should only be coalesced if there has been no up/down event between them (this
* basically only applies to multitouch since for single touches an up would signal the end of the
* gesture). To illustrate to kind of coalescing we want, imagine we are coalescing the following
* touch stream:
*
* (U = finger up, D = finger down, M = move)
* D MMMMM D MMMMMMMMMMMMMM U MMMMM D MMMMMM U U
*
* We want to make sure to coalesce this as
*
* D M D M U M D U U
*
* and *not*
*
* D D U M D U U
*
* To accomplish this, this class provides a way to initialize a coalescing key for a gesture and
* then increment it for every pointer up/down that occurs during that single gesture.
*
* We identify a single gesture based on {@link android.view.MotionEvent#getDownTime()} which will
* stay constant for a given set of related touches on a single view.
*
* NB: even though down time is a long, we cast as an int using the least significant bits as the
* identifier. In practice, we will not be coalescing over a time range where the most significant
* bits of that time range matter. This would require a gesture that lasts Integer.MAX_VALUE * 2 ms,
* or ~48 days.
*
* NB: we assume two gestures cannot begin at the same time.
*
* NB: this class should only be used from the UI thread.
*/
public class TouchEventCoalescingKeyHelper {
private static final SparseIntArray sDownTimeToCoalescingKey = new SparseIntArray();
/**
* Starts tracking a new coalescing key corresponding to the gesture with this down time.
*/
public static void addCoalescingKey(long downTime) {
sDownTimeToCoalescingKey.put((int) downTime, 0);
}
/**
* Increments the coalescing key corresponding to the gesture with this down time.
*/
public static void incrementCoalescingKey(long downTime) {
int currentValue = sDownTimeToCoalescingKey.get((int) downTime, -1);
if (currentValue == -1) {
throw new RuntimeException("Tried to increment non-existent cookie");
}
sDownTimeToCoalescingKey.put((int) downTime, currentValue + 1);
}
/**
* Gets the coalescing key corresponding to the gesture with this down time.
*/
public static short getCoalescingKey(long downTime) {
int currentValue = sDownTimeToCoalescingKey.get((int) downTime, -1);
if (currentValue == -1) {
throw new RuntimeException("Tried to get non-existent cookie");
}
return ((short) (0xffff & currentValue));
}
/**
* Stops tracking a new coalescing key corresponding to the gesture with this down time.
*/
public static void removeCoalescingKey(long downTime) {
sDownTimeToCoalescingKey.delete((int) downTime);
}
}