Android R上展讯平台CameraAPP的Settings设置项管理

CameraAPP的设置项管理是CameraAPP中客户需求比较偏重的一部分,一般客户要添加新功能,都需要提供一个设置项开关出来。今天我们来整理下设置项的逻辑,先来看下设置项的截图:
在这里插入图片描述
我们知道,不同Module下设置项的个数和种类也是不同的,现在就开始我们的代码追踪之旅吧。

DataModuleBasic系列是管理设置项的基类,在它内部定义了几个常用的内部类。
DataSPAndPath
关键成员变量:String mPath
int position
SharedPreferences mSharePreferences
根据名称就可以猜到,此类是与SharePreference,保存数据相关的。
DataStorageStruct
关键成员变量:String mKey;
int mStorePosition;
String mDefaultValue;
CharSequence[] mEntryValues;
CharSequence[] mEntries;
String mRestorageValue;
数据存储结构类,此类是与设置项的xml配置是一致的,用来装从xml中读取的设置项数据。

还有一个不在DataModuleBasic中定义的类 :
DataStructSetting
关键成员变量:String mCategory;//photo/video/camera
boolean mIsFront; // front/back camera
int mMode;
int mCameraID;
此类是用来描述一个Module的信息

回到DataModuleBasic中,其关键方法initializeData,此方法通过DreamSettingUtil来从xml中获取配置的设置项数据
1,DreamSettingUtil .getSupportDataResourceID

public void initializeData(DataStructSetting dataSetting) {
        mDataSetting = dataSetting;

        // generate support configuration data resourceID
        int supportdataResourceID = DreamSettingUtil
                .getSupportDataResourceID(dataSetting);

        // generate support data map
        if (supportdataResourceID != -1) {
            Log.d(TAG, "initializeData -- generateSupportDataList supportdataResourceID:" + supportdataResourceID);
            generateSupportDataList(supportdataResourceID);
        }

        // generate mutex data resourceID
        int mutexDataResourceID = DreamSettingUtil
                .getMutexDataResourceID(dataSetting);

        // generate mutex data map
        if (mutexDataResourceID != -1) {
            generateMutexDataList(mutexDataResourceID);
        }

        // initialize show item resourceID
        int showItemSetID = DreamSettingUtil
                .getPreferenceUIConfigureID(dataSetting);

        // generate show item data
        if (showItemSetID != -1) {
            generateShowItemList(showItemSetID);
        }
        // setEntryAndEntryValues for list
        fillEntriesAndSummaries();
    }

流程转到 DreamSettingUtil 中:我们以后摄photo模式为例追踪代码,其他模式是类似的
在这里插入图片描述
getSupportDataBackPhoto中就会根据传过来的不同Module来读取对应的xml配置的array数组数据,这也是我们会看到在不同Module下,设置项不一样的原因。

