snapdragon camera menu控制与事件触发介绍

来源:互联网 发布:薛之谦网络合唱丑八怪 编辑:程序博客网 时间:2024/06/07 01:20

menu即拍照界面上排的选项按钮,有设置,吗,美颜,滤镜,闪光灯,情景模式等等。menu有photoMenu与videoMenu,这里以photoMenu为例介绍其控制流程。

这里以滤镜为例讲解流程。

photoMenu的初始化是在打开camera的时候实例化的。
camera启动后会调用PhotoModule.java里面的onCameraOpened> openCameraCommon最后在photoUI里面的onCameraOpened实例化

  private void onCameraOpened() {

   ... ... ...
        openCameraCommon();

    ... ... ...
  }

  private void openCameraCommon() {
        loadCameraPreferences();//根据配置加载camera的switch按钮
        mUI.onCameraOpened(mPreferenceGroup, mPreferences, mParameters, this, this);

       ... ... ...

  }

PhotoUI.java  》new PhotoMenu(mActivity, this, makeupListener);即完成初始化并将实例设置上去

 public void onCameraOpened(PreferenceGroup prefGroup, ComboPreferences prefs,

     Camera.Parameters params, OnPreferenceChangedListener listener, MakeupLevelListener makeupListener) {
      ... ... ...


        if (mMenu == null) {
            mMenu = new PhotoMenu(mActivity, this, makeupListener);实例化menu并赋予点击事件
            mMenu.setListener(listener);
        }
        mMenu.initialize(prefGroup);//实例化menu后初始化所有的menu选项
        mMenuInitialized = true;

        ... ... ...

        mGestures.setPhotoMenu(mMenu);//将menu添加到预览手势触摸点击事件控制器PreviewGestures.java(这个个控制器负责了整个预览界面触摸事件分发,保证正确的控件事件响应)

        ... ... ...

 }

自此photoMenu已经初始化完毕,接下来的控制流程就直接到photoMenu.java里面看了。如上,这里以滤镜来解析其控制流程。如上实例化menu后调用了mMenu.initialize(Group).

PhotoMenu.java 》initialize 》initFilterModeButton》对应滤镜menu选项

public void initialize(PreferenceGroup group) {
        super.initialize(group);
        ... ... ...
        initFilterModeButton(mFilterModeSwitcher);//初始化滤镜按钮
        ... ... ...
}

初始化包括filter按钮的初始值,根据初始值设置颜色,按钮的点击事件,点击后我们会看到左侧面会移出一侧边filter选项popmenu,此由addFilterMode实现,再下面是其显示动画

  public void initFilterModeButton(View button) {//初始化滤镜按钮,上排menu中的三个圈圈
        button.setVisibility(View.INVISIBLE);
        final IconListPreference pref = (IconListPreference) mPreferenceGroup
                .findPreference(CameraSettings.KEY_COLOR_EFFECT);//得到配置文件里面配置的所有滤镜信息
        if (pref == null || pref.getValue() == null)
            return;
        changeFilterModeControlIcon(pref.getValue());//滤镜按钮(三个圈)数值更新,为none就灰显,不为none就蓝显
        button.setVisibility(View.VISIBLE);
        button.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                closeMakeup();
                addFilterMode();//加载滤镜选项,为滤镜menu布好局
                ViewGroup menuLayout = mUI.getPreviewMenuLayout();
                if (menuLayout != null) {
                    View view = mUI.getPreviewMenuLayout().getChildAt(0);
                    mUI.adjustOrientation();//确定方向
                    animateSlideIn(view, previewMenuSize, false);//动画飞出滤镜选择menu视图
                }
            }
        });
    }
