/*
* 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 android.os.RemoteException;
import com.android.uiautomator.core.UiDevice;
import io.appium.android.bootstrap.*;
import org.json.JSONException;
import java.util.Hashtable;
/**
* This handler is used to get or set the orientation of the device.
*
*/
public class Orientation extends CommandHandler {
/*
* @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 {
final Hashtable<String, Object> params = command.params();
final String orientation = (String) params.get("orientation");
boolean isNaturalOrientation = false;
if (params.containsKey("naturalOrientation")) {
isNaturalOrientation = Boolean.valueOf(String.valueOf(params.get("naturalOrientation")));
}
if (params.containsKey("orientation")) {
// Set the rotation
try {
return handleRotation(orientation, isNaturalOrientation);
} catch (final Exception e) {
return getErrorResult("Unable to rotate screen: " + e.getMessage());
}
} else {
// Get the rotation
return getRotation(isNaturalOrientation);
}
}
/**
* Returns the current rotation
*
* @return {@link AndroidCommandResult}
*/
private AndroidCommandResult getRotation(boolean isNaturalOrientation) {
String res = null;
final UiDevice d = UiDevice.getInstance();
final OrientationEnum currentRotation = OrientationEnum.fromInteger(d
.getDisplayRotation());
Logger.debug("Current rotation: " + currentRotation);
boolean naturalOrientationRequired = isNaturalOrientation && isWideScreenDevice(d);
if (naturalOrientationRequired) {
Logger.debug("Device's natural display recognized as landscape");
}
switch (currentRotation) {
case ROTATION_0:
case ROTATION_180:
res = naturalOrientationRequired ? "LANDSCAPE" : "PORTRAIT";
break;
case ROTATION_90:
case ROTATION_270:
res = naturalOrientationRequired ? "PORTRAIT" : "LANDSCAPE";
break;
}
if (res != null) {
return getSuccessResult(res);
} else {
return getErrorResult("Get orientation did not complete successfully");
}
}
/**
* Set the desired rotation
*
* @param orientation
* The rotation desired (LANDSCAPE or PORTRAIT)
* @return {@link AndroidCommandResult}
* @throws RemoteException
* @throws InterruptedException
*/
private AndroidCommandResult handleRotation(String orientation, boolean isNaturalOrientation)
throws RemoteException, InterruptedException {
final UiDevice d = UiDevice.getInstance();
OrientationEnum desired;
OrientationEnum current = OrientationEnum.fromInteger(d
.getDisplayRotation());
Logger.debug("Desired orientation: " + orientation);
Logger.debug("Current rotation: " + current);
if (isNaturalOrientation && isWideScreenDevice(d)) {
Logger.debug("Device's natural display recognized as landscape");
orientation = orientation.equalsIgnoreCase("LANDSCAPE") ? "PORTRAIT" : "LANDSCAPE";
}
if (orientation.equalsIgnoreCase("LANDSCAPE")) {
switch (current) {
case ROTATION_0:
d.setOrientationRight();
desired = OrientationEnum.ROTATION_270;
break;
case ROTATION_180:
d.setOrientationLeft();
desired = OrientationEnum.ROTATION_270;
break;
default:
return getSuccessResult("Already in landscape mode.");
}
} else {
switch (current) {
case ROTATION_90:
case ROTATION_270:
d.setOrientationNatural();
desired = OrientationEnum.ROTATION_0;
break;
default:
return getSuccessResult("Already in portrait mode.");
}
}
current = OrientationEnum.fromInteger(d.getDisplayRotation());
// If the orientation has not changed,
// busy wait until the TIMEOUT has expired
final int TIMEOUT = 2000;
final long then = System.currentTimeMillis();
long now = then;
while (current != desired && now - then < TIMEOUT) {
Thread.sleep(100);
now = System.currentTimeMillis();
current = OrientationEnum.fromInteger(d.getDisplayRotation());
}
if (current != desired) {
return getErrorResult("Set the orientation, but app refused to rotate.");
}
return getSuccessResult("Rotation (" + orientation + ") successful.");
}
/**
* this method will determine if the device natural display is landscape.
*/
private static boolean isWideScreenDevice(UiDevice uiDevice){
OrientationEnum rotation = OrientationEnum.fromInteger(uiDevice.getDisplayRotation());
int width = uiDevice.getDisplayWidth();
int height = uiDevice.getDisplayHeight();
// if the device's natural orientation is portrait, false will be returned. Otherwise, true will be returned.
return (!((rotation == OrientationEnum.ROTATION_0 || rotation == OrientationEnum.ROTATION_180) && height > width ||
(rotation == OrientationEnum.ROTATION_90 || rotation == OrientationEnum.ROTATION_270) && width > height));
}
}