private static int getSupportDataBackPhoto(int mode , int id) {
        int resourceID = id;
        switch (mode) {
            case DataConfig.PhotoModeType.PHOTO_MODE_BACK_AUTO:
                resourceID = R.array.photo_back_auto_setting;
                break;
            case DataConfig.PhotoModeType.PHOTO_MODE_BACK_MANUAL:
                resourceID = R.array.photo_back_manual_setting;
                break;
            case DataConfig.PhotoModeType.PHOTO_MODE_BACK_CONTINUE_PICTURE:
                resourceID = R.array.photo_back_continue_pic_setting;
                break;
            case DataConfig.PhotoModeType.PHOTO_MODE_BACK_PANORAMA:
                resourceID = R.array.photo_back_panorama_setting;
                break;

            case DataConfig.PhotoModeType.PHOTO_MODE_BACK_SCENE:
                resourceID = R.array.photo_back_scene_setting;
                break;

            case DataConfig.PhotoModeType.PHOTO_MODE_BACK_UCAM_FILTER:
                resourceID = getResourceIdBackUcamFilter(resourceID);
                break;
            case DataConfig.PhotoModeType.PHOTO_MODE_BACK_INTENT_CAPTURE:
                resourceID = R.array.photo_back_mode_intent_capture_setting;
                break;
            case DataConfig.PhotoModeType.PHOTO_MODE_BACK_QRCODE:
                resourceID = R.array.photo_back_mode_qrcode_setting;
                break;
            case DataConfig.PhotoModeType.PHOTO_MODE_BACK_SOUND_PICTURE:
                resourceID = R.array.photo_back_mode_sound_setting;
                break;
            case DataConfig.PhotoModeType.PHOTO_MODE_BACK_PIP_VIV:
            case DataConfig.PhotoModeType.PHOTO_MODE_BACK_REFOCUS:
                resourceID = getResourceIdBackRefocus(resourceID);
                break;
            case DataConfig.PhotoModeType.PHOTO_MODE_BACK_3DNR:
                resourceID = R.array.photo_back_3dnr_setting;
                break;
            case DataConfig.PhotoModeType.PHOTO_MODE_BACK_3DNR_PRO:
                resourceID = R.array.photo_back_3dnr_pro_setting;
                break;
            case DataConfig.PhotoModeType.PHOTO_MODE_BACK_ULTRA_WIDE_ANGLE:
                resourceID = R.array.photo_back_ultra_wide_angle_setting;
                break;
            case DataConfig.PhotoModeType.PHOTO_MODE_BACK_PORTRAIT:
                resourceID = R.array.photo_back_portrait_setting;
                break;
            case DataConfig.PhotoModeType.PHOTO_MODE_BACK_HIGH_RESOLUTION:
                resourceID = R.array.photo_back_high_resolution_photo_setting;
                break;
            case DataConfig.PhotoModeType.PHOTO_MODE_BACK_IR:
                resourceID = R.array.photo_back_ir_photo_setting;
                break;
            case DataConfig.PhotoModeType.PHOTO_MODE_BACK_FOCUS_LENGTH_FUSION:
                resourceID = R.array.photo_back_focus_length_fusion_setting;
                break;
            case DataConfig.PhotoModeType.PHOTO_MODE_BACK_MACRO:
                resourceID = R.array.photo_back_macro_photo_setting;
                break;
            case DataConfig.PhotoModeType.PHOTO_MODE_BACK_PORTRAIT_BACKGROUND_REPLACEMENT:
                resourceID = R.array.photo_back_mode_protrait_background_replacement_photo_setting;
                break;
            default:
                break;
        }
        return resourceID;
    }

以后摄photo模式为例,来看下 R.array.photo_back_auto_setting内容

<integer-array name="photo_back_auto_setting">
        <item>@array/pref_camera_picturesize_back_key_array</item>
        <item>@array/pref_camera_jpeg_quality_key_array</item>
        <item>@array/pref_camera_composition_line_key_array</item>
        <item>@array/pref_camera_face_detect_key_array</item>
        <item>@array/pref_camera_antibanding_key_array</item>
        <item>@array/pref_auto3dnr_param_key_array</item>
        <item>@array/pref_camera_ai_scene_detect_key_array</item>
        <item>@array/pref_ai_detect_smile_key_array</item>
        <item>@array/pref_ai_detect_face_attributes_key_array</item>
        <item>@array/pref_camera_hdr_normal_pic_key_array</item>
        <item>@array/pref_auto_add_logowatermark_key_array</item>
        <item>@array/pref_auto_add_timewatermark_key_array</item>
        <item>@array/pref_add_level_key_array</item>
        <item>@array/pref_camera_touching_photograph_key_array</item>
        <item>@array/pref_camera_time_stamp_key_array</item>
        <item>@array/pref_camera_zsl_key_array</item>
        <item>@array/pref_auto_tracking_key_array</item>
        <item>@array/pref_camera_back_beauty_entered_key_array</item>
        <item>@array/pref_make_up_display_key_array</item>
        <item>@array/pref_camera_ai_beauty_entered_key_back_array</item>
        <item>@array/pref_camera_flashmode_key_array</item>
        <item>@array/pref_camera_countdown_duration_key_array</item>
        <item>@array/pref_camera_refocus_key_array</item>
        <item>@array/pref_camera_hdr_key_array</item>
        <item>@array/pref_eois_dc_back_key_array</item>
        <item>@array/pref_camera_metering_key_array</item>
        <item>@array/pref_camera_zoom_enable_true_key_array</item>
        <item>@array/pref_camera_ae_lock_key_array</item>
        <item>@array/pref_camera_ultra_wide_angle_key_array</item>
        <item>@array/pref_camera_montionphoto_key_array</item>
    </integer-array>

