All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.robolectric.shadows.ShadowMotionEvent Maven / Gradle / Ivy

The newest version!
package org.robolectric.shadows;

import static android.os.Build.VERSION_CODES.M;
import static android.os.Build.VERSION_CODES.P;
import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static org.robolectric.shadows.NativeAndroidInput.AMOTION_EVENT_AXIS_ORIENTATION;
import static org.robolectric.shadows.NativeAndroidInput.AMOTION_EVENT_AXIS_PRESSURE;
import static org.robolectric.shadows.NativeAndroidInput.AMOTION_EVENT_AXIS_SIZE;
import static org.robolectric.shadows.NativeAndroidInput.AMOTION_EVENT_AXIS_TOOL_MAJOR;
import static org.robolectric.shadows.NativeAndroidInput.AMOTION_EVENT_AXIS_TOOL_MINOR;
import static org.robolectric.shadows.NativeAndroidInput.AMOTION_EVENT_AXIS_TOUCH_MAJOR;
import static org.robolectric.shadows.NativeAndroidInput.AMOTION_EVENT_AXIS_TOUCH_MINOR;
import static org.robolectric.shadows.NativeAndroidInput.AMOTION_EVENT_AXIS_X;
import static org.robolectric.shadows.NativeAndroidInput.AMOTION_EVENT_AXIS_Y;

import android.graphics.Matrix;
import android.os.Parcel;
import android.view.MotionEvent;
import android.view.MotionEvent.PointerCoords;
import android.view.MotionEvent.PointerProperties;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.List;
import org.robolectric.annotation.HiddenApi;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.annotation.InDevelopment;
import org.robolectric.annotation.RealObject;
import org.robolectric.annotation.Resetter;
import org.robolectric.res.android.NativeObjRegistry;
import org.robolectric.util.ReflectionHelpers;
import org.robolectric.versioning.AndroidVersions.V;

