/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * See the NOTICE file distributed with this work for additional * information regarding copyright ownership. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.appium.android.bootstrap.handler; import com.android.uiautomator.core.UiDevice; import com.android.uiautomator.core.UiObjectNotFoundException; import io.appium.android.bootstrap.*; import io.appium.android.bootstrap.exceptions.InvalidCoordinatesException; import io.appium.android.bootstrap.utils.Point; import org.json.JSONException; import java.util.Hashtable; /** * This handler is used to flick elements in the Android UI. * * Based on the element Id, flick that element. * */ public class Flick extends CommandHandler { private Point calculateEndPoint(final Point start, final Integer xSpeed, final Integer ySpeed) { final UiDevice d = UiDevice.getInstance(); final Point end = new Point(); final double speedRatio = (double) xSpeed / ySpeed; double xOff; double yOff; final double value = Math.min(d.getDisplayHeight(), d.getDisplayWidth()); if (speedRatio < 1) { yOff = value / 4; xOff = value / 4 * speedRatio; } else { xOff = value / 4; yOff = value / 4 / speedRatio; } xOff = Integer.signum(xSpeed) * xOff; yOff = Integer.signum(ySpeed) * yOff; end.x = start.x + xOff; end.y = start.y + yOff; return end; } /* * @param command The {@link AndroidCommand} used for this handler. * * @return {@link AndroidCommandResult} * * @throws JSONException * * @see io.appium.android.bootstrap.CommandHandler#execute(io.appium.android. * bootstrap.AndroidCommand) */ @Override public AndroidCommandResult execute(final AndroidCommand command) throws JSONException { Point start = new Point(0.5, 0.5); Point end = new Point(); Double steps; final Hashtable<String, Object> params = command.params(); final UiDevice d = UiDevice.getInstance(); if (command.isElementCommand()) { AndroidElement el; try { el = command.getElement(); start = el.getAbsolutePosition(start); final Integer xoffset = (Integer) params.get("xoffset"); final Integer yoffset = (Integer) params.get("yoffset"); final Integer speed = (Integer) params.get("speed"); steps = 1250.0 / speed + 1; end.x = start.x + xoffset; end.y = start.y + yoffset; } catch (final Exception e) { return getErrorResult(e.getMessage()); } } else { try { final Integer xSpeed = (Integer) params.get("xSpeed"); final Integer ySpeed = (Integer) params.get("ySpeed"); final Double speed = Math.min(1250.0, Math.sqrt(xSpeed * xSpeed + ySpeed * ySpeed)); steps = 1250.0 / speed + 1; start = PositionHelper.getDeviceAbsPos(start); end = calculateEndPoint(start, xSpeed, ySpeed); } catch (final InvalidCoordinatesException e) { return getErrorResult(e.getMessage()); } catch (final UiObjectNotFoundException e) { return getErrorResult(e.getMessage()); } } steps = Math.abs(steps); Logger.debug("Flicking from " + start.toString() + " to " + end.toString() + " with steps: " + steps.intValue()); final boolean res = d.swipe(start.x.intValue(), start.y.intValue(), end.x.intValue(), end.y.intValue(), steps.intValue()); if (res) { return getSuccessResult(res); } else { return getErrorResult("Flick did not complete successfully"); } } }