Orientation

调整屏幕方向的操作。

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();
if (params.containsKey("orientation")) {
// Set the rotation final String orientation = (String) params.get("orientation");
try {
return handleRotation(orientation);
} catch (final Exception e) {
return getErrorResult("Unable to rotate screen: " + e.getMessage());
}
} else {
// Get the rotation
return getRotation();
} } /**
* Returns the current rotation
*
* @return {@link AndroidCommandResult}
*/
private AndroidCommandResult getRotation() {
String res = null;
final UiDevice d = UiDevice.getInstance();
final OrientationEnum currentRotation = OrientationEnum.fromInteger(d
.getDisplayRotation());
Logger.debug("Current rotation: " + currentRotation);
switch (currentRotation) {
case ROTATION_0:
case ROTATION_180:
res = "PORTRAIT";
break;
case ROTATION_90:
case ROTATION_270:
res = "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(final String orientation)
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 (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.");
}
}

这个事件有点小复杂哈,当初研究uiautomator源代码时就被它折腾的不行。也仅仅实验了左和上的方向成功。

没办法,既然又遇到了,那就仅仅能纯理论讲啦。

execute方法中。首先推断參数中是否含有orientation,假设含有调用handleRotation。否则调用getRotation。

所以execute又分流到上面的2个方法中。

handleRotation

这样的情况是參数里含有orientation,此时。我们来看看该方法中做了哪些事。

final UiDevice d = UiDevice.getInstance();
OrientationEnum desired;
OrientationEnum current = OrientationEnum.fromInteger(d
.getDisplayRotation());

首先获取当前设备的方向,然后初始化一个私有变量,以备后用。当中OrientationEnum枚举类里定义了4个方向,fromInteger方法是依据整数值得到对应的枚举值,当中各个值的意思。

public enum OrientationEnum {
ROTATION_0(0), ROTATION_90(1), ROTATION_180(2), ROTATION_270(3); public static OrientationEnum fromInteger(final int x) {
switch (x) {
case 0:
return ROTATION_0;
case 1:
return ROTATION_90;
case 2:
return ROTATION_180;
case 3:
return ROTATION_270;
}
return null;
}

ROTATION_0:你正常查看手机时,竖屏。此时屏幕的方向为0度。此时的power键在顶端。

例如以下:

ROTATION_90:你将上面的屏幕向右顺时针旋转90度,此时设备旋转角度为90度,此时我的power键在右端。假设此时你的设备能够自己主动旋转屏幕的话。你屏幕里面的内容应该是什么样的?例如以下所看到的

ROTATION_180:从90度角再向下顺时针旋转90度。此时我的power键在下端。此时的角度为180.因为我的手机禁止了这样的自由旋转,所以此时的屏幕展如今我的面前是这样一番景象:

ROTATION_270:从180度再顺时针想左旋转90度。此时我power键在左边。此时为270度。展如今我面前的图例如以下:

假设你理解了上面4个keyword的意思。那么以下理解代码就非常easy啦。

handleRotation方法里做完初始化操作以后。就要推断client要求是横屏还是竖屏。假设是横屏,处理例如以下:

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.");
}
}

假设是横屏的话,那么仅仅须要处理屏幕处于0度和180度的情况,由于90度和270度都已经是横屏啦,自然不须要再处理。

假设是ROTATION_0,说明设备朝上,此时想要横屏,自然是顺时针向右旋转一下屏幕。此时,正常情况下能够旋转的话。屏幕里的视图应该是从左到右的,所以desired的值才会被设置为ROTATION_270.所以要分清屏幕的角度和视图的角度。

以下就是向右顺时针旋转90度后,里面的视图是270度的。此时power键在右端。

假设是ROTATION_180度,说明设备拿反了,power键朝下。此时你向左顺时针旋转90度或者向右逆时针旋转90度。都能达到横屏的效果。源代码里是向左旋转的,此时power键朝左,视图和上面是一样的,desired的值为ROTATION——270.

====================================================================================================================================

假设client传递过来的命令想要的是竖屏。就要走else里的代码块:

else {
switch (current) {
case ROTATION_90:
case ROTATION_270:
d.setOrientationNatural();
desired = OrientationEnum.ROTATION_0;
break;
default:
return getSuccessResult("Already in portrait mode.");
}
}

此时仅仅要处理90度和270的情况。我们要把它变为ROTATION_0的情况,d.setOrientationNatural()是设置设备转到自然方向,该方向就是设备初始设置的方向。说明通常的设备横屏的2个方向能够旋转。竖屏方向就仅仅有一个方向能够旋转。上面的处理完成后,方法会做一个推断,推断是否旋转成功。

 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.");

首先获得此时屏幕的方向,然后推断一下与预期的是否同样。假设不同样,等待2秒钟,再获取一次屏幕的方向,假设经过这么一次验证完成后。当前的屏幕方向仍然和预期的不同样,那么就返回旋转失败的消息给client。假设同样的话,就返回旋转成功的消息给client。

到此为止handleRotation处理完成。以下处理參数里不含有orientation的情况。

getRotation

该方法中就是依据当前的屏幕的方向得到横屏还是竖屏,将结果返回给client。

非常easy。

