场景模式scence mode流程

参考:http://blog.csdn.net/wxzking/article/details/6225702

amera设置取景模式流程分析:

在Android平台上,设置菜单有两种方式:通过XML布局来实现和通过Menu.add方法实现。Camera系统中的菜单可以说是通过XML布局来实现的,但它的实现过程并非像一般文章里介绍的那样简单。所以,在此我就以设置取景模式的菜单为例,将Camera系统中菜单的设置流程作以简单介绍。

1、资源文件分析

在packages/apps/Camera/res/xml/有两个xml文件,分别为Camera_preferences.xml(拍照的xml文件)和Video_preferences.xml(视频录制的xml文件)。这两个文件中列举了Camera和Video Camera两种模式下的不同菜单信息。以Camera_preferences.xml为例,其中关于Scence mode的菜单项信息为:

<PreferenceGroup
。。。
    <IconListPreference
            camera:key="pref_camera_scenemode_key"
            camera:defaultValue="@string/pref_camera_scenemode_default"
            camera:title="@string/pref_camera_scenemode_title"
            camera:singleIcon="@drawable/ic_scn_holo_light"
            camera:entries="@array/pref_camera_scenemode_entries"
            camera:entryValues="@array/pref_camera_scenemode_entryvalues" />
。。。
</PreferenceGroup>

问题:什么是PreferenceGroup和IconListPreference

pref_camera_scenemode_title的定义在packages/apps/Camera/res/values/strings.xml中,其中有如下的定义:
    <!-- Settings screen, Select Scene mode -->
    <string name="pref_camera_scenemode_title">Scene mode</string>
这个是相机设置上的标题,点击这个控件就会选择相应的取景模式

pref_camera_scenemode_entries定义在
packages/apps/Camera/res/values/arrays.xml中,其中有如下的定义:
    <!-- Camera Preferences Scene Mode dialog box entries -->
    <string-array name="pref_camera_scenemode_entries" translatable="false">
        <item>@string/pref_camera_scenemode_entry_auto</item>
        <item>@string/pref_camera_scenemode_entry_landscape</item>
        <item>@string/pref_camera_scenemode_entry_portrait</item>
        <item>@string/pref_camera_scenemode_entry_night</item>
        <item>@string/pref_camera_scenemode_entry_night_portrait</item>
        <item>@string/pref_camera_scenemode_entry_action</item>
        <item>@string/pref_camera_scenemode_entry_theatre</item>
        <item>@string/pref_camera_scenemode_entry_beach</item>
        <item>@string/pref_camera_scenemode_entry_snow</item>
        <item>@string/pref_camera_scenemode_entry_sunset</item>
        <item>@string/pref_camera_scenemode_entry_steadyphoto</item>
        <item>@string/pref_camera_scenemode_entry_fireworks</item>
        <item>@string/pref_camera_scenemode_entry_sports</item>
        <item>@string/pref_camera_scenemode_entry_party</item>
        <item>@string/pref_camera_scenemode_entry_candlelight</item>
    </string-array>
由上面这些定义,我们可以看出,Android的Camera应用程序支持auto到candlelight的取景模式。但是硬件并非都支持这些模式的。所以最终的菜单中只会显示这几种模式当中中底层硬件所支持的,如果硬件支持的取景模式与其中任何一种都不匹配,则不会显示出“Scene mode”的菜单。

2、菜单的创建

在文件Packages\apps\legacycamera\src\com\android\camera\Camera.java中,函数onCreateOptionsMenu()用来创建Camera系统的菜单。其具体定义如下:
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);

        if (mIsImageCaptureIntent) {
            // No options menu for attach mode.
            return false;
        } else {
            addBaseMenuItems(menu);
        }
        return true;
    }
在非Video Camera模式下,mIsImageCaptureIntent为true,此处将不做任何处理。当mIsImageCaptureIntent为false时,即Video Camera模式下,将调用函数addBaseMenuItems()来创建Video Camera的菜单。取景模式的菜单不会出现在Video Camera模式下,所以就不对addBaseMenuItems()函数分析了。

