本文来自于腾讯bugly开发者社区,未经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/583ba1df25d735cd2797004d

由于Android系统的开放策略,Android手机呈现碎片化的趋势,兼容性问题一直是Android App 开发者头疼的难题。本文以Android相机预览方向为例,探索在Android机型适配上的一些思路。

1. android相机简介

由于Android系统的开放策略,Android手机呈现碎片化的趋势,兼容性问题一直是Android App 开发者头疼的难题。本文以Android相机预览方向为例,探索在Android机型适配上的一些思路。

1.1 相机架构

先了解下Camera的框架,它是分层的结构。由上向下分别是

1)应用层

2)Camera系统的Java类

3)Camera的JNI代码

4)Camera的本地框架

5)Camera服务部分

6)Camera HAL(Hardware Abstraction Layer)硬件抽象层

图一Camera architecture

其中Camera HAL主要的接口文件为CameraHardwareInterface.h ,需要各个系统根据自己的情况实现。由于设备底层硬件的千变万化,android框架不可能提供统一的硬件驱动以及接口实现,只能提供标准的接口,因此硬件提供商需要自己开发设备驱动,并去实现android框架提供的接口。

而实际上,由于机器的硬件配置不同,厂商的底层实现不同,Andriod版本的不同,在一部手机上调试正常的程序,不一定能在其他机型上正常运行。其中与摄像头相关的适配问题包括摄像头个数、preview size大小、预览方向、闪光灯、对焦方式、帧率等等。

本文以相机预览方向为例,探讨这个问题产生的原因,以及一些可行的解决方法。

2. 相机预览方向适配问题的产生

2.1相机的安装方向

相机图像数据都是来自于相机硬件的图像传感器(Image Sensor),这个Sensor被固定到手机之后是有一个默认的取景方向,且不会改变。比如MI3手机的屏幕“自然”方向和后置相机的图像传感器方向是如图二所示的。

图二MI3手机的屏幕“自然”方向和后置相机的图像传感器方向

在MI3手机上,对于一个横屏应用来说,屏幕“自然”方向和后置相机的图像传感器方向一致,因此看到的图像是正的,如图三所示。而对于一个竖屏应用来说,屏幕“自然”方向和后置相机的图像传感器方向是不一致,从图像传感器的角度看,它看到的图像是侧过来的,如图四所示,需要将相机预览图像顺时针旋转90度,才和屏幕“自然”方向一致。在Android系统中,提供camera.setDisplayOrientation(angle)方法,用来设置相机预览图像顺时针旋转的角度。

图三MI3手机横屏的相机应用

图四MI3手机竖屏的相机应用

2.2相机的安装方向如何获取?

Android官方提供orientation这个属性来读取,官方定义如图五所示:orientation表示相机图像的方向。它的值是相机图像顺时针旋转到设备自然方向一致时的角度。例如假设设备是竖屏的。后置相机传感器是横屏安装的。当你面向屏幕时,如果后置相机传感器顶边的和设备自然方向的右边是平行的,则后置相机的orientation是90。如果前置相机传感器顶边和设备自然方向的右边是平行的,则前置相机的orientation是270。

int android.hardware.Camera.CameraInfo.orientation

public int orientation

Added in API level 9

The orientation of the camera image. The value is the angle that the camera image needs to be rotated clockwise so it shows correctly on the display in its natural orientation. It should be 0, 90, 180, or 270. 

For example, suppose a device has a naturally tall screen. The back-facing camera sensor is mounted in landscape. You are looking at the screen. If the top side of the camera sensor is aligned with the right edge of the screen in natural orientation, the value should be 90. If the top side of a front-facing camera sensor is aligned with the right of the screen, the value should be 270.

图五camerainfo.orientation定义

以MI3为例,通过程序调用取到的后置相机的orientation是90,前置相机的orientation是270。我理解的orientation是相机采集的图像顺时针旋转到屏幕自然方向的角度。图六所示是MI3手机的后置相机和前置相机对准同一个小人,后置前置相机采集到的图像及前置相机预览的图像。需要特别说明的是,对于前置相机来说,相机预览的图像是相机采集到的图像的镜像, 关注图六中小人头发在前置采集到的图像和预览的图像中头发的不同。因此在MI3手机上做竖屏应用时,对于后置相机的预览方向,只需要旋转后置相机的orientation,即90度即可和屏幕方向保持一致;对于前置相机的预览方向,由于系统对前置相机采集到的图像做了镜像,因此需要旋转270-180,也是90度即可和屏幕方向保持一致。

