package com.mindbodyonline.ironhide.Infrastructure.Extensions; import android.support.test.espresso.PerformException; import android.support.test.espresso.UiController; import android.support.test.espresso.ViewAction; import android.support.test.espresso.action.CoordinatesProvider; import android.support.test.espresso.action.PrecisionDescriber; import android.view.View; import android.view.ViewConfiguration; import com.mindbodyonline.ironhide.Infrastructure.Extensions.Zoomer.Status; import org.hamcrest.Matcher; import java.util.Arrays; import static android.support.test.espresso.matcher.ViewMatchers.isDisplayingAtLeast; import static android.support.test.espresso.util.HumanReadables.describe; import static com.mindbodyonline.ironhide.Infrastructure.Extensions.Zoomer.Status.FAILURE; import static com.mindbodyonline.ironhide.Infrastructure.Extensions.Zoomer.Status.SUCCESS; import static java.lang.String.format; /** * Enables zooming across a view. */ public class GeneralZoomAction implements ViewAction { /** Maximum number of times to attempt sending a zoom action. */ private static final int MAX_TRIES = 3; /** The minimum amount of a view that must be displayed in order to zoom across it. */ private static final int VIEW_DISPLAY_PERCENTAGE = 90; private final CoordinatesProvider[] startCoordinatesProviders; private final CoordinatesProvider[] endCoordinatesProviders; private final Zoomer zoomer; private final PrecisionDescriber precisionDescriber; public GeneralZoomAction(Zoomer zoomer, CoordinatesProvider[] startCoordinatesProviders, CoordinatesProvider[] endCoordinatesProviders, PrecisionDescriber precisionDescriber) { this.zoomer = zoomer; this.startCoordinatesProviders = startCoordinatesProviders; this.endCoordinatesProviders = endCoordinatesProviders; this.precisionDescriber = precisionDescriber; } @Override public Matcher<View> getConstraints() { return isDisplayingAtLeast(VIEW_DISPLAY_PERCENTAGE); } @Override public void perform(UiController uiController, View view) { float[][] startCoordinates = new float[][]{ startCoordinatesProviders[0].calculateCoordinates(view), startCoordinatesProviders[1].calculateCoordinates(view) }; float[][] endCoordinates = new float[][]{ endCoordinatesProviders[0].calculateCoordinates(view), endCoordinatesProviders[1].calculateCoordinates(view) }; float[] precision = precisionDescriber.describePrecision(); Status status = FAILURE; for (int tries = 0; tries < MAX_TRIES && status != SUCCESS; tries++) { try { status = zoomer.sendZoom(uiController, startCoordinates, endCoordinates, precision); } catch (RuntimeException e) { throw new PerformException.Builder() .withActionDescription(getDescription()) .withViewDescription(describe(view)) .withCause(e) .build(); } // ensures that all work queued to process the zoom has been run. uiController.loopMainThreadForAtLeast(ViewConfiguration.getPressedStateDuration()); } if (status == FAILURE) { String failure = format("Couldn't zoom from: %s to: %s" + " precision: %s. Zoomer: %s start coordinate providers: %s" + " precision describer: %s. Tried %s times", Arrays.deepToString(startCoordinates), Arrays.deepToString(endCoordinates), Arrays.toString(precision), zoomer, Arrays.toString(startCoordinatesProviders), precisionDescriber, MAX_TRIES); throw new PerformException.Builder() .withActionDescription(getDescription()) .withViewDescription(describe(view)) .withCause(new RuntimeException(failure)) .build(); } } @Override public String getDescription() { return zoomer.toString().toLowerCase() + " zoom"; } }