在Camera.java文件中定义了类MainHandler,它里面只有一个成员函数handleMessage(),它用来处理Camera应用程序中的message。
    private class MainHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case CLEAR_SCREEN_DELAY: {
                    getWindow().clearFlags(
                            WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
                    break;
                }

                case FIRST_TIME_INIT: {
                    initializeFirstTime();
                    break;
                }

                case SET_CAMERA_PARAMETERS_WHEN_IDLE: {
                    setCameraParametersWhenIdle(0);
                    break;
                }

                case CHECK_DISPLAY_ROTATION: {
                    // Set the display orientation if display rotation has changed.
                    // Sometimes this happens when the device is held upside
                    // down and camera app is opened. Rotation animation will
                    // take some time and the rotation value we have got may be
                    // wrong. Framework does not have a callback for this now.
                    if (Util.getDisplayRotation(Camera.this) != mDisplayRotation) {
                        setDisplayOrientation();
                    }
                    if (SystemClock.uptimeMillis() - mOnResumeTime < 5000) {
                        mHandler.sendEmptyMessageDelayed(CHECK_DISPLAY_ROTATION, 100);
                    }
                    break;
                }

                case SHOW_TAP_TO_FOCUS_TOAST: {
                    showTapToFocusToast();
                    break;
                }

                case UPDATE_THUMBNAIL: {
                    mImageSaver.updateThumbnail();
                    break;
                }
            }
        }
    }
Message FIRST_TIME_INIT应该在类Camera初始化时就会被处理,我是这样猜的,只是还没有找到具体的code。
initializeFirstTime()的实现如下所示:
。。。
        mHeadUpDisplay = new CameraHeadUpDisplay(this);
        mHeadUpDisplay.setListener(new MyHeadUpDisplayListener());
        initializeHeadUpDisplay();
。。。


initializeHeadUpDisplay
    CameraSettings settings = new CameraSettings(this, mInitialParams,CameraHolder.instance().getCameraInfo());
    mHeadUpDisplay.initialize(this,settings.getPreferenceGroup(R.xml.camera_preferences),getZoomRatios(), mOrientationCompensation);

语句mHeadUpDisplay.initialize(this,settings.getPreferenceGroup(R.xml.camera_preferences),getZoomRatios(), mOrientationCompensation);中的R.xml.camera_preferences指的就是camera_preference.xml资源文件。
接下来我们将对settings.getPreferenceGroup(),mHeadUpDisplay.initialize()和MyHeadUpDisplayListener做以介绍。

1.settings.getPreferenceGroup()
函数settings.getPreferenceGroup()定义在文件Packages/apps/camera/src/com/android/camera/CameraSetting.java中。其具体定义为:
    public PreferenceGroup getPreferenceGroup(int preferenceRes) {
        PreferenceInflater inflater = new PreferenceInflater(mContext);
        PreferenceGroup group =
                (PreferenceGroup) inflater.inflate(preferenceRes);
        if (mParameters != null) initPreference(group);
        return group;
    }
函数inflater.inflate(preferenceRes)将camera_preference.xml文件中的菜单信息存储到PreferenceGroup中。接着函数initPreference()对这些信息做了处理,其定义为:
    private void initPreference(PreferenceGroup group) {
。。。
        ListPreference sceneMode = group.findPreference(KEY_SCENE_MODE);
。。。
        if (sceneMode != null) {
            filterUnsupportedOptions(group,
                    sceneMode, mParameters.getSupportedSceneModes());
        }
。。。
}

其中,宏定义 KEY_SCENE_MODE定义在文件Packages/apps/camera/src/com/android/camera/CameraSetting.java中,具体定义为:
    public static final String KEY_SCENE_MODE = "pref_camera_scenemode_key";
该值与camera_preference.xml中的KEY值匹配。

ListPreference sceneMode = group.findPreference(KEY_SCENE_MODE);将Scence mode信息存储在了结构体ListPreference sceneMode中。

语句
        if (sceneMode != null) {
            filterUnsupportedOptions(group,
                    sceneMode, mParameters.getSupportedSceneModes());
        }
mParameters.getSupportedSceneModes()获取了硬件Camera所支持的场景模式信息。
该信息在我目前所拿的机器在Camera HAL层中实现。在函数initDefaultParameters()中设置了硬件所支持的picture大小。路径:broadcom\rhea_hawaii\v4l2_camerahal\brcm\CameraHAL.cpp
CODE如下:
status_t CameraHAL::initDefaultParameters()
{
...//这个需要进一步分析源码。下次分析。
    str8 = pCamDev->querySceneModes(defScene);
    if (str8.length() > 0) {
        ALOGI("initDefaultParameters(): camera device supports %s scene modes", str8.string());
        mParameters.set(CameraParameters::KEY_SUPPORTED_SCENE_MODES, str8.string());
        mParameters.set(CameraParameters::KEY_SCENE_MODE, defScene.string());
    }
    else
        ALOGI("initDefaultParameters(): camera deevice does not support any scene mode");
...
}