总结

通过上面的分析。说明client关于屏幕方向的命令有2种:

  • 获取屏幕的方向
  • 改变屏幕的方向

大家要特别主要选择方向的定义,设备的方向和里面视图的方向的差别。

bootstrap之Orientation的更多相关文章

  1. 手机自动化测试:appium源码分析之bootstrap四

    手机自动化测试:appium源码分析之bootstrap四   Orientation是调整屏幕方向的操作 package io.appium.android.bootstrap.handler; i ...

  2. Bootstrap WPF Style,Bootstrap风格的WPF样式

    简介 GitHub地址:https://github.com/ptddqr/bootstrap-wpf-style 此样式基于bootstrap-3.3.0,样式文件里的源码行数都是指的这个版本.CS ...

  3. 关于bootstrap的datepicker在meteor应用中的使用(不包含bootstrap框架)

    1.安装bootstrap3-datepicker包 meteor add rajit:bootstrap3-datepicker 2.使用方法 Example In your handlebars ...

  4. bootstrap之Click大事

    上一篇文章中谈到了bootstrap流程,本文开始把目光bootstrap它可以接受指令(从源代码视图的透视.因为appium该项目现在还处于不断更新,因此,一些指令已经实现.也许未来会实现一些.从视 ...

  5. Appium Android Bootstrap源码分析之命令解析执行

    通过上一篇文章<Appium Android Bootstrap源码分析之控件AndroidElement>我们知道了Appium从pc端发送过来的命令如果是控件相关的话,最终目标控件在b ...

  6. 基于Bootstrap的炫酷jQuery slider插件

    简要教程 这是一款在原生bootstrap slider的基础上制作效果非常炫酷的jQuery slider插件.该slider插件可以自定义slider的颜色.形状.透明度和tooltip等属性,美 ...

  7. BootStrap详解之(一)

    一.BootStrap简介 BootStrap是一个用来构建网站前段框架的一个插件.无论你是想构建应用程序.博客还是CMS网站,Bootstrap都特别的使用,只要你想得到,它就能行.Bootstra ...

  8. Appuim源码剖析(Bootstrap)

    Appuim源码剖析(Bootstrap) SkySeraph Jan. 26th 2017 Email:skyseraph00@163.com 更多精彩请直接访问SkySeraph个人站点:www. ...

  9. 手机自动化测试:appium源码分析之bootstrap三

    手机自动化测试:appium源码分析之bootstrap三   研究bootstrap源码,我们可以通过代码的结构,可以看出来appium的扩展思路和实现方式,从中可以添加我们自己要的功能,针对app ...

随机推荐

  1. unity 美术注意事项

    有时候美术的一个不小心,就会给程序徒增极大的工作量,所以在项目开始之前是有必要和美术沟通一下,来规范一些东西, 1.将单体模型的轴心置中. 2.模型有父物体时,子物体应相对于父物体的(0,0,0)位置 ...

  2. 中断API之enable_irq

    void enable_irq(unsigned int irq) 用于使能一个irq. void disable_irq(unsigned int irq)则用于禁止一个irq 其使用的例程如下: ...

  3. 【UVa 12563】Jin Ge Jin Qu hao

    [Link]: [Description] KTV给你T秒的唱歌时间; 你有n首一定要唱的歌; 然后有一首很变态的歌有678s,你想在T秒结束之前唱一下这首歌; 因为这样的话,你能尽量晚地走出KTV( ...

  4. Java Exception和Error的差别

    Java中异常的抽象类是Throwable,在此基础上.派生出两大类:Error和Exception. Error是程序中的严重错误,不应该用try-catch包括.Javadoc的说明例如以下: A ...

  5. 将IP表存入SQL里的程序

    将IP表存入SQL里的程序 写得比較粗糙,另一点错误,只是能达到效果.请大家測试  create.asp  ---------------------------------------------- ...

  6. 学习 shell —— 创建序列数组

    list/array 1. seq 方法创建 基本用法: $ a_num_seq = ($seq 5) $ echo $a_num_seq 1 2 3 4 5 a_num_seq 得到是字符串,不同之 ...

  7. 如何保证对象线程内唯一:数据槽(CallContext)

    CallContext 是类似于方法调用的线程本地存储区的专用集合对象,并提供对每个逻辑执行线程都唯一的数据槽.数据槽不在其他逻辑线程上的调用上下文之间共享.当 CallContext 沿执行代码路径 ...

  8. Excel 文本内容拆分

    1.首先把文本数据粘贴到excel-->在旁边插入空白列..选择数据-->分列-->固定宽度 2.数据预览点击下一步 3.最后分好的数据就在 归去来兮,田园将芜胡不归?既自以心为形役 ...

  9. ES6第一节:开发环境的搭建

    前言:由于目前浏览器对ES6的支持度不高,需要借助babel将编写好的ES6代码转换成ES5,浏览器才能解析. 需要在NodeJS环境下运行 一. 建立结构:两个文件夹和一个html文件,分别是src ...

  10. ES6学习笔记(六)数组的扩展

    1.扩展运算符 1.1含义 扩展运算符(spread)是三个点(...).它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列. console.log(...[1, 2, 3]) // ...