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

来源:互联网 发布:trados翻译软件官方 编辑:程序博客网 时间:2024/06/05 18:30

在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 0