图六MI3手机上orientation的例子。

2.3官方推荐的相机预览方向适配做法

通过orientation属性的含义可以知道,我们可以用它和应用的方向来做相机预览方向的适配,图七是官方网站推荐的代码。但并不是所有手机的orientation值都靠谱,比如VIVO V1手机第一次获取后置相机的CameraInfo的orientation值是90,而当执行了mCamera = Camera.open();之后再获取CameraInfo的orientation值就是0,而且以后获取的都是 0 ,除非重启手机。无论是这款手机上的哪个应用,只要执行了一次Camera.open()之后,其他所有程序中获取CameraInfo的orientation都是是0。因此按照此方法做适配不能解决所有手机上的问题。

图七 Android官方推荐的相机预览方向的适配做法

3. 相机预览方向适配

3.1方案一:App端添加兼容性代码

思路是在App端对特殊的手机添加兼容性代码,如下所示。这样可以解决部分问题,但当版本发出后,又发现问题只能等版本升级修复;同时由于手机型号,系统版本的很多组合,而且客户端要维护一套很长的代码。很自然的想到把相机预览方向的角度做成后台配置,就有了方案二。

if (is VIVO V1 mobile) {
camera.setDisplayOrientation(90);
} else if (is MotoXPro mobile) {
camera.setDisplayOrientation(270);
} else {
Android官方推荐的相机预览方向适配做法
}

3.2方案二:Server端动态配置

为了解决方案一的弊端,可以将相机预览方向顺时针旋转的角度抽取出来,作为一个变量从server端下发。这样可以做到机型无关,版本发布后,出现问题可以通过Server端上线新的配置来解决。但新机型上问题的发现,确认,解决,上线均需要一定的人力耗费,而且有滞后性。还有没有更好的解决方案呢?

if (get angle from server) {
camera.setDisplayOrientation(angle);
} else {
Android官方推荐的相机预览方向适配做法
}

3.3方案三:Server端动态配置与用户自助引导相结合

公司一直提倡开发人员有产品思维。从产品的角度说,用户在使用相机应用时,他是知道相机预览方向是正确的还是错误的,我们可以给用户一个旋转相机预览方向的按钮,当用户发现方向不对时,通过自助点击按钮解决问题。如下图所示

图八 发生问题时,引导用户自助旋转相机预览方向

这样即具有方案二的优点,同时又可以实时解决用户的问题,不需要用户等待我们后台下发正确的配置。进一步的,如果发现用户点击了旋转按钮,同时正确使用了相机功能,可以将本机型对应的angle上报给Server端。Server端可以自动或辅助人工以更新配置。对于QQ安全中心APP来说,在人脸验证过程需要打开前置相机,如果用户本次人脸验证点击了旋转预览方向按钮,同时又通过了人脸验证,我们可以认为用户正确使用了相机功能,Server端可以自动更新用户上报的angle,使和该用户同机型的其他用户都受益。

if (get angle from server) {
camera.setDisplayOrientation(angle);
} else {
Android官方推荐的相机预览方向适配做法
}
...
if (user click rotate icon) {
angle = angle + 90;
camera.setDisplayOrientation(angle);
}
...
report(angle);

4 结语

在做相机相关的App时,需要考虑的适配问题还有很多,远不止相机预览方向这一种。总的思路就是能实时解决的就不滞后,能动态配置的就不要写死在App端,有时可以换个角度,考虑技术和产品相结合的方案。


更多精彩内容欢迎关注腾讯优测的微信公众账号:

腾讯优测是专业的移动云测试平台,为应用、游戏、H5混合应用的研发团队提供产品质量检测与问题解决服务。不仅在线上平台提供app自动化测试、云真机远程操控与调试、私有自动化测试工具XTest等多种质量检测工具,更为VIP客户配备了专家团队提供定制化综合测试解决方案。

