,


此篇博客是记一次客户需求修改,从上周五到现在正好一周时间,期间的各种酸爽,就不说了,还是来看大家关注的技术问题吧。


首先看下以前效果和修改后的效果:

修改前:修改后:

不知道有没有看明白,我在简单说下,没修改前Camera 设置中是有两个选项的一个负责预览大小(显示的宽高比如16:9),一个负责照片大小(如1600x1200),修改后 只要一个Picture Size 即负责切换预览大小也负责照片大小。


看到这是不是觉的好简单只要在Picture Size添加几个选项,然后在点击不同像素的选项时同样也能切换比例,。。。。。。。。。。。。。。其实呢就是这么简单!!!

但是前提是需要对系统的Camera有一定的了解,不然就和我一样苦逼的搞了一周最后发现只要不到50行代码就可以实现这个功能。所以改这个需求也是我对Camera的一次探索之旅,如果你的工作中也要涉及到camera模块,但对它又比较陌生就和我一起开始学习camera模块吧。

说明一下这里主要围绕文章开头的那个需求来说的,也就是camera设置模块,毕竟我只研究了一周,对它的整体设计
还有待深入研究,这里就不误人子弟了 O(∩_∩)O哈哈~

还是看那个需求 这里分为三步去解决

1、在Picture Size中添加需要的所以像素;

2、隐藏Preview Size;

3、添加各个像素选中后切换比例的功能

但是 首先呢 我们还是要对Camera有个基本的认识看看系统Camera的整体构架(虽然今天只是了解一小部分但是框架还是要了解一点点滴)

Camera根据Android 架构从上至下可分为

1)Applications: 最上层的应用,编译后生成Camera  APK;

2)Application Framework: 主要为Applications提供API;

3)JNI: 使Application Framework和Libraries可交互;

4)Libraries: 包括Camera Framework和Camera Service(camera service和camera client);

5)HAL: 硬件抽象层, 用来链接driver和 Camera Service;

6)Kernel: image sensor driver的实作.

在来一张图 是山寨之王MTK提供的:

这个是MTK对camera进行了一下定制 他们主要对HAL和Kernel层着两层进行了比较大的改动

好了就大致提一下,如果全部都搞通了你就很niubility了。

我们还是看应用层的东东吧

这里就是整个界面的上有用到的控件了,camera的设计只有一个activity叫CameraActivity当然看到CameraLauncher的话也是CameraActivity,CameraLauncher只是CameraActivity的别名。

好了看了上面这么多高大上的东东,我们要研究的呢只是 这一小块,而且还不会全部都看

开始我们也需要对Setting的流程有一个了解 看上图可以知道SettingManager主要就是设置模块的管理类具体的话大家有时间可以点进去看下,这里从点击这个按钮开始

 public void onClick(View view) {
        if (view == mIndicator) {
            if (!mShowingContainer) {
                showSetting();
            } else {
                collapse(true);
            }
        }
    }

它会去调用showSetting() 然后一路调用到initializeSettings 开始布局设置的界面,至于其中每项显示的内容是从xml文件的camera_preferences.xml中获取,而camera_preferences.xml的解析需要从CameraDeviceCtrl中开始跟 ,最后解析的数据会保存到SettingItem类中,具体流程的话需要大家去跟一下,我其实也没太怎么跟,领导天天在屁股后面问搞好了没,这感觉你懂的。

如果你跟过了上面的显示流程(不跟也没什么关系),我们来看下关于Picture Size 和preview Size选项中的数据来源,如果跟进camera_preferences.xml看的话 你会说 这里面不是有数据么

 <ListPreference
    camera:key="pref_camera_picturesize_key"
    camera:title="@string/pref_camera_picturesize_title"
    camera:entries="@array/pref_camera_picturesize_entries"
    camera:entryValues="@array/pref_camera_picturesize_entryvalues" />

但是有没有发现这里的数据并没有都显示在列表里面,这是为什么呢,

带着这个疑问我们通过打log发现刚进去Camera的时候有很多