我们把addFilterMode的关键的内容做了中文备注,看下
public void addFilterMode() {
        final IconListPreference pref = (IconListPreference) mPreferenceGroup
                .findPreference(CameraSettings.KEY_COLOR_EFFECT);//得到配置文件中的滤镜配置项
        if (pref == null)
            return;
        ... ......
         WindowManager wm = (WindowManager) mActivity.getSystemService(Context.WINDOW_SERVICE);
        Display display = wm.getDefaultDisplay();
        CharSequence[] entries = pref.getEntries();//从配置项中得到所有滤镜条目

        Resources r = mActivity.getResources();
        int height = (int) (r.getDimension(R.dimen.filter_mode_height) + 2
                * r.getDimension(R.dimen.filter_mode_padding) + 1);
        int width = (int) (r.getDimension(R.dimen.filter_mode_width) + 2
                * r.getDimension(R.dimen.filter_mode_padding) + 1);

        int gridRes = 0;
        boolean portrait = (rotation == 0) || (rotation == 180);
        int size = height;
        if (portrait) {//根据横竖屏加载对应布局
            gridRes = R.layout.vertical_grid;
            size = width;
        } else {
            gridRes = R.layout.horiz_grid;
        }
       ... ... ...
       int[] thumbnails = pref.getThumbnailIds();//得到对应滤镜的表示图片
       ... ... ...
       
        for (int i = 0; i < entries.length; i++) {
           ... ... ...
            layout2.setOnTouchListener(new View.OnTouchListener() {//为每一个filter 的menuItem添加点击事件
                private long startTime;
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    if (event.getAction() == MotionEvent.ACTION_DOWN) {
                        startTime = System.currentTimeMillis();
                    } else if (event.getAction() == MotionEvent.ACTION_UP) {
                        if (System.currentTimeMillis() - startTime < CLICK_THRESHOLD) {
                            pref.setValueIndex(j);
                            changeFilterModeControlIcon(pref.getValue());//根据点击的滤镜选项图片更新三圈图标
                            onSettingChanged(pref);//重新刷新一遍设置项,并使对应的滤镜预览生效。最后都是回调PhotoModule(其它xxxModule类同)里面的onSharedPreferenceChanged
                            for (View v1 : views) {
                                v1.setBackground(null);
                            }
                            ImageView image = (ImageView) v.findViewById(R.id.image);
                            image.setBackgroundColor(0xff33b5e5);//给点击的那个图片着色
                        }
                    }
                    return true;
                }
            });
                   views[j] = imageView;
            if (i == init)
                imageView.setBackgroundColor(0xff33b5e5);
            TextView label = (TextView) layout2.findViewById(R.id.label);
            imageView.setImageResource(thumbnails[i])//为对应的滤镜选项设置对应的表示图片
            label.setText(entries[i]);
            layout.addView(layout2);//将item加到pop布局里面
        }
        previewMenuLayout.addView(basic);
        mPreviewMenu = basic;
}
@Override
    public void onSettingChanged(ListPreference pref) {
     ... ... ...
     updateFilterModeIcon(pref, pref);//更新滤镜menu选择按钮
     ... ... ... 
     super.onSettingChanged(pref);//setting更新后调用这个在MenuController回调PhotoModule(其它xxxModule类同)里面的onSharedPreferenceChanged
     ... ... ...
     }