函数 filterUnsupportedOptions() 会将Camera应用层和硬件支持的Scence mode中两者匹配的大小存储在group中。
这样settings.getPreferenceGroup()获取的group就是最终显示到Scence mode选项上的模式。

2.mHeadUpDisplay.initialize()
函数mHeadUpDisplay.initialize()定义在文件
broadcom_test_apps\brcmcamera\src\com\broadcom\camera\ui\CameraHeadUpDisplay.java 中,其具体定义为:
    public void initialize(Context context, PreferenceGroup group,
            float[] initialZoomRatios, int initialOrientation) {
        mInitialZoomRatios = initialZoomRatios;
        mInitialOrientation = initialOrientation;
        super.initialize(context, group);//调用父类的initialize
    }

    public void initialize(Context context, PreferenceGroup preferenceGroup) {
        mPreferenceGroup = preferenceGroup;
        mSharedPrefs = ComboPreferences.get(context);
        mPopupWindow = null;
        clearComponents();
        initializeIndicatorBar(context, preferenceGroup);//将group添加到菜单中。实现如下
        requestLayout();
    }

    protected void initializeIndicatorBar(
            Context context, PreferenceGroup group) {
        super.initializeIndicatorBar(context, group);

        ListPreference[] prefs = getListPreferences(group,
                CameraSettings.KEY_FOCUS_MODE,
                CameraSettings.KEY_EXPOSURE,
                CameraSettings.KEY_SCENE_MODE,
                CameraSettings.KEY_PICTURE_SIZE,
                CameraSettings.KEY_JPEG_QUALITY,
                CameraSettings.KEY_COLOR_EFFECT);

        mOtherSettings = new OtherSettingsIndicator(context, prefs);
        mOtherSettings.setOnRestorePreferencesClickedRunner(new Runnable() {
            public void run() {
                if (mListener != null) {
                    mListener.onRestorePreferencesClicked();
                }
            }
        });
        mIndicatorBar.addComponent(mOtherSettings);

        addIndicator(context, group, CameraSettings.KEY_WHITE_BALANCE);
        addIndicator(context, group, CameraSettings.KEY_VIDEOCAMERA_FLASH_MODE);
        addIndicator(context, group, CameraSettings.KEY_VIDEO_QUALITY);
        addIndicator(context, group, CameraSettings.KEY_CAMERA_ID);

        mIndicatorBar.setOrientation(mInitialOrientation);
    }
}
函数addComponent()将group中的Scence mode添加到了菜单中。至此,菜单的创建就告一段落。下面我们介绍一下菜单的事件。


3、菜单的监听事件MyHeadUpDisplayListener
当菜单被点击时,菜单的监听事件就会监听到该事件,并作出相应的处理。监听事件定义在文件broadcom_test_apps\brcmcamera\src\com\broadcom\camera\Camera.java
    private class MyHeadUpDisplayListener implements HeadUpDisplay.Listener {

        public void onSharedPreferencesChanged() {
            Camera.this.onSharedPreferenceChanged();
        }

        public void onRestorePreferencesClicked() {
            Camera.this.onRestorePreferencesClicked();
        }

        public void onPopupWindowVisibilityChanged(int visibility) {
        }
    }
函数onSharedPreferenceChanged()定义为:
onSharedPreferenceChanged
    setCameraParametersWhenIdle(UPDATE_PARAM_PREFERENCE);
        setCameraParameters
            updateCameraParametersPreference

private void updateCameraParametersPreference() {
....
        // Since change scene mode may change supported values,
        // Set scene mode first,
        mSceneMode = mPreferences.getString(
                CameraSettings.KEY_SCENE_MODE,
                getString(R.string.pref_camera_scenemode_default));
        if (isSupported(mSceneMode, mParameters.getSupportedSceneModes())) {
            if (!mParameters.getSceneMode().equals(mSceneMode)) {
                mParameters.setSceneMode(mSceneMode);
                mCameraDevice.setParameters(mParameters);

                // Setting scene mode will change the settings of flash mode,
                // white balance, and focus mode. Here we read back the
                // parameters, so we can know those settings.
                mParameters = mCameraDevice.getParameters();
            }
        } else {
            mSceneMode = mParameters.getSceneMode();
            if (mSceneMode == null) {
                mSceneMode = Parameters.SCENE_MODE_AUTO;
            }
        }
...
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值