这样的信息 通过字面意思可以发现一个是支持的size 一个是可使用的list,而 buildEnableList里面的就是在设置界面显示的size ,

  public static String buildEnableList(String[] list, String current) {
        String listStr = null;
        if (list != null) {
            listStr = ENABLE_LIST_HEAD + current + ENABLE_LIST_SEPERATOR;
            List<String> uniqueList = new ArrayList<String>();
            for (int i = 0, len = list.length; i < len; i++) {
                if (uniqueList.contains(list[i])) {
                    continue;
                }
                uniqueList.add(list[i]);
                if (i == (len - 1)) {
                    listStr += list[i];
                } else {
                    listStr += (list[i] + ENABLE_LIST_SEPERATOR);
                }
            }
        }
        Log.d(TAG, "buildEnableList(" + current + ") return " + listStr);
        return listStr;
    }

可以发现String[] list就是可用的列表,所以需要找到buildEnableList是谁调用的

通过跟踪buildEnableList的调用堆栈,发现是在CommonRule类中调用public void execute()来获取size的list的

   overrideValue = SettingUtils.buildEnableList(
                        resultValuesAfterFilter.toArray(values), resultValue);

当然这个方法里面有很多事情要做,辣么多的代码,我就不拷贝了 可以看出来resultValuesAfterFilter.toArray(values)就是它,我们的list, 继续跟进去

List<String> resultValues = mResults.get(index);
List<String> resultValuesAfterFilter = filterUnsupportedValue(resultValues, mResultKey);

很明朗了filterUnsupportedValue字面意思过滤掉不匹配的 所以resultValues 包括所有的尺寸

而resultValues = mResults.get(index) 继续看看mResults 是哪儿赋值的

  public void addLimitation(String condition, List<String> result, MappingFinder mappingFinder) {
        mConditions.add(condition);
        mResults.add(result);
        mMappingFinder.add(mappingFinder);
    }
 private void createRuleFromRestrictions() {

     Restriction[] restrictionArray = SettingDataBase.getRestrictions();
      ...
                    rule.addLimitation(conditionValues.get(k), resultValues, mappingFinder);
        ...
    }

当然还是打印堆栈最后发现createRuleFromRestrictions中有调用 最后追到了SettingDataBase.getRestrictions();中

public static Restriction[] getRestrictions() {
        return RESTRICTIOINS;
    }

这个是一个Restriction数组代码量好大,有条件的话最好自己去看看 我就不贴了

private static final String[] PICTURE_SIZE_4_3
private static final String[] PICTURE_SIZE_16_9

最后发现没过滤前的数据就是上面这两个数组, 我现在默认是全屏也就是16:9 所以刚进去的时候是用的PICTURE_SIZE_16_9这个数组,按我们现在的需求 只要把4:3的数据都放到这个数组里面就好了。

有没有发现对camera不了解的话这一步其实也要跟很久呢。

至此第一步合并数据算是完成了,

第二部需要把preview size给隐藏了 这个应该比较简单了方法有很多 我这里是通过

public void initialize(ArrayList<ListPreference> listItems) {
        //by linyu.li for mixture picturesize 20161215 start
        if (listItems != null) {
            for (int i = 0; i < listItems.size(); i++) {
                if (listItems.get(i) != null) {
                    if (listItems.get(i).getKey()
                            .equals("pref_camera_picturesize_ratio_key")) {
                        continue;
                    }
                }
                mListItem.add(listItems.get(i));
            }
        }
       // mListItem = listItems;
        //by linyu.li for mixture picturesize 20161215 end

        mListItemAdapter = new SettingsListAdapter();
        mSettingList.setAdapter(mListItemAdapter);
        mSettingList.setOnItemClickListener(this);
        mSettingList.setSelector(android.R.color.transparent);
        mSettingList.setOnScrollListener(this);
    }

这种方式做的

来看最后一步 切换比例

设置中点击事件的调用堆栈如上图