我们看到photo_back_auto_setting数组的内部每一项又都是数组,以pref_auto_add_logowatermark_key_array为例看下

<integer-array name="pref_auto_add_logowatermark_key_array">
        <item>@string/pref_auto_add_logowatermark_key</item>
        <item>@integer/storage_position_category_bf</item>
        <item>@string/preference_switch_item_default_value_false</item>
        <item>@array/preference_camera_switch_entryvalues</item>
        <item>@array/preference_camera_switch_entryvalues</item>
</integer-array>

logoWaterMark的设置项包含:key、position、defaultValue、entry、entryValues值。
还记得上面在DataModuleBasic中的内部类DataStorageStruct吗,没错,每个设置项的配置与DataStorageStruct的结构是一致的,这在后面会有用处的。

现在我们回到DreamSettingUtil.getSupportDataResourceID,它是返回对应Module下的设置项数组,对于后摄Photo模式就是返回R.array.photo_back_auto_setting,然后再返回到DataModuleBasic的initializeData方法中。

2,generateSupportDataList(supportdataResourceID);

private void generateSupportDataList(int resourceID) {
        synchronized (mLock) {
            Log.e(TAG, "======== support data list start ========== resourceID:" + resourceID);
             TypedArray types = mContext.getResources().obtainTypedArray(resourceID);
             mSupportDataMap.clear();
             if (types != null) {
                 for (int i = 0; i < types.length(); i++) {
                     TypedArray type = mContext.getResources().obtainTypedArray(
                             types.getResourceId(i, -1));

                     if (type != null) {
                         DataStorageStruct data = new DataStorageStruct(type);
                         mSupportDataMap.put(data.mKey, data);
                         data.mRestorageValue = getString(data.mKey);
                         Log.e(TAG, data.toString());
                         type.recycle();
                     }
                 }
             }
             types.recycle();
             Log.e(TAG, "===== support data list end =====");
        }
    }

根据上一步返回的array数组,循环遍历,将array数据填充到DataStorageStruct类型的类中,然后构建一个以设置项key值为key,设置项数据填充的DataStorageStruct对象为value的map,得到mSupportDataMap数据。

到此得到了一个关键map,mSupportDataMap,在后续代码追踪中,我们会经常看到这个map的出现,现在我们要记住,这个map装的就是xml中配置的所有设置项的数据。

在回到 DataModuleBasic的initializeData方法中,在完成了generateSupportDataList后,后续其又generateMutexDataList、generateShowItemList。流程与generateSupportDataList是类似的,结果都是在java中通过一定的数据结构保存相应xml配置的数据。
其中的generateShowItemList需要注意下,我们来看下后摄Photo模式的xml配置。

<integer-array name="photo_back_mode_auto_setting_display">
        <item>@string/pref_camera_picturesize_back_key</item>
        <item>@string/pref_camera_jpeg_quality_key</item>
        <item>@string/pref_camera_composition_line_key</item>
        <item>@string/pref_ai_detect_smile_key</item>
        <item>@string/pref_ai_detect_face_attributes_key</item>
        <item>@string/pref_auto_add_logowatermark_key</item>
        <item>@string/pref_add_level_key</item>
        <item>@string/pref_auto_add_timewatermark_key</item>
        <item>@string/pref_camera_antibanding_key</item>
        <item>@string/pref_auto3dnr_param_key</item>
        <item>@string/pref_camera_ai_scene_detect_key</item>
        <item>@string/pref_camera_hdr_normal_pic_key</item>
        <item>@string/pref_camera_touching_photograph_key</item>
        <item>@string/pref_camera_time_stamp_key</item>
        <item>@string/pref_camera_flashmode_key</item>
        <item>@string/pref_camera_countdown_duration_key</item>
        <item>@string/pref_camera_refocus_key</item>
        <item>@string/pref_camera_hdr_key</item>
        <item>@string/pref_eois_dc_back_key</item>
        <item>@string/pre_ae_lock_key</item>
        <item>@string/pref_camera_ultra_wide_angle_key</item>
        <item>@string/pref_auto_tracking_key</item>
        <item>@string/pref_key_montionphoto</item>
    </integer-array>

