Android4.4 Camera Gallery2 App之间消息传递分析!

在Android4.4上面,Camera和Gallery2的关系在代码上是分开的。但是在在实际代码上,Camera和Gallery的关系很密切。

下面以实际开发过程中遇到的一个问题来展开分析:

需求:客户要求做假对焦,进入到preview界面的时候,自动对焦一次。

我的做法是在PhotoActor.java中的onPreviewStartDone预览完成的函数中模拟onSingleTapUp触摸点击效果的自动对焦过程。

mCamera.getFocusManager().onSingleTapUp(mCamera.getPreviewFrameWidth() / 2, mCamera.getPreviewFrameHeight() / 2);

FocusManager.java

    public void onSingleTapUp(int x, int y) {
        Log.i(TAG,"onSingleTapUp x = " + x + " y = " + y);
        if (!mInitialized || mState == STATE_FOCUSING_SNAP_ON_FINISH || mState == STATE_UNKNOWN) { return; }

        ………………
        // Disable "center" rule because we no longer want to put it in the center.
        int[] rules = p.getRules();
        rules[RelativeLayout.CENTER_IN_PARENT] = 0;
        mFocusIndicatorRotateLayout.requestLayout();

        // Stop face detection because we want to specify focus and metering area.
        mListener.stopFaceDetection();

        // Set the focus area and metering area.
        mListener.setFocusParameters();
        if (mFocusAreaSupported) {
            autoFocus();
        } else {  // Just show the indicator in all other cases.
            updateFocusUI();
            // Reset the metering area in 3 seconds.
            mHandler.removeMessages(RESET_TOUCH_FOCUS);
            mHandler.sendEmptyMessageDelayed(RESET_TOUCH_FOCUS, RESET_TOUCH_FOCUS_DELAY);
            //add 
            mHandler.removeMessages(MSG_SHOW_FOCUS_END);
            mHandler.sendEmptyMessageDelayed(MSG_SHOW_FOCUS_END, MSG_SHOW_FOCUS_END_DELAY);
        }
    }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
            case RESET_TOUCH_FOCUS:
                cancelAutoFocus();
                mListener.startFaceDetection();
                break;
           case MSG_SHOW_FOCUS_END:
            mFocusIndicatorRotateLayout.showSuccess(true);
            mListener.playSound(MediaActionSound.FOCUS_COMPLETE);
            break;			
            default:
                break;
            }
        }

这样,简单的功能是实现了,但是首先遇到的第一个问题是:由于Preview的SurfaceView界面是先绘制出来,然后取景的,取景需要时间,这样对焦就经常发生在SurfaceView还是灰色界面的时候就开始对焦,特别是在切换前后摄像头的时候特别明显。真实对焦是不会发生这样的问题的,因为它是根据Sensor捕获到的信息上传后产生效果的,取景没完成是不会对焦的。假对焦那就采取野蛮的办法,增加一个延时,演变成下面的代码:

            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    mCamera.getFocusManager().onSingleTapUp(mCamera.getPreviewFrameWidth() / 2, mCamera.getPreviewFrameHeight() / 2);
                }
            }, 1000);

这样基本上能接受了。

很快,测试找到了第二个问题点:Camera Activity启动后,进入到图片预览界面,然后OnPause,再OnResume的时候,进入到的还是图片预览界面,但是这时候会有对焦行为。通过log分析,OnResume的时候也是有startPreview行为的(不管你是在preview界面,还是在图片预览界面),我的理解是,这时候不管在哪个界面,Preview都已经需要Init,只是在图片预览时,Camera preview的行为是在另外开辟的一个缓存中进行的,只是没有在当前屏幕显示出来而已。

自然而然,我们就必须增加一个判断条件来判断Camera Preview是否在当先的显示画面。很快在PhotoPage.java就找到了相关的代码。重点问题来的,我要怎么在Camera和Gallery之间来传递消息呢?

Camera.java和GalleryActivity.java都集成自AbstractGalleryActivity.java,通过分析在ActivityBase.java中找到AppBridge,顾名思义,可以看出来,这就是桥梁。在AppBridge抽象类中有一个接口:

    public interface Server {
        // Set the camera frame relative to GLRootView.
        public void setCameraRelativeFrame(Rect frame);
        // Switch to the previous or next picture using the capture animation.
        // The offset is -1 to switch to the previous picture, 1 to switch to
        // the next picture.
        public boolean switchWithCaptureAnimation(int offset);
        // Enable or disable the swiping gestures (the default is enabled).
        public void setSwipingEnabled(boolean enabled);
        // Notify that the ScreenNail is changed.
        public void notifyScreenNailChanged();
        // Add a new media item to the secure album.
        public void addSecureAlbumItem(boolean isVideo, int id);
        /// M: for camera gesture feature @
        public Listener setGestureListener(Listener listener);
        /// @}

        // M: Notify PhotoView to render FullPicture only to boost performance
        public void renderFullPictureOnly(boolean fullPictureOnly);
        public void setOritationTag(boolean lock, int oritationNum);
        ///M:add for set camera path
        public void setCameraPath(String setPath);
        
        public int getSecureAlbumCount();
	 public boolean isCameraScreen(int offset);  
    }

而PhotoPage实现了该接口:

public class PhotoPage extends ActivityState implements
        PhotoView.Listener, OrientationManager.Listener, ShareActionProvider.OnShareTargetSelectedListener,AppBridge.Server,
        PhotoPageBottomControls.Delegate, GalleryActionBar.OnAlbumModeSelectedListener,
        AbstractGalleryActivity.GyroPositionListener, 
        AbstractGalleryActivity.HotknotCompleteListener{
……
    public boolean isCameraScreen(int offset) {
        return mModel.isCamera(offset);
    }
……
}

找到问题点,实现起来就非常简单了,中间还有两层的封装就不多说了,最终的代码变为:

        if(mCamera.isCameraScreen(0)) {
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    mCamera.getFocusManager().onSingleTapUp(mCamera.getPreviewFrameWidth() / 2, mCamera.getPreviewFrameHeight() / 2);
                }
            }, 1000);
        }

整个过程还是花了我1.5天的时间,主要是没有找到好的可以查看整个app UML结构的工具,所以一点点找起来麻烦,浪费时间,而且代码量大,很容易就迷失了。

有好的工具,请留言推荐,谢谢!


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值