首先說api1的預覽流程
CameraActivity的onCreate先區分是不是安全模式(鎖屏進入就是安全模式),如果是安全模式會設置flag
indowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED這個flag會在鎖屏的時候顯示出來
if (mSecureCamera) {
// Change the window flags so that secure camera can show when locked
Window win = getWindow();
WindowManager.LayoutParams params = win.getAttributes();
params.flags |= WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
if (intent.getComponent().getClassName().equals(GESTURE_CAMERA_NAME)) {
params.flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
PowerManager pm = ((PowerManager) getSystemService(POWER_SERVICE));
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
mWakeLock.acquire();
Log.d(TAG, "acquire wake lock");
}
win.setAttributes(params);
}
然後給moduleIndex賦值,第一次進入會賦值ModuleSwitcher.PHOTO_MODULE_INDEX
然後這裏會有個api2的選擇,如果你把開發者選項(設置裏的紅眼消除按五下)裏的Camera2 Mode打開就會選擇api2,也就是
moduleIndex 的值賦了 ModuleSwitcher.CAPTURE_MODULE_INDEX;
boolean cam2on = mSettingsManager.isCamera2On();
if (cam2on && moduleIndex == ModuleSwitcher.PHOTO_MODULE_INDEX)
moduleIndex = ModuleSwitcher.CAPTURE_MODULE_INDEX;
然後進入SetModuleFromIndex,通過moduleIndex給實例賦值,這裏以拍照的module爲例,如果是第一次進入就會走
mPhotoModule.init(this, mCameraPhotoModuleRootView);這裏的PhotoModule就是mvc裏的m.
case ModuleSwitcher.PHOTO_MODULE_INDEX:
if (mPhotoModule == null) {
mPhotoModule = new PhotoModule();
mPhotoModule.init(this, mCameraPhotoModuleRootView);
} else {
mPhotoModule.reinit();
}
mCurrentModule = mPhotoModule;
mCameraPhotoModuleRootView.setVisibility(View.VISIBLE);
break;
然後我們進入PhotoModule的init,在進入之前先看一下PhotoModule的定義,實現了10個接口,再看每一個類之前最好有看定義的習慣,能大體的知道這個類裏面都幹了什麼
public class PhotoModule
implements
CameraModule,//拍照,錄像都要實現的接口,裝飾者模式的
PhotoController,// 按鈕的點擊事件處理接口ShutterButton.OnShutterButtonListener
FocusOverlayManager.Listener,//處理所有焦點的類
CameraPreference.OnPreferenceChangedListener,//處理
ShutterButton.OnShutterButtonListener,//按鈕的點擊事件處理接口
MediaSaveService.Listener,//
OnCountDownFinishedListener,//
LocationManager.Listener,//
SensorEventListener,//
MakeupLevelListener {//
現在看init,就是做了初始化ui和開啓openCamera線程.
mUI = new PhotoUI(activity, this, parent);
if (mOpenCameraThread == null) {
mOpenCameraThread = new OpenCameraThread();
mOpenCameraThread.start();
}
這裏的ui就是mvc裏的view,負責顯示所有的控件,包括surfaceview和mSurfaceHolder的初始化
mSurfaceView = (SurfaceView) mRootView.findViewById(R.id.mdp_preview_content);
mSurfaceView.setVisibility(View.VISIBLE);
mSurfaceHolder = mSurfaceView.getHolder();
mSurfaceHolder.addCallback(this);
這裏要說一下SurfaceView和SurfaceHolder,surface的關係,SurfaceView可以理解成比普通的view多個surface,然後SurfaceView通過SurfaceHolder控制surface,surface就是用來顯示camera的圖像的,SurfaceHolder有三個callback,分別是
surfaceChanged(),surface首次顯示在屏幕上調用該方法
surfaceCreated(),surfaceview的視圖層級結構被放到屏幕上時調用該方法
surfaceDestroyed(),surface銷燬時調用
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Log.v(TAG, "surfaceChanged: width =" + width + ", height = " + height);
RectF r = new RectF(mSurfaceView.getLeft(), mSurfaceView.getTop(),
mSurfaceView.getRight(), mSurfaceView.getBottom());
mController.onPreviewRectChanged(CameraUtil.rectFToRect(r));
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
Log.v(TAG, "surfaceCreated");
mSurfaceHolder = holder;
mController.onPreviewUIReady();
mActivity.updateThumbnail(mThumbnail);
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
Log.v(TAG, "surfaceDestroyed");
mSurfaceHolder = null;
mController.onPreviewUIDestroyed();
}
然後我們繼續看mOpenCameraThread,這個thread調用了openCamera
private class OpenCameraThread extends Thread {
@Override
public void run() {
openCamera();
startPreview();
}
}
openCamera裏調用了
mCameraDevice = CameraUtil.openCamera(
mActivity, mCameraId, mHandler,
mActivity.getCameraOpenErrorCallback());
然後CameraUtil裏調用了CameraHolder.instance().open(handler, cameraId, cb);
public static CameraManager.CameraProxy openCamera(
Activity activity, final int cameraId,
Handler handler, final CameraManager.CameraOpenErrorCallback cb) {
try {
throwIfCameraDisabled(activity);
return CameraHolder.instance().open(handler, cameraId, cb);
} catch (CameraDisabledException ex) {
handler.post(new Runnable() {
@Override
public void run() {
cb.onCameraDisabled(cameraId);
}
});
}
return null;
}
CameraHolder的open又調用了
mCameraDevice = CameraManagerFactory .getAndroidCameraManager().cameraOpen(handler, cameraId, cb);
mCameraDevice = CameraManagerFactory
.getAndroidCameraManager().cameraOpen(handler, cameraId, cb);
而這個CameraManagerFactory .getAndroidCameraManager()返回的是AndroidCameraManagerImpl的實例
public class CameraManagerFactory {
private static AndroidCameraManagerImpl sAndroidCameraManager;
/**
* Returns the android camera implementation of {@link CameraManager}.
*
* @return The {@link CameraManager} to control the camera device.
*/
public static synchronized CameraManager getAndroidCameraManager() {
if (sAndroidCameraManager == null) {
sAndroidCameraManager = new AndroidCameraManagerImpl();
}
return sAndroidCameraManager;
}
}
所以openCamera其實最終調用的是AndroidCameraManagerImpl裏的cameraOpen方法,也就是通過反射調用的camera的openLegacy,就是api1的標準接口,現在就和底層通信上了
try {
Method openMethod = Class.forName("android.hardware.Camera").getMethod(
"openLegacy", int.class, int.class);
mCamera = (android.hardware.Camera) openMethod.invoke(
null, msg.arg1, CAMERA_HAL_API_VERSION_1_0);
} catch (Exception e) {
/* Retry with open if openLegacy doesn't exist/fails */
Log.v(TAG, "openLegacy failed due to " + e.getMessage()
+ ", using open instead");
mCamera = android.hardware.Camera.open(msg.arg1);
}
然後子線程繼續調用startPreview,主要做的就是1,把camera和SurfaceHolder綁定上,mCameraDevice.setPreviewDisplay(sh);2,設置camera的參數setCameraParameters. 3開始預覽mCameraDevice.startPreview();
private void startPreview() {
if (mPaused || mCameraDevice == null || mParameters == null) {
return;
}
synchronized (mCameraDevice) {
SurfaceHolder sh = null;
Log.v(TAG, "startPreview: SurfaceHolder (MDP path)");
if (mUI != null) {
sh = mUI.getSurfaceHolder();
}
// Let UI set its expected aspect ratio
mCameraDevice.setPreviewDisplay(sh);//camera和SurfaceHolder綁定上
}
if (!mCameraPreviewParamsReady) {
Log.w(TAG, "startPreview: parameters for preview are not ready.");
return;
}
mErrorCallback.setActivity(mActivity);
mCameraDevice.setErrorCallback(mErrorCallback);
// ICS camera frameworks has a bug. Face detection state is not cleared 1589
// after taking a picture. Stop the preview to work around it. The bug
// was fixed in JB.
if (mCameraState != PREVIEW_STOPPED && mCameraState != INIT) {
stopPreview();
}
if (!mSnapshotOnIdle) {
mFocusManager.setAeAwbLock(false); // Unlock AE and AWB.
}
setCameraParameters(UPDATE_PARAM_ALL);
mCameraDevice.setOneShotPreviewCallback(mHandler,
new CameraManager.CameraPreviewDataCallback() {
@Override
public void onPreviewFrame(byte[] data, CameraProxy camera) {
mUI.hidePreviewCover();
}
});
Log.w("fy","startPreview--"+Log.getStackTraceString(new Throwable()));
mCameraDevice.startPreview();
mHandler.sendEmptyMessage(ON_PREVIEW_STARTED);
setDisplayOrientation();
if (!mSnapshotOnIdle && !mInstantCaptureSnapShot) {
// If the focus mode is continuous autofocus, call cancelAutoFocus to
// resume it because it may have been paused by autoFocus call.
if (CameraUtil.FOCUS_MODE_CONTINUOUS_PICTURE.equals(mFocusManager.getFocusMode())) {
mCameraDevice.cancelAutoFocus();
}
} else {
Log.v(TAG, "Trigger snapshot from start preview.");
mHandler.post(mDoSnapRunnable);
}
}
這裏的setCameraParameters會調用了updateCameraParametersPreference,主要的功能就是將數據庫中的數據
PictureSize,PreviewSize,flash,照片質量等數據設置給camera,mCameraDevice.setParameters(mParameters);
這個時候主線程也同時調用cameraActivity的onResume,會調用mCurrentModule.onResumeBeforeSuper();和
mCurrentModule.onResumeAfterSuper();
@Override
public void onResume() {
...
mCurrentModule.onResumeBeforeSuper();
super.onResume();
mPaused = false;
mCurrentModule.onResumeAfterSuper();
在PhotoModule的onResumeAfterSuper裏調用了onResumeTasks();
@Override
public void onResumeAfterSuper() {
mLastPhotoTakenWithRefocus = false;
mUI.showSurfaceView();
// 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.
String action = mActivity.getIntent().getAction();
if (MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA.equals(action)
|| MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE.equals(action)) {
Log.v(TAG, "On resume, from lock screen.");
// Check if there is a need to take a snapshot without
// waiting for the shutter click
if (isInstantCaptureEnabled()) {
mInstantCaptureSnapShot = true;
}
// Note: onPauseAfterSuper() will delete this runnable, so we will
// at most have 1 copy queued up.
mHandler.postDelayed(new Runnable() {
public void run() {
onResumeTasks();
}
}, ON_RESUME_TASKS_DELAY_MSEC);
} else {
Log.v(TAG, "On resume.");
onResumeTasks();
}
而onResumeTasks裏主要是調用了initializeSecondTime,作用是初始化MediaSaveService和NameImage用來保存的
private void initializeSecondTime() {
// Start location update if needed.
boolean recordLocation = RecordLocationPreference.get(mPreferences);
mLocationManager.recordLocation(recordLocation);
MediaSaveService s = mActivity.getMediaSaveService();
if (s != null) {
s.setListener(this);
}
mNamedImages = new NamedImages();
if (!mIsImageCaptureIntent) {
mUI.showSwitcher();
}
mUI.initializeSecondTime(mParameters);
}
這樣預覽的整個流程就走下來了。
總結:
1在xml佈局中定義一個SurfaceView,用於預覽相機採集的數據
2給SurfaceHolder添加回調,在surfaceCreated(holder: SurfaceHolder?)回調中打開相機
3成功打開相機後,設置相機參數。比如:對焦模式,預覽大小,照片保存大小等等
4設置相機預覽時的旋轉角度,然後調用startPreview()開始預覽
拍照流程先看ShutterButton的performClick,調用了mListener.onShutterButtonClick();
@Override
public boolean performClick() {
boolean result = super.performClick();
if (mListener != null && getVisibility() == View.VISIBLE) {
mListener.onShutterButtonClick();
}
return result;
}
而PhotoModule實現了這個接口,最終調用了PhotoModule的onShutterButtonClick
先看是不是倒計時拍照,不是就調用initiateSnap();
@Override
public synchronized void onShutterButtonClick() {
...
String timer = mPreferences.getString(
CameraSettings.KEY_TIMER,
mActivity.getString(R.string.pref_camera_timer_default));
boolean playSound = mPreferences.getString(CameraSettings.KEY_TIMER_SOUND_EFFECTS,
mActivity.getString(R.string.pref_camera_timer_sound_default))
.equals(mActivity.getString(R.string.setting_on_value));
int seconds = Integer.parseInt(timer);
// When shutter button is pressed, check whether the previous countdown is
// finished. If not, cancel the previous countdown and start a new one.
if (mUI.isCountingDown()) {
mUI.cancelCountDown();
}
if (seconds > 0) {
String zsl = mPreferences.getString(CameraSettings.KEY_ZSL,
mActivity.getString(R.string.pref_camera_zsl_default));
mUI.overrideSettings(CameraSettings.KEY_ZSL, zsl);
mUI.startCountDown(seconds, isShutterSoundOn());
} else {
mSnapshotOnIdle = false;
initiateSnap();
}
}
然後在initiateSnap中要看是不是自拍,是自拍要啓線程調用mFocusManager.doSnap();不是自拍直接調用mFocusManager.doSnap()
private void initiateSnap() {
if (mPreferences.getString(CameraSettings.KEY_SELFIE_FLASH,
mActivity.getString(R.string.pref_selfie_flash_default))
.equalsIgnoreCase("on") &&
mCameraId == CameraHolder.instance().getFrontCameraId()) {//自拍閃光燈
mUI.startSelfieFlash();
if (selfieThread == null) {
selfieThread = new SelfieThread();
selfieThread.start();
}
} else {
mFocusManager.doSnap();
}
}
然後doSnap會調用capture,會最終調用mListener.capture().
public void doSnap() {
if (!mInitialized) return;
// If the user has half-pressed the shutter and focus is completed, we
// can take the photo right away. If the focus mode is infinity, we can
// also take the photo.
if (!needAutoFocusCall() || (mState == STATE_SUCCESS || mState == STATE_FAIL)) {
capture();
} else if (mState == STATE_FOCUSING) {
// Half pressing the shutter (i.e. the focus button event) will
// already have requested AF for us, so just request capture on
// focus here.
mState = STATE_FOCUSING_SNAP_ON_FINISH;
} else if (mState == STATE_IDLE) {
// We didn't do focus. This can happen if the user press focus key
// while the snapshot is still in progress. The user probably wants
// the next snapshot as soon as possible, so we just do a snapshot
// without focusing again.
capture();
}
}
這個mListener是PhotoModule,所以調用了PhotoModule的capture()
首先調用了mCaptureStartTime = System.currentTimeMillis();記錄系統的當前時間
mReceivedSnapNum = 0;是當前的張數,最終調用了mCameraDevice.takePicture(mHandler, new ShutterCallback(!animateBefore), mRawPictureCallback, mPostViewPictureCallback, new JpegPictureCallback(loc));
@Override
public boolean capture() {
// If we are already in the middle of taking a snapshot or the image save request
// is full then ignore.
Log.w(TAG,"capture");
if (mCameraDevice == null || mCameraState == SNAPSHOT_IN_PROGRESS
|| mCameraState == SWITCHING_CAMERA
|| mActivity.getMediaSaveService() == null
|| mActivity.getMediaSaveService().isQueueFull()) {
return false;
}
mCaptureStartTime = System.currentTimeMillis();
mPostViewPictureCallbackTime = 0;
mJpegImageData = null;
final boolean animateBefore = (mSceneMode == CameraUtil.SCENE_MODE_HDR);
if(mHiston) {
if (mSnapshotMode != CameraInfo.CAMERA_SUPPORT_MODE_ZSL) {
mHiston = false;
mCameraDevice.setHistogramMode(null);
}
mActivity.runOnUiThread(new Runnable() {
public void run() {
if(mGraphView != null)
mGraphView.setVisibility(View.INVISIBLE);
}
});
}
if (animateBefore) {
animateAfterShutter();
}
if (mCameraState == LONGSHOT) {
mCameraDevice.setLongshot(true);
}
// Set rotation and gps data.
int orientation = mOrientation;
mJpegRotation = CameraUtil.getJpegRotation(mCameraId, orientation);
String pictureFormat = mParameters.get(KEY_PICTURE_FORMAT);
Location loc = getLocationAccordPictureFormat(pictureFormat);
synchronized (mCameraDevice) {
if (mCameraId == CAMERA_ID_MAIN) {
mParameters.setFlashMode(Parameters.FLASH_MODE_OFF);
}
mParameters.setRotation(mJpegRotation);
CameraUtil.setGpsParameters(mParameters, loc);
if (mRefocus) {
mParameters.set(CameraSettings.KEY_QC_LEGACY_BURST,
CameraSettings.KEY_QC_RE_FOCUS_COUNT);
} else {
mParameters.remove(CameraSettings.KEY_QC_LEGACY_BURST);
}
// Unlock AE&AWB, if they continue
// to be locked during snapshot, then
// side effects could be triggered w.r.t.
// flash.
mFocusManager.setAeAwbLock(false);
setAutoExposureLockIfSupported();
setAutoWhiteBalanceLockIfSupported();
mCameraDevice.setParameters(mParameters);
mParameters = mCameraDevice.getParameters();
}
mBurstSnapNum = mParameters.getInt("num-snaps-per-shutter");
mReceivedSnapNum = 0;
mPreviewRestartSupport = SystemProperties.getBoolean(
PERSIST_PREVIEW_RESTART, false);
mPreviewRestartSupport &= CameraSettings.isInternalPreviewSupported(
mParameters);
mPreviewRestartSupport &= (mBurstSnapNum == 1);
// Restart is needed if HDR is enabled
mPreviewRestartSupport &= !CameraUtil.SCENE_MODE_HDR.equals(mSceneMode);
mPreviewRestartSupport &= PIXEL_FORMAT_JPEG.equalsIgnoreCase(
pictureFormat);
// We don't want user to press the button again while taking a
// multi-second HDR photo. For longshot, no need to disable.
if (mCameraState != LONGSHOT) {
mUI.enableShutter(false);
}
if (!isShutterSoundOn()) {
mCameraDevice.enableShutterSound(false);
} else {
mCameraDevice.enableShutterSound(!mRefocus);
}
Log.w(TAG,"mCameraState="+mCameraState);
if (mCameraState == LONGSHOT) {
mLongShotCaptureCountLimit = SystemProperties.getInt(
"persist.camera.longshot.shotnum", 0);
mLongShotCaptureCount = 1;
Log.w(TAG,"mLongshotSave1="+mLongshotSave);
if(mLongshotSave) {
mCameraDevice.takePicture(mHandler,
new LongshotShutterCallback(),
mRawPictureCallback, mPostViewPictureCallback,
new LongshotPictureCallback(loc));
} else {
mCameraDevice.takePicture(mHandler,
new LongshotShutterCallback(),
mRawPictureCallback, mPostViewPictureCallback,
new JpegPictureCallback(loc));
}
} else {
mCameraDevice.takePicture(mHandler,
new ShutterCallback(!animateBefore),
mRawPictureCallback, mPostViewPictureCallback,
new JpegPictureCallback(loc));
setCameraState(SNAPSHOT_IN_PROGRESS);
}
mNamedImages.nameNewImage(mCaptureStartTime, mRefocus);
if (mSnapshotMode != CameraInfo.CAMERA_SUPPORT_MODE_ZSL) {
mFaceDetectionStarted = false;
}
UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA,
UsageStatistics.ACTION_CAPTURE_DONE, "Photo", 0,
UsageStatistics.hashFileName(mNamedImages.mQueue.lastElement().title + ".jpg"));
return true;
}
這裏的takePicture(shutter, raw, postView, jpeg)裏面的參數分別是
shutter是在加工處理原始圖像數據且沒有存儲之前,圖像捕捉時刻的回調,或爲空
raw原始(未壓縮)圖像數據的回調
postview包含postview圖像數據的回調(一般需要硬件支持)
jpeg jpeg圖像數據的回調
驍龍camera裏只實現了shutter和jpeg數據的回調,shutter主要做的事情