【腾讯优测干货分享】Android 相机预览方向及其适配探索的更多相关文章

  1. 腾讯优测干货精选|Android双卡双待适配——隐藏在数据库中的那些秘密

    腾讯优测是专业的app自动化测试平台,除了提供兼容性测试,远程真机租用等多维度的测试服务,还有优分享-腾讯内部的移动研发测试干货精选~ 许多APP都希望获取用户通讯录联系人,利用通讯录关系链信息来丰富 ...

  2. 【腾讯优测干货分享】微信小程序之自动化亲密接触

    本文来自于腾讯优测公众号(wxutest),未经作者同意,请勿转载,原文地址:http://mp.weixin.qq.com/s/HcPakz5CV1SHnu-U8n85pw 导语 山雨欲来风满楼,最 ...

  3. 【腾讯优测干货分享】安卓专项测试之GPU测试探索

    本文来自于Dev Club 开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/57c7ffdc0569a1191bce8a63 作者:章未哲——腾讯SNG质 ...

  4. 【腾讯优测干货分享】如何降低App的待机内存(四)——进阶:内存原理

    本文来自于腾讯优测公众号(wxutest),未经作者同意,请勿转载,原文地址:http://mp.weixin.qq.com/s/3FTPFvZRqyAQnU047kmWJQ 1.4进阶:内存原理 在 ...

  5. 【腾讯优测干货分享】如何降低App的待机内存(三)——探索内存增长的原因

    本文来自于腾讯优测公众号(wxutest),未经作者同意,请勿转载,原文地址:https://mp.weixin.qq.com/s/8BiKIt3frq9Yv9KV5FXlGw 1.3新问题的进一步挖 ...

  6. 【腾讯优测干货分享】如何降低App的待机内存(二)——规范测试流程及常见问题

    本文来自于腾讯优测公众号(wxutest),未经作者同意,请勿转载,原文地址:https://mp.weixin.qq.com/s/806TiugiSJvFI7fH6eVA5w 作者:腾讯TMQ专项测 ...

  7. 【腾讯优测干货分享】越用越卡为哪般——如何降低App的待机内存(一)

    本文来自于腾讯优测公众号(wxutest),未经作者同意,请勿转载,原文地址:http://mp.weixin.qq.com/s/1_FKMbi1enpcKMqto-o_FQ 作者:腾讯TMQ专项测试 ...

  8. 【腾讯优测干货分享】如何降低App的待机内存(五)——优化dex相关内存及本章总结

    本文来自于腾讯优测公众号(wxutest),未经作者同意,请勿转载,原文地址:http://mp.weixin.qq.com/s/01Abwe0p1h3WLh28Tzg_Dw 1.5案例:优化dex相 ...

  9. 【腾讯优测干货分享】Android内存泄漏的简单检查与分析方法

    本文来自于Dev Club 开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/57d14047603a5bf1242ad01b 导语 内存泄漏问题大约是An ...

随机推荐

  1. Conditional project or library reference in Visual Studio

    Conditional project or library reference in Visual Studio In case you were wondering why you haven’t ...

  2. JMeter执行dos命令

    1.通过java代码实现 参考Java实现操作dos命令 2.直接通过JMeter内置的beanshell脚本操作 String command = "cmd /c start ping w ...

  3. 命名规范(数据库,c#)

    Ⅰ.  Naming Conventions 1. Table Naming Rule 1a ( Prefix) 新加的Table要加上適當的前缀 e.g.  mUsr, eTxn, tmpRolle ...

  4. 在Heroku上部署Node.js应用

    最近在学习Node.js,想找一个可以免费部署Node的平台,于是便找到了Heroku 直接进入主题,接下来我们一步一步部署自己的Node应用. 步骤1: 注册一个免费的Heroku账号. 步骤2: ...

  5. python学习6 web开发

    wsgi自带,用语构建简单服务器 例子 from wsgiref.simple_server import make_server def index(env, res): res('200 ok', ...

  6. 基于dubbo的分布式项目实例应用

    本文主要学习dubbo服务的启动检查.集群容错.服务均衡.线程模型.直连提供者.只定阅.只注册等知识点,希望通过实例演示进一步理解和掌握这些知识点. 启动检查 Dubbo缺省会在启动消费者时检查依赖的 ...

  7. 【算法杂谈】Miller-Rabin素性测试算法

    额,我们今天来讲一讲Miller-Rabin素性测试算法. 读者:怎么又是随机算法!!!(⊙o⊙)… [好了,言归正传] [费马小定理] 费马小定理只是个必要条件,符合费马小定理而非素数的数叫做Car ...

  8. php js数组问题

    <script type="text/javascript"> var a = new Array(); a = "a"; a = "b& ...

  9. java-并发-不可变对象

    浏览以下内容前,请点击并阅读 声明 当一个对象创建后的状态不可改变时就认为其为不可变对象,尽可能地利用不可变对象被公认为是构建简单可靠代码的有效方法.不可变对象在并发程序中比较有用,由于其状态无法改变 ...

  10. [转] nodemon 基本配置与使用

    在开发环境下,往往需要一个工具来自动重启项目工程,之前接触过 python 的 supervisor,现在写 node 的时候发现 supervisior 在很多地方都有他的身影,node 也有一个 ...