当时通过跟踪发现主要在SettingCtrl的

 public void onSettingChanged(String settingKey, String value) {
      ...

        onSettingChanged(parameters, currentCameraId, settingKey, value);

     ...
    }
 private void onSettingChanged(Parameters parameters, int currentCameraId, String key,
            String value) {
        ...
        //by linyu.li for mixture picturesize 20161215 start
        if (SettingConstants.KEY_PICTURE_SIZE.equals(key)) {
            String prefName0 = mContext.getPackageName() + "_preferences_" + 0;
            String prefName1 = mContext.getPackageName() + "_preferences_" + 1;
            SharedPreferences sharedPreferences0 = mContext.getSharedPreferences(prefName0, Context.MODE_PRIVATE);
            SharedPreferences.Editor editor0 = sharedPreferences0.edit();

            SharedPreferences sharedPreferences1 = mContext.getSharedPreferences(prefName1, Context.MODE_PRIVATE);
            SharedPreferences.Editor editor1 = sharedPreferences1.edit();

             int index = value.indexOf('x');
             float width = Integer.parseInt(value.substring(0, index));
             float height = Integer.parseInt(value.substring(index + 1));
             Log.i(TAG,"heightonseting === "+height+",width === "+width+"w/h = "+width/height);
             if(currentCameraId==0){
                 if(width/height==(4f/3f)){
                     editor0.putString(SettingConstants.KEY_PICTURE_RATIO, "1.3333");
                     onSettingChanged(parameters, currentCameraId, SettingConstants.KEY_PICTURE_RATIO,
                             "1.3333");
                 }else if(width/height==(16f/9f)||width/height>1.7f){
                     editor0.putString(SettingConstants.KEY_PICTURE_RATIO, "1.7778");
                     onSettingChanged(parameters, currentCameraId, SettingConstants.KEY_PICTURE_RATIO,
                             "1.7778");
                 }
             }else{
                 if(width/height==(4f/3f)){
                     editor1.putString(SettingConstants.KEY_PICTURE_RATIO, "1.3333");
                     onSettingChanged(parameters, currentCameraId, SettingConstants.KEY_PICTURE_RATIO,
                             "1.3333");
                 }else if(width/height==(16f/9f)||width/height>1.7f){
                     editor1.putString(SettingConstants.KEY_PICTURE_RATIO, "1.7778");
                     onSettingChanged(parameters, currentCameraId, SettingConstants.KEY_PICTURE_RATIO,
                             "1.7778");
                 }
             }
             editor0.apply();
             editor1.apply();

        }
        //if(!SettingConstants.KEY_PICTURE_RATIO.equals(key))
        //by linyu.li for mixture picturesize 20161215 end
        executeRule(parameters, currentCameraId, key);
    }

下面就是我添加的代码应该也好懂吧。

到这里我的这个需求就完美的解决了,可以发现这个需求其实很简单,但是还是需要对camera的设计流程有一定的了解,并且通过分析android原生的app,可以发现里面的设计思想真的很值得我们学习,就比如,executeRule(parameters, currentCameraId, key); 中当点击preview size时 会递归的再次调用onSettingChanged来切换 picture size 从而使picture size 和preview size 对应,可惜我的这个需求老板一直在催,就只是简单递归了一下,其实我觉得可以用更少的代码代替上面的那一堆的代码,待我闲时在分析吧。我要闪人了,连续一周加班到现在,当然今天是加班写博客 O(∩_∩)O哈哈~。

