重构原生camera2 有3个月了,现在也算告一段落,这里总结一些原生APK流程以做记录。
camera2的所有主要操作都在一个activity中进行,那就是CameraActivity.java,所以现在先onCreate开始说起,由于我们现在主要讲启动流程,所以将与主流程无关的代码和UI界面相关的复杂代码删除,以便阅读。
CameraActivity.java
public void onCreate(Bundle state) {
CameraPerformanceTracker.onEvent(CameraPerformanceTracker.ACTIVITY_START);
super.onCreate(state);
if (!Glide.isSetup()) {
Glide.setup(new GlideBuilder(this)
.setResizeService(new FifoPriorityThreadPoolExecutor(1)));
Glide.get(this).setMemoryCategory(MemoryCategory.HIGH);
}
mOnCreateTime = System.currentTimeMillis();
mAppContext = getApplicationContext();
mSoundPlayer = new SoundPlayer(mAppContext);
//获取cameramanager,在CaptureModule中使用,但是我们拍照用的是PhotoModule所以暂时无用
mCameraManager = OneCameraManager.get(this);
// TODO: Try to move all the resources allocation to happen as soon as
// possible so we can call module.init() at the earliest time.
mModuleManager = new ModuleManagerImpl();
GcamHelper.init(getContentResolver());
//初始化Modules,这里Module的作用相当于MVC模式中M的作用,它对camera进行操作。
ModulesInfo.setupModules(mAppContext, mModuleManager);
//SettingsManager保存camera配置
mSettingsManager = getServices().getSettingsManager();
AppUpgrader appUpgrader = new AppUpgrader(this);
appUpgrader.upgrade(mSettingsManager);
Keys.setDefaults(mSettingsManager, mAppContext);
getWindow().requestFeature(Window.FEATURE_ACTION_BAR);
setContentView(R.layout.activity_main);
mActionBar = getActionBar();
// set actionbar background to 100% or 50% transparent
if (ApiHelper.isLOrHigher()) {
mActionBar.setBackgroundDrawable(new ColorDrawable(0x00000000));
} else {
mActionBar.setBackgroundDrawable(new ColorDrawable(0x80000000));
}
mActionBar.addOnMenuVisibilityListener(mOnMenuVisibilityListener);
mMainHandler = new MainHandler(this, getMainLooper());
//创建camera的controll对象,通过CameraController来对framework的API接口进行控制,现在camera有2套API机制可以在CameraAgentFactory中看到,后续再进行说明。
mCameraController = new CameraController(mAppContext, this, mMainHandler,
CameraAgentFactory.getAndroidCameraAgent(this, CameraAgentFactory.CameraApi.API_1),
CameraAgentFactory.getAndroidCameraAgent(this, CameraAgentFactory.CameraApi.AUTO));
mCameraController.setCameraDefaultExceptionCallback(mCameraDefaultExceptionCallback,
mMainHandler);
.........
//CameraAppUI来绘制camera总UI,不同module的UI在对应的module内再绘制,比如photomodule的ui由PhotoUI绘制
mCameraAppUI = new CameraAppUI(this,
(MainActivityLayout) findViewById(R.id.activity_root_view), isCaptureIntent());
.........
//设置当前module
setModuleFromModeIndex(getModeIndex());
//初始化UI
mCameraAppUI.prepareModuleUI();
//初始化当前Module
mCurrentModule.init(this, isSecureCamera(), isCaptureIntent());
.........
}
//这样oncreate完成,接下来看onStart,我们拍照界面用的是PhotoModule,所以后面module都用PhotoModule为列
public void onStart() {
super.onStart();
mIsActivityRunning = true;
mPanoramaViewHelper.onStart();
//获取当前所用moduleID
int modeIndex = getModeIndex();
if (!isCaptureIntent() && mCurrentModeIndex != modeIndex) {
//切换modeIndex所代表的module
onModeSelected(modeIndex);
}
if (mResetToPreviewOnResume) {
mCameraAppUI.resume();
mResetToPreviewOnResume = false;
}
}
public void onModeSelected(int modeIndex) {
if (mCurrentModeIndex == modeIndex) {
return;
}
CameraPerformanceTracker.onEvent(CameraPerformanceTracker.MODE_SWITCH_START);
// Record last used camera mode for quick switching
if (modeIndex == getResources().getInteger(R.integer.camera_mode_photo)
|| modeIndex == getResources().getInteger(R.integer.camera_mode_gcam)) {
mSettingsManager.set(SettingsManager.SCOPE_GLOBAL,
Keys.KEY_CAMERA_MODULE_LAST_USED,
modeIndex);
}
//关闭之前module
closeModule(mCurrentModule);
// Select the correct module index from the mode switcher index.
modeIndex = getPreferredChildModeIndex(modeIndex);
setModuleFromModeIndex(modeIndex);
mCameraAppUI.resetBottomControls(mCurrentModule, modeIndex);
mCameraAppUI.addShutterListener(mCurrentModule);
mCameraAppUI.hideLetterboxing();
//打开所选module
openModule(mCurrentModule);
mCurrentModule.onOrientationChanged(mLastRawOrientation);
// Store the module index so we can use it the next time the Camera
// starts up.
//保存当前module值到sharePreference
mSettingsManager.set(SettingsManager.SCOPE_GLOBAL,
Keys.KEY_STARTUP_MODULE_INDEX, modeIndex);
}
private void openModule(CameraModule module) {
module.init(this, isSecureCamera(), isCaptureIntent());
module.hardResetSettings(mSettingsManager);
module.resume();
UsageStatistics.instance().changeScreen(currentUserInterfaceMode(),
NavigationChange.InteractionCause.BUTTON);
updatePreviewVisibility();
}
private void closeModule(CameraModule module) {
module.pause();
mCameraAppUI.clearModuleUI();
}
//现在在PhotoModule中查看对应init,resum,epause
PhotoModule.java
public void init(CameraActivity activity, boolean isSecureCamera, boolean isCaptureIntent) {
mActivity = activity;
// TODO: Need to look at the controller interface to see if we can get
// rid of passing in the activity directly.
mAppController = mActivity;
//控制UI
mUI = new PhotoUI(mActivity, this, mActivity.getModuleLayoutRoot());
mActivity.setPreviewStatusListener(mUI);
SettingsManager settingsManager = mActivity.getSettingsManager();
//获取当前cameraID,一般后摄为0,前摄为1
mCameraId = settingsManager.getInteger(mAppController.getModuleScope(),
Keys.KEY_CAMERA_ID);
.........
}
public void resume() {
mPaused = false;
// Add delay on resume from lock screen only, in order to to speed up
// the onResume --> onPause --> onResume cycle from lock screen.
// Don't do always because letting go of thread can cause delay.
if (isResumeFromLockscreen()) {
Log.v(TAG, "On resume, from lock screen.");
// Note: onPauseAfterSuper() will delete this runnable, so we will
// at most have 1 copy queued up.
mHandler.postDelayed(mResumeTaskRunnable, ON_RESUME_TASKS_DELAY_MSEC);
} else {
Log.v(TAG, "On resume.");
onResumeTasks();
}
}
private void onResumeTasks() {
if (mPaused) {
return;
}
Log.v(TAG, "Executing onResumeTasks.");
mCountdownSoundPlayer.loadSound(R.raw.timer_final_second);
mCountdownSoundPlayer.loadSound(R.raw.timer_increment);
if (mFocusManager != null) {
// If camera is not open when resume is called, focus manager will
// not be initialized yet, in which case it will start listening to
// preview area size change later in the initialization.
mAppController.addPreviewAreaSizeChangedListener(mFocusManager);
}
mAppController.addPreviewAreaSizeChangedListener(mUI);
CameraProvider camProvider = mActivity.getCameraProvider();
if (camProvider == null) {
// No camera provider, the Activity is destroyed already.
return;
}
//打开camera
requestCameraOpen();
.........
}
private void requestCameraOpen() {
Log.v(TAG, "requestCameraOpen");
//GservicesHelper.useCamera2ApiThroughPortabilityLayer(mActivity)默认为true
//getCameraProvider()获得的对象就是在CameraActivity中new出来的CameraController
mActivity.getCameraProvider().requestCamera(mCameraId,
GservicesHelper.useCamera2ApiThroughPortabilityLayer(mActivity));
}
下面看CameraController.java
public class CameraController implements CameraAgent.CameraOpenCallback, CameraProvider {
private final CameraAgent mCameraAgent;
private final CameraAgent mCameraAgentNg;
//CameraActivity oncreate时NEW的对象
public CameraController(Context context, CameraAgent.CameraOpenCallback callbackReceiver,
Handler handler, CameraAgent cameraManager, CameraAgent cameraManagerNg) {
mContext = context;
//将CameraActivity中复写的CameraAgent.CameraOpenCallback传入
mCallbackReceiver = callbackReceiver;
mCallbackHandler = handler;
//看CameraActivity中初始化的时候可以看到cameraManager传入的是AndroidCameraAgentImpl.java对象
mCameraAgent = cameraManager;
// If the new implementation is the same as the old, the
// CameraAgentFactory decided this device doesn't support the new API.
//这里如果用的是camera_api2则会是AndroidCamera2AgentImpl.java对象 否则也是AndroidCameraAgentImpl.java对象
mCameraAgentNg = cameraManagerNg != cameraManager ? cameraManagerNg : null;
mInfo = mCameraAgent.getCameraDeviceInfo();
if (mInfo == null && mCallbackReceiver != null) {
mCallbackReceiver.onDeviceOpenFailure(-1, "GETTING_CAMERA_INFO");
}
}
@Override
public void requestCamera(int id, boolean useNewApi) {
//如果打开的是相同的cameraId则返回
if (mRequestingCameraId != EMPTY_REQUEST || mRequestingCameraId == id) {
return;
}
if (mInfo == null) {
return;
}
mRequestingCameraId = id;
// Only actually use the new API if it's supported on this device.
//useNewApi为true时,说明走API2
useNewApi = mCameraAgentNg != null && useNewApi;
CameraAgent cameraManager = useNewApi ? mCameraAgentNg : mCameraAgent;
if (mCameraProxy == null) {
// No camera yet.
//第一次启动camera时会走这里
checkAndOpenCamera(mContext, cameraManager, id, mCallbackHandler, this);
} else if (mCameraProxy.getCameraId() != id || mUsingNewApi != useNewApi) {
//切换camera时会走这先关闭camera再重启
boolean syncClose = GservicesHelper.useCamera2ApiThroughPortabilityLayer(mContext);
Log.v(TAG, "different camera already opened, closing then reopening");
// Already has camera opened, and is switching cameras and/or APIs.
if (mUsingNewApi) {
mCameraAgentNg.closeCamera(mCameraProxy, true);
} else {
// if using API2 ensure API1 usage is also synced
mCameraAgent.closeCamera(mCameraProxy, syncClose);
}
checkAndOpenCamera(mContext, 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;
}
private static void checkAndOpenCamera(Context context, CameraAgent cameraManager,
final int cameraId, Handler handler, final CameraAgent.CameraOpenCallback cb) {
Log.v(TAG, "checkAndOpenCamera");
try {
CameraUtil.throwIfCameraDisabled(context);
//这里调用CameraAgent的openCamera
cameraManager.openCamera(handler, cameraId, cb);
} catch (CameraDisabledException ex) {
handler.post(new Runnable() {
@Override
public void run() {
cb.onCameraDisabled(cameraId);
}
});
}
}
}
CameraAgent.java
public void openCamera(final Handler handler, final int cameraId,
final CameraOpenCallback callback) {
getDispatchThread().runJob(new Runnable() {
@Override
public void run() {
//这里发送CameraActions.OPEN_CAMERA消息,假设我们走的是API1,那AndroidCameraAgentImpl接收消息
getCameraHandler().obtainMessage(CameraActions.OPEN_CAMERA, cameraId, 0,
CameraOpenCallbackForward.getNewInstance(handler, callback)).sendToTarget();
}});
}
AndroidCameraAgentImpl.java
case CameraActions.OPEN_CAMERA: {
final CameraOpenCallback openCallback = (CameraOpenCallback) msg.obj;
final int cameraId = msg.arg1;
//如果camera已经打开则回调onDeviceOpenedAlready
if (mCameraState.getState() != AndroidCameraStateHolder.CAMERA_UNOPENED) {
openCallback.onDeviceOpenedAlready(cameraId, generateHistoryString(cameraId));
break;
}
Log.i(TAG, "Opening camera " + cameraId + " with camera1 API");
//API1中通过camera.java来设置camera,这里通过JNI方法native_setup来启动camera并获取mCamera对象
mCamera = android.hardware.Camera.open(cameraId);
if (mCamera != null) {
mCameraId = cameraId;
//私有类 用来获取Camera.getParameters()
mParameterCache = new ParametersCache(mCamera);
mCharacteristics =
AndroidCameraDeviceInfo.create().getCharacteristics(cameraId);
//初始化camrea设置相关的信息,如果支持功能则加载到AndroidCameraCapabilities的列表中
mCapabilities = new AndroidCameraCapabilities(
mParameterCache.getBlocking());
mCameraState.setState(AndroidCameraStateHolder.CAMERA_IDLE);
//回调onCameraOpened方法,通知camera已经open,并传递参数
if (openCallback != null) {
openCallback.onCameraOpened(
new AndroidCameraProxyImpl(cameraId, mCamera,
mCharacteristics, mCapabilities));
}
} else {
//打开camera失败则回调onDeviceOpenFailure
if (openCallback != null) {
openCallback.onDeviceOpenFailure(cameraId, generateHistoryString(cameraId));
}
}
break;
}
至此camea已经成功打开,并回调Callback的onCameraOpened方法通知上层,我们前面知道Callback是在CameraController.java中传递下来的,
而又是在CameraActivity.java中new的CameraController,所以这个Callback最初是在CameraActivity中传递下去的,现在回头看
CameraActivity.java
public void onCameraOpened(CameraAgent.CameraProxy camera) {
Log.v(TAG, "onCameraOpened");
//界面未显示的话关闭camera
if (mPaused) {
Log.v(TAG, "received onCameraOpened but activity is paused, closing Camera");
mCameraController.closeCamera(false);
return;
}
//这里设置界面上方的一些控件
if (!mSettingsManager.isSet(SettingsManager.SCOPE_GLOBAL,
Keys.KEY_FLASH_SUPPORTED_BACK_CAMERA)) {
HardwareSpec hardware =
new HardwareSpecImpl(getCameraProvider(), camera.getCapabilities());
mSettingsManager.set(SettingsManager.SCOPE_GLOBAL,
Keys.KEY_FLASH_SUPPORTED_BACK_CAMERA,
hardware.isFlashSupported());
}
//此模式不支持camera时关闭camera,一般默认都写成支持
if (!mModuleManager.getModuleAgent(mCurrentModeIndex).requestAppForCamera()) {
// We shouldn't be here. Just close the camera and leave.
mCameraController.closeCamera(false);
throw new IllegalStateException("Camera opened but the module shouldn't be " +
"requesting");
}
//我们这里以PhotoModule为例所以mCurrentModule为PhotoModule
if (mCurrentModule != null) {
//这里将配置写入camera
resetExposureCompensationToDefault(camera);
//调用PhotoModule的onCameraAvailable方法
mCurrentModule.onCameraAvailable(camera);
} else {
Log.v(TAG, "mCurrentModule null, not invoking onCameraAvailable");
}
Log.v(TAG, "invoking onChangeCamera");
mCameraAppUI.onChangeCamera();
}
//对camera进行操作的所有配置最后都会保存在CameraSettings中,在API1中最后通过camera.applySettings(cameraSettings);
//来将CameraSettings中的配置写入camera中。
private void resetExposureCompensationToDefault(CameraAgent.CameraProxy camera) {
// Reset the exposure compensation before handing the camera to module.
CameraSettings cameraSettings = camera.getSettings();
cameraSettings.setExposureCompensationIndex(0);
camera.applySettings(cameraSettings);
}
PhotoModule.java
public void onCameraAvailable(CameraProxy cameraProxy) {
Log.i(TAG, "onCameraAvailable");
if (mPaused) {
return;
}
mCameraDevice = cameraProxy;
//获取一些必要功能是否支持
initializeCapabilities();
// Reset zoom value index.
mZoomValue = 1.0f;
//对焦功能
if (mFocusManager == null) {
initializeFocusManager();
}
mFocusManager.updateCapabilities(mCameraCapabilities);
// Do camera parameter dependent initialization.
mCameraSettings = mCameraDevice.getSettings();
setCameraParameters(UPDATE_PARAM_ALL);
// Set a listener which updates camera parameters based
// on changed settings.
SettingsManager settingsManager = mActivity.getSettingsManager();
settingsManager.addListener(this);
mCameraPreviewParamsReady = true;
//开启预览界面,预览相关流程我会在下篇文章另作分析
startPreview();
onCameraOpened();
}
private void onCameraOpened() {
openCameraCommon();
initializeControlByIntent();
}
private void openCameraCommon() {
//调用PhotoUI的onCameraOpened,主要是设置焦距,这里不展开
mUI.onCameraOpened(mCameraCapabilities, mCameraSettings);
if (mIsImageCaptureIntent) {
// Set hdr plus to default: off.
SettingsManager settingsManager = mActivity.getSettingsManager();
settingsManager.setToDefault(SettingsManager.SCOPE_GLOBAL,
Keys.KEY_CAMERA_HDR_PLUS);
}
//更新拍照模式
updateSceneMode();
}
至此camera的启动流程结束。
本文详细梳理了Android原生Camera2应用的启动流程,从CameraActivity的onCreate开始,逐步讲解如何通过PhotoModule和CameraController初始化相机,并最终在CameraAgent中成功打开相机并回调onCameraOpened方法。整个流程从CameraActivity传递Callback到CameraController,再由CameraActivity新建CameraController,完成相机的启动操作。
397





