AndroidR上展讯CameraAPP的openCamera流程

看展讯平台的Camera有一段时间了,今天来整理下openCamera的流程。
其实,CameraAPP的主要逻辑可分为两大部分:界面显示 + camera处理

展讯和MTK平台CameraAPP的共同点是两者都有Module的概念,即不同的Module处理app中不同的模式,比如拍照模式、美颜模式、录像模式等等。
但是在与camera这个硬件设备打交道的时候,设计却明显不同。MTK平台app是将UI的处理与camera处理均放在当前Module中处理,而展讯平台是Module只处理与当前模式相关的界面逻辑,而将camera操作统一封装,由专门的类去处理。

如下是处理与camera相关逻辑的类的继承关系
在这里插入图片描述
从图明显看出,在CameraAgent处分支了,一支类名中带有2,一支没有,这是与camera使用api1还是api2有关的。显然我们现在都是使用的api2,因此我们关注左边的分支。
与camera相关的打开、预览、拍照、数据callback、关闭等操作均在这几个类里面处理。

现在我们以普通的photo模式为例,来看下openCamera流程调用。

从PhotoModule的resume开始,

@Override
public void resume() {
   Log.i(TAG, "resume start!");
   //---此处省略与UI相关的处理
   requestCameraOpen();
}

流程转到requestCameraOpen方法

/**
     * Uses the {@link CameraProvider} to open the currently-selected camera
     * device, using {@link GservicesHelper} to choose between API-1 and API-2.
     */
    protected void requestCameraOpen() {
        /**
         * SPRD: fix bug47362 Log.v(TAG, "requestCameraOpen");
         */
        /*
         * SPRD:Fix bug 513841 KEY_CAMERA_ID may be changed during the camera in
         * background if user do switch camera action in contacts, and then we
         * resume the camera, the init function will not be called, so the
         * mCameraId will not be the latest one. Which will cause the switch
         * camera function can not be used. @{
         */
        int mCameraID = mDataModule.getInt(Keys.KEY_CAMERA_ID);
        if(mIsImageCaptureIntent) {
            mCameraID = mDataModule.getInt(Keys.KEY_INTENT_CAMERA_ID);
        }
        if(mCameraID != mCameraId){
            mCameraId = mCameraID;
            mActivity.getCameraAppUI().updateModeList();
        }

        if (mCameraId == DreamUtil.FRONT_CAMERA && isSupportSensoSelfShotModule()) {
            mCameraId = CameraUtil.SENSOR_SELF_SHOT_CAMERA_ID;
        }

        /* @} */

        /*start add for w+t*/
        if (CameraUtil.isWPlusTAbility(mActivity,mActivity.getCurrentModuleIndex(),mCameraId)){
            mCameraId = CameraUtil.BACK_W_PLUS_T_PHOTO_ID;
        }
        /*end add for w+t*/

//        if (mActivity.getCurrentModuleIndex() == SettingsScopeNamespaces.AUTO_PHOTO && !DreamUtil.isFrontCamera(mActivity,mCameraId)) {
        if (CameraUtil.isTcamAbility(mActivity,mActivity.getCurrentModuleIndex(),mCameraId)) {
            mCameraId = CameraUtil.BACK_TRI_CAMERA_ID;
        }
        /**
         * SPRD: Change for New Feature VGesture and dream camera
         * original code
         * @{
        mActivity.getCameraProvider().requestCamera(
                mCameraId,
                GservicesHelper.useCamera2ApiThroughPortabilityLayer(mActivity
                         .getContentResolver()));
          */
        Log.i(TAG, "requestCameraOpen mCameraId:" + mCameraId);
        doCameraOpen(mCameraId);
       /**
         * @}
         */
    }

此方法的前半部分是对mCameraId各种情况下的校验,最后是调用doCameraOpen(mCameraId)

protected void doCameraOpen(int cameraId){
        mActivity.getCameraProvider().requestCamera(cameraId, useNewApi());
    }

doCameraOpen方法很简单,就是将流程又转到 requestCamera,这里我们关注下 mActivity.getCameraProvider()是个什么类型。

在CameraActivity中,我们看到getCameraProvider就是CameraController类, 去看下CameraController。

public class CameraController implements CameraAgent.CameraOpenCallback, CameraProvider

CameraController 内容不多,因为实现了CameraAgent.CameraOpenCallback,所以其主要内容是camera状态的回调,但是并不处理这些回调,是在在接收到回调后,转发给相应的处理者。

还是回到从PhotoModule跟过来的requestCamera方法。

@Override
    public void requestCamera(int id, boolean useNewApi) {
        Log.i(TAG, "requestCamera id="+id);
        Log.i(TAG, "mRequestingCameraId = " + mRequestingCameraId + "mInfo = " + mInfo);
        if (mRequestingCameraId != EMPTY_REQUEST || mRequestingCameraId == id) {
            return;
        }
        mRequestingCameraId = id;
        mActiveCameraDeviceTracker.onCameraOpening(CameraId.fromLegacyId(id));

        // Only actually use the new API if it's supported on this device.
        useNewApi = mCameraAgentNg != null && useNewApi;
        CameraAgent cameraManager = useNewApi ? mCameraAgentNg : mCameraAgent;

        if (mCameraProxy == null) {
            // No camera yet.
            checkAndOpenCamera(cameraManager, id, mCallbackHandler, this);
        } else if (mCameraProxy.getCameraId() != id || mUsingNewApi != useNewApi) {
            boolean syncClose = GservicesHelper.useCamera2ApiThroughPortabilityLayer(mContext
                        .getContentResolver());
            Log.v(TAG, "different camera already opened, closing then reopening");
            mCameraProxy = null;
            // Already has camera opened, and is switching cameras and/or APIs.
            if (mUsingNewApi) {
                if (mCameraAgentNg != null)
                    mCameraAgentNg.closeCamera(mCameraProxy, true);
            } else {
                // if using API2 ensure API1 usage is also synced
                mCameraAgent.closeCamera(mCameraProxy, syncClose);
            }
            checkAndOpenCamera(cameraManager, id, mCallbackHandler, this);
        } else {
            // The same camera, just do a reconnect.
            Log.v(TAG, "reconnecting to use the existing camera");
            mCameraProxy.reconnect(mCallbackHandler, this);
            mCameraProxy = null;
        }

        mUsingNewApi = useNewApi;
    }

有与CameraAgent相关的:
CameraAgent cameraManager = useNewApi ? mCameraAgentNg : mCameraAgent;
我们在CameraAPP中可以看到很多类似的,通过useNewApi 这个boolean值判断使用哪个Agent,这其实就是我们前面说的api1与api2的兼容处理。

我们以打开CameraAPP,第一次请求openCamera的流程来跟踪,那么 mCameraProxy == null 是符合的,进入第一个if分支:checkAndOpenCamera

private static void checkAndOpenCamera(CameraAgent cameraManager,
            final int cameraId, Handler handler, final CameraAgent.CameraOpenCallback cb) {
        Log.i(TAG, "checkAndOpenCamera");
        try {
            CameraUtil.throwIfCameraDisabled();
            cameraManager.openCamera(handler, cameraId, cb);
        } catch (CameraDisabledException ex) {
            handler.post(new Runnable() {
                @Override
                public void run() {
                    cb.onCameraDisabled(cameraId);
                }
            });
        }
    }

关键代码:cameraManager.openCamera(handler, cameraId, cb);
而cameraManager就是前面通过useNewApi的boolean值判断得来的api2的那支的CameraAgent。
还记得最前面的那张继承关系图吗?
现在就要从CameraController中的openCamera方法转到那张继承关系图中的类了。

因为是继承关系,我也不知道具体的openCamera方法是在继承关系中的哪个类实现的,我们就一个个找吧。
最终在CameraAgent中找到了openCamera的实现:

public void openCamera(final Handler handler, final int cameraId,
                           final CameraOpenCallback callback) {
        Log.e(TAG,"openCamera "+android.util.Log.getStackTraceString(new Throwable()));
        try {
            getDispatchThread().runJob(new Runnable() {
                @Override
                public void run() {
                    synchronized (mOpenCloseSyncLock) {
                        isOpeningAndCloseNeedWait = true;
                    }
                    getCameraHandler().obtainMessage(CameraActions.OPEN_CAMERA, cameraId, 0,
                            CameraOpenCallbackForward.getNewInstance(handler, callback)).sendToTarget();
                }
            });
        } catch (final RuntimeException ex) {
            getCameraExceptionHandler().onDispatchThreadException(ex);
        }
    }

看来CameraAgent的openCamera也没做什么事情,就是通过handler–message机制转发了下CameraActions.OPEN_CAMERA消息。
再来追CameraActions.OPEN_CAMERA消息的处理
我们在AndoridCamera2AgentImpl中找到了

case CameraActions.OPEN_CAMERA:
 {
    CameraOpenCallback openCallback = (CameraOpenCallback) msg.obj;
    int cameraIndex = msg.arg1;

    if (mCameraState.getState() > AndroidCamera2StateHolder.CAMERA_UNOPENED) {
        openCallback.onDeviceOpenedAlready(cameraIndex,
                generateHistoryString(cameraIndex));
        break;
    }

    mOpenCallback = openCallback;
    mCameraIndex = cameraIndex;

    /*
     * SPRD: Fix bug 591216 that add new feature 3d range finding, only support API2 currently @{
     * Original Code
     *
    mCameraId = mCameraDevices.get(mCameraIndex);
     */
    mCameraId = "" + mCameraIndex;
    /* @} */

    Log.i(TAG, String.format("Opening camera index %d (id %s) with camera2 API",
            cameraIndex, mCameraId));

    if (mCameraId == null) {
        mOpenCallback.onCameraDisabled(msg.arg1);
        break;
    }
    reconnect = false;
    mCameraManager.openCamera(mCameraId, mCameraDeviceStateCallback, this);

    break;
}

mCameraManager.openCamera,追到了CameraManager了。至此APP端的openCamera流程已经完成了。

最后,我们将上述流程画成时序图来总结下:
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值