,


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


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

修改前:修改后:

不知道有没有看明白,我在简单说下,没修改前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. ZOJ-2913 Bus Pass---BFS进阶版

    题目链接: https://vjudge.net/problem/ZOJ-2913 题目大意: 问哪个区域到公交路线上所有区域的最大距离最小 思路: 这里要求出到底是哪个区域到某些指定区域的最大距离最 ...

  2. Bellman-Ford算法的改进---SPFA算法

    传送门: Dijkstra Bellman-Ford SPFA Floyd 1.算法思想 Bellman-Ford算法时间复杂度比较高,在于Bellman-Ford需要递推n次,每次递推需要扫描所有的 ...

  3. isinstance(obj1,class) 可以判断前者是否是后者的实例

    isinstance(obj1,class) 可以判断前者是否是后者的实例

  4. Jenkins的安装

    安装环境: 512M内存 10G硬盘空间 Java 8环境 先来创建jenkins的运行目录: mkdir /data/jenkins && cd /data/jenkins 下载je ...

  5. STL迭代器------Traits编程技法详细理解(一)

    最近在看STL源码解析的迭代器(iterators)一章,涉及到c++ Traits的编程技法,刚开始看时一头雾水,反复看了好几遍之后才理解这个东西,因此来写写在这方面的理解,如有错误,希望读者指正. ...

  6. 使用C# (.NET Core) 实现适配器模式 (Adapter Pattern) 和外观模式 (Facade Pattern)

    本文的概念内容来自深入浅出设计模式一书 现实世界中的适配器(模式) 我带着一个国标插头的笔记本电脑, 来到欧洲, 想插入到欧洲标准的墙壁插座里面, 就需要用中间这个电源适配器. 面向对象的适配器 你有 ...

  7. MVC系列 引入MVC

    1.必须的类库 system.web.Mvc system.Web.Razor system.web.webPages system.web.webpages.razor 添加方式如下图 2.MVC项 ...

  8. hash详解

    首先介绍一下hash? 事实上是一种叫做蛤丝的病毒 hash的做法: 首先设一个进制数base,并设一个模数mod 而哈希其实就是把一个数转化为一个值,这个值是base进制的,储存在哈希表中,注意一下 ...

  9. 使用Docker安装Jenkins

    Jenkins Jenkins是一个开源软件项目,是基于Java开发的一种持续集成工具,用于监控持续重复的工作,旨在提供一个开放易用的软件平台,使软件的持续集成变成可能. 环境准备 腾讯云 硬件配置: ...

  10. [LeetCode] Design In-Memory File System 设计内存文件系统

    Design an in-memory file system to simulate the following functions: ls: Given a path in string form ...