package com.mopub.mobileads;
import android.support.annotation.Nullable;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import com.mopub.common.AdReport;
public class AdAlertGestureListener extends GestureDetector.SimpleOnGestureListener{
private static final int MINIMUM_NUMBER_OF_ZIGZAGS_TO_FLAG = 4;
private static final float MAXIMUM_THRESHOLD_X_IN_DIPS = 100;
private static final float MAXIMUM_THRESHOLD_Y_IN_DIPS = 100;
@Nullable private final AdReport mAdReport;
private float mCurrentThresholdInDips = MAXIMUM_THRESHOLD_X_IN_DIPS;
private float mPreviousPositionX;
private boolean mHasCrossedLeftThreshold;
private boolean mHasCrossedRightThreshold;
private AdAlertReporter mAdAlertReporter;
enum ZigZagState { UNSET, GOING_RIGHT, GOING_LEFT, FINISHED, FAILED}
private int mNumberOfZigZags;
private float mPivotPositionX;
private ZigZagState mCurrentZigZagState = ZigZagState.UNSET;
private View mView;
AdAlertGestureListener(View view, @Nullable AdReport adReport) {
super();
if (view != null && view.getWidth() > 0) {
mCurrentThresholdInDips = Math.min(MAXIMUM_THRESHOLD_X_IN_DIPS, view.getWidth() / 3f);
}
mView = view;
mAdReport = adReport;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
if (mCurrentZigZagState == ZigZagState.FINISHED) {
return super.onScroll(e1, e2, distanceX, distanceY);
}
// e1 is always the initial touch down event.
// e2 is the true motion event
if (isTouchOutOfBoundsOnYAxis(e1.getY(), e2.getY())) {
mCurrentZigZagState = ZigZagState.FAILED;
return super.onScroll(e1, e2, distanceX, distanceY);
}
switch(mCurrentZigZagState) {
case UNSET:
mPivotPositionX = e1.getX();
updateInitialState(e2.getX());
break;
case GOING_RIGHT:
updateZig(e2.getX());
break;
case GOING_LEFT:
updateZag(e2.getX());
break;
case FAILED:
break;
default:
break;
}
mPreviousPositionX = e2.getX();
return super.onScroll(e1, e2, distanceX, distanceY);
}
void finishGestureDetection() {
if (mCurrentZigZagState == mCurrentZigZagState.FINISHED) {
mAdAlertReporter = new AdAlertReporter(mView.getContext(), mView, mAdReport);
mAdAlertReporter.send();
}
reset();
}
void reset() {
mNumberOfZigZags = 0;
mCurrentZigZagState = ZigZagState.UNSET;
}
private boolean isTouchOutOfBoundsOnYAxis(float initialY, float currentY) {
return (Math.abs(currentY - initialY) > MAXIMUM_THRESHOLD_Y_IN_DIPS);
}
private void updateInitialState(float currentPositionX) {
if (currentPositionX > mPivotPositionX) {
mCurrentZigZagState = ZigZagState.GOING_RIGHT;
}
}
private void updateZig(float currentPositionX) {
if (rightThresholdReached(currentPositionX) && isMovingLeft(currentPositionX)) {
mCurrentZigZagState = ZigZagState.GOING_LEFT;
mPivotPositionX = currentPositionX;
}
}
private void updateZag(float currentPositionX) {
if (leftThresholdReached(currentPositionX) && isMovingRight(currentPositionX)) {
mCurrentZigZagState = ZigZagState.GOING_RIGHT;
mPivotPositionX = currentPositionX;
}
}
private void incrementNumberOfZigZags() {
mNumberOfZigZags++;
if(mNumberOfZigZags >= MINIMUM_NUMBER_OF_ZIGZAGS_TO_FLAG) {
mCurrentZigZagState = ZigZagState.FINISHED;
}
}
private boolean rightThresholdReached(float currentPosition) {
if (mHasCrossedRightThreshold) {
return true;
} else if (currentPosition >= mPivotPositionX + mCurrentThresholdInDips) {
mHasCrossedLeftThreshold = false;
mHasCrossedRightThreshold = true;
return true;
} else {
return false;
}
}
private boolean leftThresholdReached(float currentPosition) {
if (mHasCrossedLeftThreshold) {
return true;
} else if (currentPosition <= mPivotPositionX - mCurrentThresholdInDips) {
mHasCrossedRightThreshold = false;
mHasCrossedLeftThreshold = true;
incrementNumberOfZigZags();
return true;
} else {
return false;
}
}
private boolean isMovingRight(float currentPositionX) {
return (currentPositionX > mPreviousPositionX);
}
private boolean isMovingLeft(float currentPositionX) {
return (currentPositionX < mPreviousPositionX);
}
@Deprecated // for testing
int getNumberOfZigzags() {
return mNumberOfZigZags;
}
@Deprecated // for testing
float getMinimumDipsInZigZag() {
return mCurrentThresholdInDips;
}
@Deprecated // for testing
ZigZagState getCurrentZigZagState() {
return mCurrentZigZagState;
}
@Deprecated // for testing
AdAlertReporter getAdAlertReporter(){
return mAdAlertReporter;
}
}