这个数据的内部项不在是数组了,而是简单的String,并且如果你细心的看,这些String就是我们上面看到的 R.array.photo_back_auto_setting数组中每个设置项(也为array)的key值。并且这两个数组的名称也很有关联:
R.array.photo_back_auto_setting 和 R.array.photo_back_mode_auto_setting_display。后面随着我们继续的追踪,就会发现这两个数组之间确实是有关联的。

上面介绍的是DataModuleBasic将xml内容转换成map集合了,那么有了集合,就少不了对集合的数据操作,也就是用户更改这些设置项后,DataModuleBasic还要负责将用户更改的数据更新到集合并且保存下来,以便用户退出后,下次再进来,用户的设置仍然在。
数据的持久化保存就与前面介绍的内部类DataSPAndPath有关了,因为这里面有SharePreference。所以在DataModuleBasic中提供了一些set和get数据的方法:

public abstract boolean isSet(int position, String key);

public abstract void set(int position, String key, String value);

public abstract String getString(int position, String key,String defaultValue);

DataModuleBasic并没有实现这些方法,其子类DataModuleInterfacePV实现了。这里在补充一个注意点:Camera中通过SharePreference保存数据,有position的概念,不同的position对应不同的SharePreference文件,即设置项的数据是保存在不同的SP文件中的。DataConfig中定义了如下Position:

public static final int POSITION_ERROR = 0x10000000;
public static final int POSITION_CAMERA_PUBLIC = 0x00000010;
public static final int POSITION_CATEGORY = 0x00000001;
public static final int POSITION_CATEGORY_BF = 0x00000002;
public static final int POSITION_CATEGORY_BF_MODULE = 0x00000004;
public static final int POSITION_CATEGORY_BF_MODULE_ID = 0x00000008;

继续看下 DataModuleInterfacePV中set、get的实现:

private DataSPAndPath getStorageHandler(int position) {
        switch (position) {
        case SettingStoragePosition.POSITION_CATEGORY:
            return mCategorySPB;
        case SettingStoragePosition.POSITION_CATEGORY_BF:
            return mCategoryFBSPB;
        case SettingStoragePosition.POSITION_CATEGORY_BF_MODULE:
            return mCategoryFBModuleSPB;
        case SettingStoragePosition.POSITION_CATEGORY_BF_MODULE_ID:
            return mCategoryFBModuleCIDSPB;
        default:
            return null;
        }
    }

    @Override
    public boolean isSet(int position, String key) {
        DataSPAndPath spb = getStorageHandler(position);
        return ((spb != null) ? spb.isSet(key) : false); // Bug 1159255 (NULL_RETURNS)
    }

    @Override
    public void set(int position, String key, String value) {
        DataSPAndPath spb = getStorageHandler(position);
        if (spb != null) // Bug 1159255 (NULL_RETURNS)
            spb.set(key, value);
    }

    @Override
    public String getString(int position, String key, String defaultValue) {
        DataSPAndPath spb = getStorageHandler(position);
        return spb == null ? defaultValue : spb.getString(key, defaultValue);
    }

DataModuleInterfacePV从名称上看,是一个接口Public的实现,应该还有类在继续继承的。
搜索发现,确实有 DataModulePhoto、DataModuleVideo extends DataModuleInterfacePV。
DataModulePhoto和DataModuleVideo从名称就可以看出来,一个是负责管理photo的,一个是负责管理video的。
以Photo的为例,简单看下其内容