/**
 * Shadow of MotionEvent.
 *
 * 

The Android framework stores motion events in a pool of native objects. All motion event data * is stored natively, and accessed via a series of static native methods following the pattern * nativeGetXXXX(mNativePtr, ...) * *

This shadow mirrors this design, but has java equivalents of each native object. Most of the * contents of this class were transliterated from oreo-mr1 (SDK 27) * frameworks/base/core/jni/android_view_MotionEvent.cpp * * @see core/jni/android_view_MotionEvent.cpp *

Tests should not reference this class directly. MotionEvents should be created via one of * the MotionEvent.obtain methods or via MotionEventBuilder. */ @SuppressWarnings({"UnusedDeclaration"}) @Implements(value = MotionEvent.class) public class ShadowMotionEvent extends ShadowInputEvent { private static NativeObjRegistry nativeMotionEventRegistry = new NativeObjRegistry<>(NativeInput.MotionEvent.class); private static final int HISTORY_CURRENT = -0x80000000; @RealObject private MotionEvent realMotionEvent; @Resetter public static void reset() { // rely on MotionEvent finalizer to clear native object instead of calling // nativeMotionEventRegistry.clear(); ReflectionHelpers.setStaticField(MotionEvent.class, "gRecyclerTop", null); ReflectionHelpers.setStaticField(MotionEvent.class, "gSharedTempPointerCoords", null); ReflectionHelpers.setStaticField(MotionEvent.class, "gSharedTempPointerProperties", null); ReflectionHelpers.setStaticField(MotionEvent.class, "gRecyclerUsed", 0); ReflectionHelpers.setStaticField(MotionEvent.class, "gSharedTempPointerIndexMap", null); } private static void validatePointerCount(int pointerCount) { checkState(pointerCount >= 1, "pointerCount must be at least 1"); } private static void validatePointerPropertiesArray( PointerProperties[] pointerPropertiesObjArray, int pointerCount) { checkNotNull(pointerPropertiesObjArray, "pointerProperties array must not be null"); checkState( pointerPropertiesObjArray.length >= pointerCount, "pointerProperties array must be large enough to hold all pointers"); } private static void validatePointerCoordsObjArray( PointerCoords[] pointerCoordsObjArray, int pointerCount) { checkNotNull(pointerCoordsObjArray, "pointerCoords array must not be null"); checkState( pointerCoordsObjArray.length >= pointerCount, "pointerCoords array must be large enough to hold all pointers"); } private static void validatePointerIndex(int pointerIndex, int pointerCount) { checkState(pointerIndex >= 0 && pointerIndex < pointerCount, "pointerIndex out of range"); } private static void validateHistoryPos(int historyPos, int historySize) { checkState(historyPos >= 0 && historyPos < historySize, "historyPos out of range"); } private static void validatePointerCoords(PointerCoords pointerCoordsObj) { checkNotNull(pointerCoordsObj, "pointerCoords must not be null"); } private static void validatePointerProperties(PointerProperties pointerPropertiesObj) { checkNotNull(pointerPropertiesObj, "pointerProperties must not be null"); } private static NativeInput.PointerCoords pointerCoordsToNative( PointerCoords pointerCoordsObj, float xOffset, float yOffset) { NativeInput.PointerCoords outRawPointerCoords = new NativeInput.PointerCoords(); outRawPointerCoords.clear(); outRawPointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, pointerCoordsObj.x - xOffset); outRawPointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, pointerCoordsObj.y - yOffset); outRawPointerCoords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pointerCoordsObj.pressure); outRawPointerCoords.setAxisValue(AMOTION_EVENT_AXIS_SIZE, pointerCoordsObj.size); outRawPointerCoords.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, pointerCoordsObj.touchMajor); outRawPointerCoords.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, pointerCoordsObj.touchMinor); outRawPointerCoords.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, pointerCoordsObj.toolMajor); outRawPointerCoords.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, pointerCoordsObj.toolMinor); outRawPointerCoords.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, pointerCoordsObj.orientation); long packedAxisBits = ReflectionHelpers.getField(pointerCoordsObj, "mPackedAxisBits"); NativeBitSet64 bits = new NativeBitSet64(packedAxisBits); if (!bits.isEmpty()) { float[] valuesArray = ReflectionHelpers.getField(pointerCoordsObj, "mPackedAxisValues"); if (valuesArray != null) { int index = 0; do { int axis = bits.clearFirstMarkedBit(); outRawPointerCoords.setAxisValue(axis, valuesArray[index++]); } while (!bits.isEmpty()); } } return outRawPointerCoords; } private static float[] obtainPackedAxisValuesArray( int minSize, PointerCoords outPointerCoordsObj) { float[] outValuesArray = ReflectionHelpers.getField(outPointerCoordsObj, "mPackedAxisValues"); if (outValuesArray != null) { int size = outValuesArray.length; if (minSize <= size) { return outValuesArray; } } int size = 8; while (size < minSize) { size *= 2; } outValuesArray = new float[size]; ReflectionHelpers.setField(outPointerCoordsObj, "mPackedAxisValues", outValuesArray); return outValuesArray; } private static void pointerCoordsFromNative( NativeInput.PointerCoords rawPointerCoords, float xOffset, float yOffset, PointerCoords outPointerCoordsObj) { outPointerCoordsObj.x = rawPointerCoords.getAxisValue(AMOTION_EVENT_AXIS_X) + xOffset; outPointerCoordsObj.y = rawPointerCoords.getAxisValue(AMOTION_EVENT_AXIS_Y) + yOffset; outPointerCoordsObj.pressure = rawPointerCoords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE); outPointerCoordsObj.size = rawPointerCoords.getAxisValue(AMOTION_EVENT_AXIS_SIZE); outPointerCoordsObj.touchMajor = rawPointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR); outPointerCoordsObj.touchMinor = rawPointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR); outPointerCoordsObj.toolMajor = rawPointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR); outPointerCoordsObj.toolMinor = rawPointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR); outPointerCoordsObj.orientation = rawPointerCoords.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION); long outBits = 0; NativeBitSet64 bits = new NativeBitSet64(rawPointerCoords.getBits()); bits.clearBit(AMOTION_EVENT_AXIS_X); bits.clearBit(AMOTION_EVENT_AXIS_Y); bits.clearBit(AMOTION_EVENT_AXIS_PRESSURE); bits.clearBit(AMOTION_EVENT_AXIS_SIZE); bits.clearBit(AMOTION_EVENT_AXIS_TOUCH_MAJOR); bits.clearBit(AMOTION_EVENT_AXIS_TOUCH_MINOR); bits.clearBit(AMOTION_EVENT_AXIS_TOOL_MAJOR); bits.clearBit(AMOTION_EVENT_AXIS_TOOL_MINOR); bits.clearBit(AMOTION_EVENT_AXIS_ORIENTATION); if (!bits.isEmpty()) { int packedAxesCount = bits.count(); float[] outValuesArray = obtainPackedAxisValuesArray(packedAxesCount, outPointerCoordsObj); float[] outValues = outValuesArray; int index = 0; do { int axis = bits.clearFirstMarkedBit(); outBits |= NativeBitSet64.valueForBit(axis); outValues[index++] = rawPointerCoords.getAxisValue(axis); } while (!bits.isEmpty()); } ReflectionHelpers.setField(outPointerCoordsObj, "mPackedAxisBits", outBits); } @Implementation(maxSdk = P) @HiddenApi protected static long nativeInitialize( long nativePtr, int deviceId, int source, int action, int flags, int edgeFlags, int metaState, int buttonState, float xOffset, float yOffset, float xPrecision, float yPrecision, long downTimeNanos, long eventTimeNanos, int pointerCount, PointerProperties[] pointerPropertiesObjArray, PointerCoords[] pointerCoordsObjArray) { validatePointerCount(pointerCount); validatePointerPropertiesArray(pointerPropertiesObjArray, pointerCount); validatePointerCoordsObjArray(pointerCoordsObjArray, pointerCount); NativeInput.MotionEvent event; if (nativePtr > 0) { event = nativeMotionEventRegistry.getNativeObject(nativePtr); } else { event = new NativeInput.MotionEvent(); nativePtr = nativeMotionEventRegistry.register(event); } NativeInput.PointerCoords[] rawPointerCoords = new NativeInput.PointerCoords[pointerCount]; for (int i = 0; i < pointerCount; i++) { PointerCoords pointerCoordsObj = pointerCoordsObjArray[i]; checkNotNull(pointerCoordsObj); rawPointerCoords[i] = pointerCoordsToNative(pointerCoordsObj, xOffset, yOffset); } event.initialize( deviceId, source, action, 0, flags, edgeFlags, metaState, buttonState, xOffset, yOffset, xPrecision, yPrecision, downTimeNanos, eventTimeNanos, pointerCount, pointerPropertiesObjArray, rawPointerCoords); return nativePtr; } // TODO(brettchabot): properly handle displayId @Implementation(minSdk = android.os.Build.VERSION_CODES.Q) @HiddenApi protected static long nativeInitialize( long nativePtr, int deviceId, int source, int displayId, int action, int flags, int edgeFlags, int metaState, int buttonState, int classification, float xOffset, float yOffset, float xPrecision, float yPrecision, long downTimeNanos, long eventTimeNanos, int pointerCount, PointerProperties[] pointerIds, PointerCoords[] pointerCoords) { return nativeInitialize( nativePtr, deviceId, source, action, flags, edgeFlags, metaState, buttonState, xOffset, yOffset, xPrecision, yPrecision, downTimeNanos, eventTimeNanos, pointerCount, pointerIds, pointerCoords); } @Implementation @HiddenApi protected static void nativeDispose(long nativePtr) { nativeMotionEventRegistry.unregister(nativePtr); } @Implementation @HiddenApi protected static void nativeAddBatch( long nativePtr, long eventTimeNanos, PointerCoords[] pointerCoordsObjArray, int metaState) { NativeInput.MotionEvent event = getNativeMotionEvent(nativePtr); int pointerCount = event.getPointerCount(); validatePointerCoordsObjArray(pointerCoordsObjArray, pointerCount); NativeInput.PointerCoords[] rawPointerCoords = new NativeInput.PointerCoords[pointerCount]; for (int i = 0; i < pointerCount; i++) { PointerCoords pointerCoordsObj = pointerCoordsObjArray[i]; checkNotNull(pointerCoordsObj); rawPointerCoords[i] = pointerCoordsToNative(pointerCoordsObj, event.getXOffset(), event.getYOffset()); } event.addSample(eventTimeNanos, rawPointerCoords); event.setMetaState(event.getMetaState() | metaState); } @Implementation @HiddenApi protected static void nativeGetPointerCoords( long nativePtr, int pointerIndex, int historyPos, PointerCoords outPointerCoordsObj) { NativeInput.MotionEvent event = getNativeMotionEvent(nativePtr); int pointerCount = event.getPointerCount(); validatePointerIndex(pointerIndex, pointerCount); validatePointerCoords(outPointerCoordsObj); NativeInput.PointerCoords rawPointerCoords; if (historyPos == HISTORY_CURRENT) { rawPointerCoords = event.getRawPointerCoords(pointerIndex); } else { int historySize = event.getHistorySize(); validateHistoryPos(historyPos, historySize); rawPointerCoords = event.getHistoricalRawPointerCoords(pointerIndex, historyPos); } pointerCoordsFromNative( rawPointerCoords, event.getXOffset(), event.getYOffset(), outPointerCoordsObj); } @Implementation @HiddenApi protected static void nativeGetPointerProperties( long nativePtr, int pointerIndex, PointerProperties outPointerPropertiesObj) { NativeInput.MotionEvent event = getNativeMotionEvent(nativePtr); int pointerCount = event.getPointerCount(); validatePointerIndex(pointerIndex, pointerCount); validatePointerProperties(outPointerPropertiesObj); PointerProperties pointerProperties = event.getPointerProperties(pointerIndex); // pointerPropertiesFromNative(env, pointerProperties, outPointerPropertiesObj); outPointerPropertiesObj.copyFrom(pointerProperties); } @Implementation @HiddenApi protected static long nativeReadFromParcel(long nativePtr, Parcel parcelObj) { NativeInput.MotionEvent event; if (nativePtr == 0) { event = new NativeInput.MotionEvent(); nativePtr = nativeMotionEventRegistry.register(event); } else { event = nativeMotionEventRegistry.getNativeObject(nativePtr); } boolean status = event.readFromParcel(parcelObj); if (!status) { if (nativePtr > 0) { nativeMotionEventRegistry.unregister(nativePtr); } throw new RuntimeException("Failed to read MotionEvent parcel."); } return nativePtr; } @Implementation @HiddenApi protected static void nativeWriteToParcel(long nativePtr, Parcel parcel) { NativeInput.MotionEvent event = getNativeMotionEvent(nativePtr); if (!event.writeToParcel(parcel)) { throw new RuntimeException("Failed to write MotionEvent parcel."); } } @Implementation @HiddenApi protected static String nativeAxisToString(int axis) { // The native code just mirrors the AXIS_* constants defined in MotionEvent.java. // Look up the field value by reflection to future proof this method for (Field field : MotionEvent.class.getDeclaredFields()) { int modifiers = field.getModifiers(); try { if (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers) && field.getName().startsWith("AXIS_") && field.getInt(null) == axis) { // return the field name stripping off the "AXIS_" prefix return field.getName().substring(5); } } catch (IllegalAccessException e) { // ignore } } return null; } @Implementation @HiddenApi protected static int nativeAxisFromString(String label) { // The native code just mirrors the AXIS_* constants defined in MotionEvent.java. Look up // the field value by reflection try { Field constantField = MotionEvent.class.getDeclaredField("AXIS_" + label); return constantField.getInt(null); } catch (NoSuchFieldException | IllegalAccessException e) { return 0; } } @Implementation @HiddenApi protected static int nativeGetPointerId(long nativePtr, int pointerIndex) { NativeInput.MotionEvent event = getNativeMotionEvent(nativePtr); int pointerCount = event.getPointerCount(); validatePointerIndex(pointerIndex, pointerCount); return event.getPointerId(pointerIndex); } @Implementation @HiddenApi protected static int nativeGetToolType(long nativePtr, int pointerIndex) { NativeInput.MotionEvent event = getNativeMotionEvent(nativePtr); int pointerCount = event.getPointerCount(); validatePointerIndex(pointerIndex, pointerCount); return event.getToolType(pointerIndex); } @Implementation @HiddenApi protected static long nativeGetEventTimeNanos(long nativePtr, int historyPos) { NativeInput.MotionEvent event = getNativeMotionEvent(nativePtr); if (historyPos == HISTORY_CURRENT) { return event.getEventTime(); } else { int historySize = event.getHistorySize(); validateHistoryPos(historyPos, historySize); return event.getHistoricalEventTime(historyPos); } } @Implementation @HiddenApi protected static float nativeGetRawAxisValue( long nativePtr, int axis, int pointerIndex, int historyPos) { NativeInput.MotionEvent event = getNativeMotionEvent(nativePtr); int pointerCount = event.getPointerCount(); validatePointerIndex(pointerIndex, pointerCount); if (historyPos == HISTORY_CURRENT) { return event.getRawAxisValue(axis, pointerIndex); } else { int historySize = event.getHistorySize(); validateHistoryPos(historyPos, historySize); return event.getHistoricalRawAxisValue(axis, pointerIndex, historyPos); } } @Implementation @HiddenApi protected static float nativeGetAxisValue( long nativePtr, int axis, int pointerIndex, int historyPos) { NativeInput.MotionEvent event = getNativeMotionEvent(nativePtr); int pointerCount = event.getPointerCount(); validatePointerIndex(pointerIndex, pointerCount); if (historyPos == HISTORY_CURRENT) { return event.getAxisValue(axis, pointerIndex); } else { int historySize = event.getHistorySize(); validateHistoryPos(historyPos, historySize); return event.getHistoricalAxisValue(axis, pointerIndex, historyPos); } } @Implementation @HiddenApi protected static long nativeCopy(long destNativePtr, long sourceNativePtr, boolean keepHistory) { NativeInput.MotionEvent destEvent = nativeMotionEventRegistry.peekNativeObject(destNativePtr); if (destEvent == null) { destEvent = new NativeInput.MotionEvent(); destNativePtr = nativeMotionEventRegistry.register(destEvent); } NativeInput.MotionEvent sourceEvent = getNativeMotionEvent(sourceNativePtr); destEvent.copyFrom(sourceEvent, keepHistory); return destNativePtr; } @Implementation @HiddenApi protected static int nativeGetDeviceId(long nativePtr) { NativeInput.MotionEvent event = getNativeMotionEvent(nativePtr); return event.getDeviceId(); } @Implementation @HiddenApi protected static int nativeGetSource(long nativePtr) { NativeInput.MotionEvent event = getNativeMotionEvent(nativePtr); return event.getSource(); } @Implementation @HiddenApi @SuppressWarnings("robolectric.ShadowReturnTypeMismatch") protected static void nativeSetSource(long nativePtr, int source) { NativeInput.MotionEvent event = getNativeMotionEvent(nativePtr); event.setSource(source); } @Implementation @HiddenApi protected static int nativeGetAction(long nativePtr) { NativeInput.MotionEvent event = getNativeMotionEvent(nativePtr); return event.getAction(); } @Implementation @HiddenApi protected static void nativeSetAction(long nativePtr, int action) { NativeInput.MotionEvent event = getNativeMotionEvent(nativePtr); event.setAction(action); } @Implementation(minSdk = M) @HiddenApi protected static int nativeGetActionButton(long nativePtr) { NativeInput.MotionEvent event = getNativeMotionEvent(nativePtr); return event.getActionButton(); } @Implementation(minSdk = M) @HiddenApi protected static void nativeSetActionButton(long nativePtr, int button) { NativeInput.MotionEvent event = getNativeMotionEvent(nativePtr); event.setActionButton(button); } @Implementation @HiddenApi protected static boolean nativeIsTouchEvent(long nativePtr) { NativeInput.MotionEvent event = getNativeMotionEvent(nativePtr); return event.isTouchEvent(); } @Implementation @HiddenApi protected static int nativeGetFlags(long nativePtr) { NativeInput.MotionEvent event = getNativeMotionEvent(nativePtr); return event.getFlags(); } @Implementation @HiddenApi protected static void nativeSetFlags(long nativePtr, int flags) { NativeInput.MotionEvent event = getNativeMotionEvent(nativePtr); event.setFlags(flags); } @Implementation @HiddenApi protected static int nativeGetEdgeFlags(long nativePtr) { NativeInput.MotionEvent event = getNativeMotionEvent(nativePtr); return event.getEdgeFlags(); } @Implementation @HiddenApi protected static void nativeSetEdgeFlags(long nativePtr, int edgeFlags) { NativeInput.MotionEvent event = getNativeMotionEvent(nativePtr); event.setEdgeFlags(edgeFlags); } @Implementation @HiddenApi protected static int nativeGetMetaState(long nativePtr) { NativeInput.MotionEvent event = getNativeMotionEvent(nativePtr); return event.getMetaState(); } @Implementation @HiddenApi protected static int nativeGetButtonState(long nativePtr) { NativeInput.MotionEvent event = getNativeMotionEvent(nativePtr); return event.getButtonState(); } @Implementation(minSdk = M) @HiddenApi protected static void nativeSetButtonState(long nativePtr, int buttonState) { NativeInput.MotionEvent event = getNativeMotionEvent(nativePtr); event.setButtonState(buttonState); } @Implementation @HiddenApi protected static void nativeOffsetLocation(long nativePtr, float deltaX, float deltaY) { NativeInput.MotionEvent event = getNativeMotionEvent(nativePtr); event.offsetLocation(deltaX, deltaY); } @Implementation(maxSdk = UPSIDE_DOWN_CAKE) @HiddenApi @InDevelopment protected static float nativeGetXOffset(long nativePtr) { NativeInput.MotionEvent event = getNativeMotionEvent(nativePtr); return event.getXOffset(); } @Implementation(maxSdk = UPSIDE_DOWN_CAKE) @HiddenApi @InDevelopment protected static float nativeGetYOffset(long nativePtr) { NativeInput.MotionEvent event = getNativeMotionEvent(nativePtr); return event.getYOffset(); } @Implementation(minSdk = V.SDK_INT) protected final MotionEvent split(int idBits) { NativeInput.MotionEvent event = getNativeMotionEvent(); return event.nativeSplit(idBits); } @Implementation(minSdk = V.SDK_INT) @HiddenApi @InDevelopment protected static float nativeGetRawXOffset(long nativePtr) { return getNativeMotionEvent(nativePtr).getXOffset(); } @Implementation(minSdk = V.SDK_INT) @HiddenApi @InDevelopment protected static float nativeGetRawYOffset(long nativePtr) { return getNativeMotionEvent(nativePtr).getYOffset(); } @Implementation @HiddenApi protected static float nativeGetXPrecision(long nativePtr) { NativeInput.MotionEvent event = getNativeMotionEvent(nativePtr); return event.getXPrecision(); } @Implementation @HiddenApi protected static float nativeGetYPrecision(long nativePtr) { NativeInput.MotionEvent event = getNativeMotionEvent(nativePtr); return event.getYPrecision(); } @Implementation @HiddenApi protected static long nativeGetDownTimeNanos(long nativePtr) { NativeInput.MotionEvent event = getNativeMotionEvent(nativePtr); return event.getDownTime(); } @Implementation @HiddenApi protected static void nativeSetDownTimeNanos(long nativePtr, long downTimeNanos) { NativeInput.MotionEvent event = getNativeMotionEvent(nativePtr); event.setDownTime(downTimeNanos); } @Implementation @HiddenApi protected static int nativeGetPointerCount(long nativePtr) { NativeInput.MotionEvent event = getNativeMotionEvent(nativePtr); return event.getPointerCount(); } @Implementation @HiddenApi protected static int nativeFindPointerIndex(long nativePtr, int pointerId) { NativeInput.MotionEvent event = getNativeMotionEvent(nativePtr); return event.findPointerIndex(pointerId); } @Implementation @HiddenApi protected static int nativeGetHistorySize(long nativePtr) { NativeInput.MotionEvent event = getNativeMotionEvent(nativePtr); return event.getHistorySize(); } @Implementation @HiddenApi protected static void nativeScale(long nativePtr, float scale) { NativeInput.MotionEvent event = getNativeMotionEvent(nativePtr); event.scale(scale); } protected static NativeInput.MotionEvent getNativeMotionEvent(long nativePtr) { // check that MotionEvent was initialized properly. This can occur if MotionEvent was mocked checkState( nativePtr > 0, "MotionEvent has not been initialized. " + "Ensure MotionEvent.obtain was used to create it, instead of creating it directly " + "or via a Mocking framework"); return nativeMotionEventRegistry.getNativeObject(nativePtr); } @Implementation protected void transform(Matrix matrix) { checkNotNull(matrix); NativeInput.MotionEvent event = getNativeMotionEvent(); float[] m = new float[9]; matrix.getValues(m); event.transform(m); } protected NativeInput.MotionEvent getNativeMotionEvent() { long nativePtr = ReflectionHelpers.getField(realMotionEvent, "mNativePtr"); return nativeMotionEventRegistry.getNativeObject(nativePtr); } // Testing API methods /** * @deprecated use {@link MotionEvent#obtain} or {@link * androidx.test.core.view.MotionEventBuilder} to create a MotionEvent with desired data. */ @Deprecated public MotionEvent setPointer2(float pointer1X, float pointer1Y) { NativeInput.MotionEvent event = getNativeMotionEvent(); List pointerCoords = event.getSamplePointerCoords(); List pointerProperties = event.getPointerProperties(); ensureTwoPointers(pointerCoords, pointerProperties); pointerCoords.get(1).setAxisValue(AMOTION_EVENT_AXIS_X, pointer1X); pointerCoords.get(1).setAxisValue(AMOTION_EVENT_AXIS_Y, pointer1Y); return realMotionEvent; } private static void ensureTwoPointers( List pointerCoords, List pointerProperties) { if (pointerCoords.size() < 2) { pointerCoords.add(new NativeInput.PointerCoords()); } if (pointerProperties.size() < 2) { pointerProperties.add(new PointerProperties()); } } /** * @deprecated use {@link MotionEvent#obtain} or {@link * androidx.test.core.view.MotionEventBuilder#setPointerAction(int, int)} to create a * MotionEvent with desired data. */ @Deprecated public void setPointerIndex(int pointerIndex) { NativeInput.MotionEvent event = getNativeMotionEvent(); // pointer index is stored in upper two bytes of action event.setAction( event.getAction() | ((pointerIndex & 0xff) << MotionEvent.ACTION_POINTER_INDEX_SHIFT)); } /** * @deprecated use {@link MotionEvent#obtain} or {@link MotionEventBuilder} to create a * MotionEvent with desired data */ @Deprecated public void setPointerIds(int index0PointerId, int index1PointerId) { NativeInput.MotionEvent event = getNativeMotionEvent(); List pointerCoords = event.getSamplePointerCoords(); List pointerProperties = event.getPointerProperties(); ensureTwoPointers(pointerCoords, pointerProperties); pointerProperties.get(0).id = index0PointerId; pointerProperties.get(1).id = index1PointerId; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy