,


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


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

修改前:修改后:

不知道有没有看明白,我在简单说下,没修改前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. 使用LINGO来解决0/1背包算法问题

    1.问题说明 0/1背包问题:我们有n种物品,物品j的重量为wj,价格为pj.我们假定所有物品的重量和价格都是非负的.背包所能承受的最大重量为W.如果限定每种物品只能选择0个或1个,则问题称为0-1背 ...

  2. 0415关于通过FILEBEAT,LOGSTASH,ES,KIBNA实现数据的采集

    如何通过FILEBEAT,LOGSTASH,ES,KIBNA实现数据的采集总体参考网址:https://www.olinux.org.cn/elk/1157.html官方网址:https://www. ...

  3. Java 接口基础详解

    目录 Java接口示例 实现一个接口 接口实例 实现多个接口 方法签名重叠 接口变量 接口方法 接口默认方法 接口与继承 继承与默认方法 接口与多态性 在Java中,接口是一个抽象类型,有点类似于类, ...

  4. css 的一些知识点的整理

    css的一些标签整理   background-attachment: scroll;背景图可滚动 background-attachment: fixed; 固定背景的位置,不随着滚动条移动而移动 ...

  5. PHPCMS v9.6.0 任意文件上传漏洞分析

    引用源:http://paper.seebug.org/273/ 配置了php debug的环境,并且根据这篇文章把流程走了一遍,对phpstorm的debug熟练度+1(跟pycharm一样) 用户 ...

  6. [NOIp 2016]天天爱跑步

    Description 小C同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑步>是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏的地图 ...

  7. [Noi2016]区间

    题目描述 在数轴上有 n个闭区间 [l1,r1],[l2,r2],...,[ln,rn].现在要从中选出 m 个区间,使得这 m个区间共同包含至少一个位置.换句话说,就是使得存在一个 x,使得对于每一 ...

  8. THUWC逛街记

    1/28 这次打算去THUWC划个水,就定了1/29中午的飞机.同校有几个同学去PKUWC,求稳搭今天的飞机.中午时候听说今天飞长沙的飞机全都取消了,明天有没有也不好说( 事实证明29号有飞机:( ) ...

  9. Python的数据类型——字符串

    一.字符串的误解 计算机系统的每个内存单元都是唯一并且连续的物理地址,字符串在内存中一旦创建就被 操作系统分配一块唯一并且连续的地址.计算机系统不允许我们修改字符串中的内容,一旦我想 试图进行修改,系 ...

  10. quartzJob 例子

    KpiOfPoorQualityJob.javapackage com.eastcom_sw.inas.workorder.quartzJob.kpi; import net.sf.json.JSON ...