@Override
    protected void setMutex(String key, Object newValue, Set<String> keyList) {
        String entryValue = getString(key);

        switch (key) {
            case Keys.KEY_EXPOSURE_SHUTTERTIME:
                setMutexShutterTime(key, entryValue, keyList);
                break;
        case Keys.KEY_AUTO_3DNR_PARAMETER:
            setMutexAuto3Dnr(key, entryValue, keyList);
            break;
        case Keys.KEY_CAMERA_FACE_DATECT:
            setMutexAIDetect(key, entryValue, keyList);
            break;
        case Keys.KEY_CAMERA_COLOR_EFFECT:
            setMutexColorEffect(key, entryValue, keyList);
            break;
        case Keys.KEY_FLASH_MODE:
            setMutexFlash(key, entryValue, keyList);
            break;
        case Keys.KEY_CAMERA_HDR:
            setMutexHDR(key, entryValue, keyList);
            break;
        //case Keys.KEY_CAMERA_HDR_NORMAL_PIC:
            //setMutexNormalHDR(key, entryValue, keyList);
            //break;
        case Keys.KEY_SCENE_MODE:
            setMutexSceneMode(key, entryValue, keyList);
            break;
        case Keys.KEY_CAMERA_BEAUTY_ENTERED:
            setMutexBeauty(key, entryValue, keyList);
            break;
        case Keys.KEY_CAMERA_AI_BEAUTY_ENTERED:
            setMutexAiBeauty(key, entryValue, keyList);
            break;
        case Keys.KEY_CAMERA_ZSL:
            setMutexZSL(key, entryValue, keyList);
            break;
        case Keys.KEY_CAMERA_FILTER_TYPE:
            setMutexFilterType(key, entryValue, keyList);
            break;
        case Keys.KEY_CAMERA_PORTRAITBACKGROUNDREPLACEMENT_TYPE:
            setMutexPortraitBackgroundPeplacementType(key, entryValue, keyList);
            break;
        case Keys.KEY_DREAM_FLASH_GIF_PHOTO_MODE:
            setMutexGifPhotoFlash(key, entryValue, keyList);
            break;
        case Keys.KEY_CAMERA_AI_SCENE_DATECT:
            setMutexAISceneDetect(key, entryValue, keyList);
            break;
        case Keys.KEY_CAMERA_TOUCHING_PHOTOGRAPH:
             setMutexTouchingPhoto(key, entryValue, keyList);
             break;
        case Keys.KEY_AUTO_TRACKING:
            setMutexAutoTracking(key, entryValue, keyList);
            break;
        case Keys.KEY_MAKE_UP_DISPLAY:
            setMutexMakeUpDisplay(key, entryValue, keyList);
            break;
        case Keys.KEY_LIGHT_PORTIAIT_DISPLAY:
            setMutexLightPortraitDisplay(key, entryValue, keyList);
            break;
        case Keys.KEY_AE_LOCK:
            setMutexAELock(key, entryValue, keyList);
	    break;
        case Keys.KEY_LIGHT_PORTIAIT:
            if(CameraUtil.isPortraitAndRefocusMutex()){
                setMutexLightPortrait(key, entryValue, keyList);
            }
            break;
        case Keys.KEY_PORTRAIT_REFOCUS_KEY:
            if(CameraUtil.isPortraitAndRefocusMutex()){
                setMutexPortraitRefocus(key, entryValue, keyList);
            }
            break;

        /* @} */
        default:
            break;
        }

    }

主要是在处理mutex,互斥的操作。
至此,DataModuleBasic的流程就介绍结束了。这块主要是管理设置项数据,那么设置项view的处理逻辑呢?