android 原生camera——设置模块修改的更多相关文章

  1. 修改Android 4.2.2的原生Camera引出的java.lang.UnsatisfiedLinkError: Native method not found,及解决方法

    修改Android 4.2.2的原生Camera应用,做一些定制,将Camera的包名从之前的 package com.android.* 修改成了com.zhao3546.*. 调整后,应用可以正常 ...

  2. React Native Android原生模块开发实战|教程|心得|怎样创建React Native Android原生模块

    尊重版权,未经授权不得转载 本文出自:贾鹏辉的技术博客(http://blog.csdn.net/fengyuzhengfan/article/details/54691503) 告诉大家一个好消息. ...

  3. 【转】eclipse android 设置及修改生成apk的签名文件 -- custom debug keystore

    原文网址:http://hold-on.iteye.com/blog/2064642 android eclipse 设置及修改生成apk的签名文件 1. 问题: 平时在使用eclipse进行andr ...

  4. Android 系统默认参数的修改

    转自: http://www.th7.cn/Program/Android/201505/447097.shtml 写在前面的话 一般在新项目开始之初,我们需要针对客户需求进行各种系统默认属性的配置, ...

  5. 【转】Android ROM研究---Android build system增加模块

    原文网址:http://hualang.iteye.com/blog/1141315 Android build system就是编译系统的意思 在我们需要向自己编译的源代码中增加模块的时候,需要一些 ...

  6. Android 访问权限设置

    Android开发应用程序时,有时我们要用到很多权限, 今天我就收集了一些开发时可能用到的开启权限设置. 这些权限都是在 AndroidManifest.xml设置. 设置方法 <uses-pe ...

  7. MTK6577+Android之Camera驱动

    MTK6577+Android之Camera驱动 <MTK安卓平台的Camera效果在线调试> 1.     Camera拍照相关概念 1.1  ISP isp--(Image Signa ...

  8. Android 开发权限设置中英对照说明详解

    android.permission.ACCESS_CHECKIN_PROPERTIES 允许读写访问 "properties"表在checkin数据库中,改值可以修改上传( Al ...

  9. Android原生编解码接口 MediaCodec 之——踩坑

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/gb702250823/article/d ...

随机推荐

  1. 计算机网络-TCP之三次握手/四次握手

    .概念 .特点 .背景知识补充 .三次握手 .四次握手 .其他补充 1.概念 TCP(Transmission Control Protocol,传输控制协议)是 在不可靠的IP层之上实现的可靠的数据 ...

  2. [LeetCode] Redundant Connection II 冗余的连接之二

    In this problem, a rooted tree is a directed graph such that, there is exactly one node (the root) f ...

  3. 使用Remix编译和部署以太坊智能合约

      Remix 是一個开源的 Solidity 智能合约开发环境,提供基本的编译.部署至本地或测试网络.执行合约等功能.Solidity 是 以太坊Ethereum 官方设计和支持的开发语言,专门用于 ...

  4. 【基础】EM 还是 REM?这是一个问题!

    简言 应用象EM 和 REM这种相对长度单位进行页面排版是WEB开发中的最佳实践.在页面排版中较好应用EM 和 REM,根据设备尺寸缩放显示元素的大小.这就使得组件在不同设备上都达到最佳的显示效果成为 ...

  5. scrapy下载图片到自己的目录,创建缩略图,存储入库

    环境和工具:python2.7,scrapy 实验网站:http://www.27270.com/tag/333.html  爬去所有兔女郎图片,下面的推荐需要过滤 逻辑:分析网站信息,下载图片和入库 ...

  6. .NET CORE 2.0 踩坑记录之ConfigurationManager

    在之前.net framework 中使用的ConfigurationManager还是很方便的,不过在.NET CORE 2.0中SDK默认已经不存在ConfigurationManager. 那么 ...

  7. 初学servlet之@WebServlet传参

    package app01a;import java.io.IOException;import java.io.PrintWriter;import javax.servlet.ServletCon ...

  8. [USACO12FEB]牛的IDCow IDs

    题目描述 Being a secret computer geek, Farmer John labels all of his cows with binary numbers. However, ...

  9. codeforces 868C Qualification Rounds

    Snark and Philip are preparing the problemset for the upcoming pre-qualification round for semi-quar ...

  10. 【分解爪UVA11396-二分图染色模板】

    ·Rujia:"稍加推理即可解决该题--" ·英文题,述大意:      一张无向连通图,每个点连有三条边.询问是否可以将这个图分成若干个爪子,并满足条件:①每条边只能属于一个爪子 ...