while (t.getCause() != null) t = t.getCause();
return t;
}
-}
+
+ /**
+ * Appends {@code cause} at the end of the causal chain of {@code t}
+ *
+ * @return {@code t} for convenience
+ */
+ public static @NonNull Throwable appendCause(@NonNull Throwable t, @Nullable Throwable cause) {
+ if (cause != null) {
+ getRootCause(t).initCause(cause);
+ }
+ return t;
+ }
+}
\ No newline at end of file
com.android.internal.R.dimen.config_screen_magnification_scaling_threshold,
scaleValue, false);
mScalingThreshold = scaleValue.getFloat();
- mScaleGestureDetector = new ScaleGestureDetector(context, this);
+ mScaleGestureDetector = new ScaleGestureDetector(context, this, Handler.getMain());
mScaleGestureDetector.setQuickScaleEnabled(false);
- mScrollGestureDetector = new GestureDetector(context, this);
+ mScrollGestureDetector = new GestureDetector(context, this, Handler.getMain());
}
@Override
@VisibleForTesting boolean mShortcutTriggered;
- @VisibleForTesting Handler mHandler = new Handler(this);
+ @VisibleForTesting Handler mHandler = new Handler(Looper.getMainLooper(), this);
public DetectingState(Context context) {
mLongTapMinDelay = ViewConfiguration.getLongPressTimeout();
final int type = message.what;
switch (type) {
case MESSAGE_ON_TRIPLE_TAP_AND_HOLD: {
- onTripleTapAndHold(/* down */ (MotionEvent) message.obj);
+ MotionEvent down = (MotionEvent) message.obj;
+ transitionToViewportDraggingStateAndClear(down);
+ down.recycle();
}
break;
case MESSAGE_TRANSITION_TO_DELEGATING_STATE: {
// over insta-delegating on 3tap&swipe
// (which is a rare combo to be used aside from magnification)
if (isMultiTapTriggered(2 /* taps */)) {
- transitionTo(mViewportDraggingState);
- clear();
+ transitionToViewportDraggingStateAndClear(event);
} else {
transitionToDelegatingStateAndClear();
}
/** -> {@link ViewportDraggingState} */
public void afterLongTapTimeoutTransitionToDraggingState(MotionEvent event) {
mHandler.sendMessageDelayed(
- mHandler.obtainMessage(MESSAGE_ON_TRIPLE_TAP_AND_HOLD, event),
+ mHandler.obtainMessage(MESSAGE_ON_TRIPLE_TAP_AND_HOLD,
+ MotionEvent.obtain(event)),
ViewConfiguration.getLongPressTimeout());
}
}
}
- void onTripleTapAndHold(MotionEvent down) {
+ void transitionToViewportDraggingStateAndClear(MotionEvent down) {
if (DEBUG_DETECTING) Slog.i(LOG_TAG, "onTripleTapAndHold()");
clear();
import android.annotation.NonNull;
import android.content.Context;
-import android.os.Handler;
import android.os.Message;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.util.concurrent.CompletableFuture;
import java.util.function.IntConsumer;
-import java.util.function.Supplier;
/**
verify(mMgh.getNext(), times(2)).onMotionEvent(any(), any(), anyInt());
}
+ @Test
+ public void testTripleTapAndHold_zoomsImmediately() {
+ assertZoomsImmediatelyOnSwipeFrom(STATE_2TAPS);
+ assertZoomsImmediatelyOnSwipeFrom(STATE_SHORTCUT_TRIGGERED);
+ }
+
+ private void assertZoomsImmediatelyOnSwipeFrom(int state) {
+ goFromStateIdleTo(state);
+ swipeAndHold();
+ assertIn(STATE_DRAGGING_TMP);
+ returnToNormalFrom(STATE_DRAGGING_TMP);
+ }
+
private void assertTransition(int fromState, Runnable transitionAction, int toState) {
goFromStateIdleTo(fromState);
transitionAction.run();
check(tapCount() == 2, state);
} break;
case STATE_DRAGGING: {
+ check(isZoomed(), state);
check(mMgh.mCurrentState == mMgh.mViewportDraggingState,
state);
check(mMgh.mViewportDraggingState.mZoomedInBeforeDrag, state);
} break;
case STATE_DRAGGING_TMP: {
+ check(isZoomed(), state);
check(mMgh.mCurrentState == mMgh.mViewportDraggingState,
state);
check(!mMgh.mViewportDraggingState.mZoomedInBeforeDrag, state);
check(!isZoomed(), state);
} break;
case STATE_PANNING: {
+ check(isZoomed(), state);
check(mMgh.mCurrentState == mMgh.mPanningScalingState,
state);
check(!mMgh.mPanningScalingState.mScaling, state);
} break;
case STATE_SCALING_AND_PANNING: {
+ check(isZoomed(), state);
check(mMgh.mCurrentState == mMgh.mPanningScalingState,
state);
check(mMgh.mPanningScalingState.mScaling, state);
package com.android.server.testutils;
-import static android.util.ExceptionUtils.getRootCause;
+import static android.util.ExceptionUtils.appendCause;
import static android.util.ExceptionUtils.propagate;
import android.os.Handler;
+import android.os.Looper;
import android.os.Message;
import android.os.SystemClock;
import android.util.ArrayMap;
}
public TestHandler(Callback callback, LongSupplier clock) {
- super(callback);
+ super(Looper.getMainLooper(), callback);
mClock = clock;
}
} catch (Throwable t) {
// Append stack trace of this message being posted as a cause for a helpful
// test error message
- throw propagate(getRootCause(t).initCause(msg.postPoint));
+ throw propagate(appendCause(t, msg.postPoint));
} finally {
msg.message.recycle();
}