,


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


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

修改前:修改后:

不知道有没有看明白,我在简单说下,没修改前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. angularjs购物车练习

    本文是一个简单的购物车练习,功能包括增加.减少某商品的数量,从而影响该商品的购买总价以及所有商品的购买总价:从购物车内移除一项商品:清空购物车. 页面效果如图: 若使用js或jQuery来实现这个页面 ...

  2. phantomjs 开发爬虫框架

    函数 page.childframescount page.childframesname page.close page.currentframename page.deletelater page ...

  3. [LeetCode] Pyramid Transition Matrix 金字塔转变矩阵

    We are stacking blocks to form a pyramid. Each block has a color which is a one letter string, like ...

  4. java面试2(java技术栈和Hollis面试内容分享)

    1.什么是java虚拟机? java虚拟机(JVM)是一个可执行java字节码的虚拟机进程,java源文件被编译成能被java虚拟机可执行的字节码文件. 2.什么是平台无关性,java是如何做到平台无 ...

  5. Event 发布与订阅(一)

    前言 主要讲的是发布与订阅在Event中的一个简单实现用来加深理解. C #中的事件(Event)的理解: 事件具有以下属性:(From Events) 发行者确定何时引发事件:订户确定对事件作出何种 ...

  6. [NOI2009]变换序列

    Description Input Output Sample Input 5 1 1 2 2 1 Sample Output 1 2 4 0 3 HINT 30%的数据中N≤50: 60%的数据中N ...

  7. 计蒜客NOIP模拟赛4 D1T1 小X的质数

    小 X 是一位热爱数学的男孩子,在茫茫的数字中,他对质数更有一种独特的情感.小 X 认为,质数是一切自然数起源的地方. 在小 X 的认知里,质数是除了本身和 1以外,没有其他因数的数字. 但由于小 X ...

  8. [HNOI2008]玩具装箱TOY

    题目描述 P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京.他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再放到一种特殊的一维容器中.P教授有编号为1...N的N件玩具, ...

  9. 以独立的语句将new对象置入智能指针

    以独立的语句将newed对象置入智能指针: processWidget(std::tr1::share_ptr<Widget>(new Widget) , priority()); 我们在 ...

  10. 【NOIP 2017】逛公园

    Description 策策同学特别喜欢逛公园.公园可以看成一张N个点M条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口,N号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要 ...