tips:
所有的设置项改变,即各个menu的点击最后都会调用这个onSettingChanged触发camera根据设置项的改变preview新的数据与展示新的界面交互与显示。这里需要注意的是滤镜并不是在每个预览模式下都支持的,所以会通过updateFilterModeIcon重新规划menu是否可点击,比如在在选择了hdr mode时就不可以有滤镜。会将滤镜按钮灰显不可点击,如果原来是滤镜模式就会还原为普通模式。这里脱离滤镜选择旅程只是做个额外的介绍

     private void updateFilterModeIcon(ListPreference scenePref, ListPreference hdrPref) {
        if (scenePref == null || hdrPref == null) return;
        if ((notSame(scenePref, CameraSettings.KEY_SCENE_MODE, Parameters.SCENE_MODE_AUTO))
                || (notSame(hdrPref, CameraSettings.KEY_CAMERA_HDR, mSettingOff))) {
            buttonSetEnabled(mFilterModeSwitcher, false);//设置滤镜按钮不可点击
            changeFilterModeControlIcon("none");//重新设置滤镜按钮为关闭
        ... ... ...
       }

自此滤镜UI部分交互完毕,接下来是数据流部分,即点击对应的滤镜后preview的大致流程见上面对应滤镜选项点击事件触发super.onSettingChanged父类对应
MenuController.java里面

   public void onSettingChanged(ListPreference pref) {//当对应设置与menu等改变就会调用这个回调XXXModule监听
        if (mListener != null) {
            mListener.onSharedPreferenceChanged(pref);
        }
    }

onSharedPreferenceChanged实现在PhotoModule.java

 @Override
    public void onSharedPreferenceChanged(ListPreference pref) {//设置对应属性后都会被监听回调到这里更新各个属性后通过 onSharedPreferenceChanged() 调用setCameraParametersWhenIdle重新设置参数后preview出变化的数据
          ... ... ...
        //call generic onSharedPreferenceChanged
        onSharedPreferenceChanged();//根据设置项更新后重新preview
    }

     @Override
    public void onSharedPreferenceChanged() {
        // ignore the events after "onPause()"
        if (mPaused) return;
        boolean recordLocation = RecordLocationPreference.get(mPreferences);
        mLocationManager.recordLocation(recordLocation);
        if(needRestart()){
            Log.v(TAG, "Restarting Preview... Camera Mode Changed");
            stopPreview();
            startPreview();
            setCameraState(IDLE);
            mRestartPreview = false;
        }
        /* Check if the PhotoUI Menu is initialized or not. This
         * should be initialized during onCameraOpen() which should
         * have been called by now. But for some reason that is not
         * executed till now, then schedule these functionality for
         * later by posting a message to the handler */
        if (mUI.mMenuInitialized) {
            setCameraParametersWhenIdle(UPDATE_PARAM_PREFERENCE);//重新设置参数,这个就是上层preview数据变化的地方,底层会根据参数的改变设置滤镜
            mUI.updateOnScreenIndicators(mParameters, mPreferenceGroup,
                mPreferences);
        } else {
            mHandler.sendEmptyMessage(SET_PHOTO_UI_PARAMS);//这个消息接受者最后与上面一样调用setCameraParametersWhenIdle重新设置参数preview数据
        }
        resizeForPreviewAspectRatio();//根据设置项更新后重新preview包括屏幕比率
    }
    
     private void setCameraParametersWhenIdle(int additionalUpdateSet) {
        mUpdateSet |= additionalUpdateSet;
        if (mCameraDevice == null) {
            // We will update all the parameters when we open the device, so
            // we don't need to do anything now.
            mUpdateSet = 0;
            return;
        } else if (isCameraIdle()) {
            setCameraParameters(mUpdateSet); //重新设置参数
         ... ... ...
      }

      private void setCameraParameters(int updateSet) {//各种重设参数都会调用到这里,如切换前后摄,切换滤镜,切换尺寸等等
        if (mCameraDevice == null) {
            return;
        }
        synchronized (mCameraDevice) {//切换前后摄时下面if全部刷一遍更新parameter
            boolean doModeSwitch = false;
            if ((updateSet & UPDATE_PARAM_INITIALIZE) != 0) {
                updateCameraParametersInitialize();//貌似和录像有关
            }
            if ((updateSet & UPDATE_PARAM_ZOOM) != 0) {
                updateCameraParametersZoom();
            }
            if ((updateSet & UPDATE_PARAM_PREFERENCE) != 0) {//重刷parameter参数//比如设置滤镜时,
                doModeSwitch = updateCameraParametersPreference();
            }
            mCameraDevice.setParameters(mParameters);


            // Switch to gcam module if HDR+ was selected
            if (doModeSwitch && !mIsImageCaptureIntent) {
                mHandler.sendEmptyMessage(SWITCH_TO_GCAM_MODULE);
            }
        }
    }

    接着updateCameraParametersPreference--》  qcomUpdateCameraParametersPreference();

         
    比如这个滤镜最后就是在
      /** This can run on a background thread, so don't do UI updates here.*/
    private void qcomUpdateCameraParametersPreference() {
      ... ... ...
      // Set color effect parameter.//设置滤镜
        String colorEffect = mPreferences.getString(
                CameraSettings.KEY_COLOR_EFFECT,
                mActivity.getString(R.string.pref_camera_coloreffect_default));
        Log.v(TAG, "Color effect value =" + colorEffect);
        if (CameraUtil.isSupported(colorEffect, mParameters.getSupportedColorEffects())) {
            mParameters.setColorEffect(colorEffect);
        }
        ... ... ...
      }
     至此就是framework对接底层的事了

原创粉丝点击