View直接相关的是 DreamUIPreferenceSettingLayout 和 DreamUIPreferenceSettingFragment,加载的xml文件是dream_camera_preferences,xml文件中分为三类:
preference_key_category_camera_root —》DreamUISettingPartCamera
preference_key_category_photo_root —》DreamUISettingPartPhoto
preference_key_category_video_root —》DreamUISettingPartVideo
这三个自定义view均是继承的DreamUISettingPartBasic,又是basic类,basic类的关键代码逻辑是:

    public void changContent() {

        //mDataModule.addListener(this);

        updatePreItemAccordingConfig(this);

        // update UI display according properties config
        updatePreItemsAccordingProperties();

        //update UI display according currentModule settings
        updatePreItemsAccordingSettings(this);

        // setEntryAndEntryValues for list
        fillEntriesAndSummaries(this);

        // set data for each preference
        initializeData(this);

    }

    private void updatePreItemsAccordingSettings(PreferenceGroup group){//移除不在 mSupportDataMap 中的设置项
        ArrayList<String> keyListui = getAllPreKeyList(group);
        Set<String> keySetsettings = mDataModule.getSupportSettingKeys();
        for(int i = 0; i < keyListui.size(); i++){
            if(!keySetsettings.contains(keyListui.get(i))){
                Preference pref = group.findPreference(keyListui.get(i));
                group.removePreference(pref);
            }
        }
    }

    private void updatePreItemAccordingConfig(PreferenceGroup group) {//移除不在 mShowItemsSet 中的设置项
        ArrayList<String> keyList = getAllPreKeyList(group);
        keyList.removeAll(mDataModule.getShowItemsSet());

        for (int i = 0; i < keyList.size(); i++) {
            Log.e(TAG, "remove key = " + keyList.get(i));
            Preference pref = group.findPreference(keyList.get(i));
            if (pref != null) {
                group.removePreference(pref);
            }
        }
    }

注释写的很清楚,获取我们前面介绍的 mDataModuleBasic对象,根据其维护的map数据来确定设置项layout最终应该显示出来的设置项。
注意:这里用到了mShowItemsSet ,就是我们前面说的R.array.photo_back_auto_setting 和 R.array.photo_back_mode_auto_setting_display 后面这个数组,这样看来一个设置项要显示出来,不仅要在R.array.photo_back_auto_setting 中配置,还要在 R.array.photo_back_mode_auto_setting_display里面也配置。

DreamUISettingPartBasic系列,我们以DreamUISettingPartPhoto为例,来看下内容:

@Override
    protected void updatePreItemsAccordingProperties() {

        // update visibility of picturesize
        updateVisibilityPictureSizes();

        // update visibility of EIOS
        updateVisibilityEOIS();

        // update visibility of mirror
        updateVisibilityMirror();

        updateVisibilityTouchPhotograph();

        updateVisibilityAIDetect();
        updateVisibilitySensorSelfShot();
        updateVisibilityNormalHdr();
        updateVisibilityAntiFlicker();
        updateVisibilityAiSceneDetect();
        updateVisibilityHDR();
        updateVisibilityAutoTracking();
        updateVisibilityFaceAttributeDetect();
        updateVisibilityFDR();
    }

    private void updateVisibilityAutoTracking() {
        if (!CameraUtil.isAutoChasingSupport()) {
            recursiveDelete(this, findPreference(Keys.KEY_AUTO_TRACKING));
        }
    }

    private void updateVisibilityHDR() {
        if(!CameraUtil.isIsMotionPhotoEnabled() ){
            recursiveDelete(this, findPreference(Keys.KEY_CAMERA_HDR));
            return;
        }

        if((mDataModule.getDataSetting().mMode == SettingsScopeNamespaces.REFOCUS
                || mDataModule.getDataSetting().mMode == SettingsScopeNamespaces.FRONT_BLUR)
                &&!CameraUtil.isHdrBlurSupported()){
            recursiveDelete(this, findPreference(Keys.KEY_CAMERA_HDR));
        }
    }

我们看到有比较多的 updateVisibility开头的方法,用来二次控制设置项是否能显示出来。这里比较多的条件是与硬件相关的。也就是说一个设置项要能显示出来,不仅需要在xml中配置,还需要硬件支持,java文件的二次判断相当于又多加了一次拦截,把zml配置的支持的设置项在过滤一遍,避免出现不支持的设置项被显示出来了。因此,如果我们发现一个设置项不显示,不仅要检查xml是否配置,还要考虑可能是java文件做了二次拦截。

好了,到这里我们已经将CamereAPP的设置项流程(数据和layout)全部追踪完成了。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值