网上找的源码是Android 8.0(android-28)SnapdragonCamera App源码,先来看AndroidManifest.xml:
<activity
android:name="com.android.camera.CameraActivity"
android:clearTaskOnLaunch="true"
android:configChanges="orientation|screenSize|keyboardHidden"
android:icon="@mipmap/ic_launcher_camera"
android:label="@string/snapcam_app_name"
android:launchMode="singleTask"
android:logo="@mipmap/ic_launcher_gallery"
android:screenOrientation="portrait"
android:taskAffinity="com.android.camera.CameraActivity"
android:theme="@style/Theme.Camera"
android:windowSoftInputMode="stateAlwaysHidden|adjustPan"
android:visibleToInstantApps="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<meta-data
android:name="com.android.keyguard.layout"
android:resource="@layout/keyguard_widget" />
</activity>
...
<activity-alias
android:name="com.android.camera.CameraLauncher"
android:icon="@mipmap/ic_launcher_camera"
android:label="@string/snapcam_app_name"
android:launchMode="singleTop"
android:targetActivity="com.android.camera.CameraActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
可以看到作为SnapdragonCamera应用显示在Launcher上的入口Activity为CameraLauncher,但实际上却是CameraActivity.java,也就是说这个应用的主要工作都是在CameraActivity中完成。
CameraActivity
从CameraActivity生命周期的的onCreate()方法开始:
onCreate()
// Check if this is in the secure camera mode.
Intent intent = getIntent();
String action = intent.getAction();
if (INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE.equals(action)
|| ACTION_IMAGE_CAPTURE_SECURE.equals(action)
|| intent.getComponent().getClassName().equals(GESTURE_CAMERA_NAME)) {
mSecureCamera = true;
} else {
mSecureCamera = intent.getBooleanExtra(SECURE_CAMERA_EXTRA, false);
}
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);
}
if (mSecureCamera && !hasCriticalPermissions()) {
return;
}
if (isStartRequsetPermission()) {
Log.v(TAG, "onCreate: Missing critical permissions.");
finish();
return;
}
1、判断是否是安全相机,赋值mSecureCamera,当处于安全相机模式下,设置窗口属性;
2、判断相关权限是否已申请,相关权限包括Camera、录音、读写存储权限等:
/**
* Checks if any of the needed Android runtime permissions are missing.
* If they are, then launch the permissions activity under one of the following conditions:
* a) If critical permissions are missing, display permission request again
* b) If non-critical permissions are missing, just display permission request once.
* Critical permissions are: camera, microphone and storage. The app cannot run without them.
* Non-critical permission is location.
*/
private boolean hasCriticalPermissions() {
boolean hasCriticalPermission = false;
if (checkSelfPermission(Manifest.permission.CAMERA) ==
PackageManager.PERMISSION_GRANTED &&
checkSelfPermission(Manifest.permission.RECORD_AUDIO) ==
PackageManager.PERMISSION_GRANTED &&
checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) ==
PackageManager.PERMISSION_GRANTED &&
checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) ==
PackageManager.PERMISSION_GRANTED) {
hasCriticalPermission = true;
} else {
hasCriticalPermission = false;
}
return hasCriticalPermission;
}
3、如果权限未申请,先进入PermissionsActivity申请权限,相关权限包括Camera、录音、读写存储、定位权限等:
private boolean isStartRequsetPermission() {
boolean isStartPermissionActivity = false;
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
boolean isRequestShown = prefs.getBoolean(CameraSettings.KEY_REQUEST_PERMISSION, false);
if(!mSecureCamera && (!isRequestShown || !hasCriticalPermissions())) {
Log.v(TAG, "Start Request Permission");
Intent intent = new Intent(this, PermissionsActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
SharedPreferences.Editor editor = prefs.edit();
editor.putBoolean(CameraSettings.KEY_REQUEST_PERMISSION, true);
editor.apply();
isStartPermissionActivity = true;
}
return isStartPermissionActivity;
}
当权限申请成功后,再次运行CameraActivity:
private void handlePermissionsSuccess() {
if (mIntent != null) {
setRequestPermissionShow();
mIsReturnResult = true;
mIntent.setClass(this, CameraActivity.class);
mIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
startActivity(mIntent);
finish();
} else {
mIsReturnResult = false;
Intent intent = new Intent(this, CameraActivity.class);
startActivity(intent);
finish();
}
}
继续看onCreate()方法:
mCursor = getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
null, null, null, null);
GcamHelper.init(getContentResolver());
getWindow().requestFeature(Window.FEATURE_ACTION_BAR);
LayoutInflater inflater = getLayoutInflater();
View rootLayout = inflater.inflate(R.layout.camera, null, false);
mCameraRootFrame = (FrameLayout)rootLayout.findViewById(R.id.camera_root_frame);
mCameraPhotoModuleRootView = rootLayout.findViewById(R.id.camera_photo_root);
mCameraVideoModuleRootView = rootLayout.findViewById(R.id.camera_video_root);
mCameraPanoModuleRootView = rootLayout.findViewById(R.id.camera_pano_root);
mCameraCaptureModuleRootView = rootLayout.findViewById(R.id.camera_capture_root);
mMultiCameraModuleRootView = rootLayout.findViewById(R.id.multi_camera_root);
1、查询系统MediaStore数据库,初始化mCursor;
2、加载布局R.layout.camera,初始化相关控件;
根据Intent的启动信息及其前一次退出应用前的所处模式判断当前启动的相机模式,初始化moduleIndex:
int moduleIndex = -1;
if (MediaStore.INTENT_ACTION_VIDEO_CAMERA.equals(getIntent().getAction())
|| MediaStore.ACTION_VIDEO_CAPTURE.equals(getIntent().getAction())) {
moduleIndex = ModuleSwitcher.VIDEO_MODULE_INDEX;
} else if (MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA.equals(getIntent().getAction())
|| MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE.equals(getIntent()
.getAction())) {
moduleIndex = ModuleSwitcher.PHOTO_MODULE_INDEX;
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
if (prefs.getInt(CameraSettings.KEY_STARTUP_MODULE_INDEX, -1)
== ModuleSwitcher.GCAM_MODULE_INDEX && GcamHelper.hasGcamCapture()) {
moduleIndex = ModuleSwitcher.GCAM_MODULE_INDEX;
}
} else if (MediaStore.ACTION_IMAGE_CAPTURE.equals(getIntent().getAction())
|| MediaStore.ACTION_IMAGE_CAPTURE_SECURE.equals(getIntent().getAction())) {
moduleIndex = ModuleSwitcher.PHOTO_MODULE_INDEX;
} else {
// If the activity has not been started using an explicit intent,
// read the module index from the last time the user changed modes
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
moduleIndex = prefs.getInt(CameraSettings.KEY_STARTUP_MODULE_INDEX, -1);
if ((moduleIndex == ModuleSwitcher.GCAM_MODULE_INDEX &&
!GcamHelper.hasGcamCapture()) || moduleIndex < 0) {
moduleIndex = ModuleSwitcher.PHOTO_MODULE_INDEX;
}
}
boolean cam2on = PersistUtil.getCamera2Mode();
CameraHolder.setCamera2Mode(this, cam2on);
if (cam2on && (moduleIndex == ModuleSwitcher.PHOTO_MODULE_INDEX ||
moduleIndex == ModuleSwitcher.VIDEO_MODULE_INDEX))
moduleIndex = ModuleSwitcher.CAPTURE_MODULE_INDEX;
从后面几句可以看到,如果当前使用CameraApi2且当前出于拍照模式时,则moduleIndex = ModuleSwitcher.CAPTURE_MODULE_INDEX,即使用CaptureModule.java。
初始化mOrientationListener,接收从SensorManager传输过来的屏幕方向切换的数据:
mOrientationListener = new MyOrientationEventListener(this);
设置CameraActivity界面布局R.layout.camera_filmstrip:
setContentView(R.layout.camera_filmstrip);
mFilmStripView = (FilmStripView) findViewById(R.id.filmstrip_view);
根据刚刚初始化的moduleIndex初始化mCurrentModuleIndex,并创建一个新的Module模式赋值mCurrentModule。这个所谓的Module模式,即我们常说的拍照、录像等模式:
setModuleFromIndex(moduleIndex);
/**
* Sets the mCurrentModuleIndex, creates a new module instance for the given
* index an sets it as mCurrentModule.
*/
private void setModuleFromIndex(int moduleIndex) {
mCameraPhotoModuleRootView.setVisibility(View.GONE);
mCameraVideoModuleRootView.setVisibility(View.GONE);
mCameraPanoModuleRootView.setVisibility(View.GONE);
mCameraCaptureModuleRootView.setVisibility(View.GONE);
mMultiCameraModuleRootView.setVisibility(View.GONE);
mCurrentModuleIndex = moduleIndex;
switch (moduleIndex) {
case ModuleSwitcher.VIDEO_MODULE_INDEX:
if(mVideoModule == null) {
mVideoModule = new VideoModule();
mVideoModule.init(this, mCameraVideoModuleRootView);
} else {
mVideoModule.reinit();
}
mCurrentModule = mVideoModule;
mCameraVideoModuleRootView.setVisibility(View.VISIBLE);
break;
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;
case ModuleSwitcher.WIDE_ANGLE_PANO_MODULE_INDEX:
if(mPanoModule == null) {
mPanoModule = new WideAnglePanoramaModule();
mPanoModule.init(this, mCameraPanoModuleRootView);
}
mCurrentModule = mPanoModule;
mCameraPanoModuleRootView.setVisibility(View.VISIBLE);
break;
case ModuleSwitcher.CAPTURE_MODULE_INDEX:
if(mCaptureModule == null) {
mCaptureModule = new CaptureModule();
mCaptureModule.init(this, mCameraCaptureModuleRootView);
} else {
mCaptureModule.reinit();
}
mCurrentModule = mCaptureModule;
mCameraCaptureModuleRootView.setVisibility(View.VISIBLE);
break;
case ModuleSwitcher.MULTIE_CAMERA_MODULE_INDEX:
if(mMultiCameraModule == null) {
mMultiCameraModule = new MultiCameraModule();
mMultiCameraModule.init(this, mMultiCameraModuleRootView);
} else {
mMultiCameraModule.reinit();
}
mCurrentModule = mMultiCameraModule;
mMultiCameraModuleRootView.setVisibility(View.VISIBLE);
break;
case ModuleSwitcher.PANOCAPTURE_MODULE_INDEX:
final Activity activity = this;
if(!PanoCaptureProcessView.isSupportedStatic()) {
this.runOnUiThread(new Runnable() {
public void run() {
RotateTextToast.makeText(activity, "Panocapture library is missing", Toast.LENGTH_SHORT).show();
}
});
mCurrentModuleIndex = ModuleSwitcher.PHOTO_MODULE_INDEX;
//Let it fall through to photo module
} else {
if (mPano2Module == null) {
mPano2Module = new PanoCaptureModule();
mPano2Module.init(this, mCameraPanoModuleRootView);
}
mCurrentModule = mPano2Module;
mCameraPanoModuleRootView.setVisibility(View.VISIBLE);
break;
}
case ModuleSwitcher.LIGHTCYCLE_MODULE_INDEX: //Unused module for now
case ModuleSwitcher.GCAM_MODULE_INDEX: //Unused module for now
default:
// Fall back to photo mode.
if(mPhotoModule == null) {
mPhotoModule = new PhotoModule();
mPhotoModule.init(this, mCameraPhotoModuleRootView);
} else {
mPhotoModule.reinit();
}
mCurrentModule = mPhotoModule;
mCameraPhotoModuleRootView.setVisibility(View.VISIBLE);
break;
}
}
构建Module对象,并执行相关init()方法;
正常情况下一般初次进入应用时,都是默认出于拍照模式,且由于使用的是CameraAPI2,即初始化CaptureModule,直接来看CaptureModule.java的init()方法:
@Override
public void init(CameraActivity activity, View parent) {
mActivity = activity;
mRootView = parent;
mSettingsManager = SettingsManager.getInstance();
mSettingsManager.createCaptureModule(this);
mSettingsManager.registerListener(this);
if (isBackCameraId()) {
CURRENT_ID = BACK_MODE;
} else {
CURRENT_ID = FRONT_MODE;
}
mSettingsManager.init();
mFirstPreviewLoaded = false;
Log.d(TAG, "init");
for (int i = 0; i < MAX_NUM_CAM; i++) {
mCameraOpened[i] = false;
mTakingPicture[i] = false;
}
for (int i = 0; i < MAX_NUM_CAM; i++) {
mState[i] = STATE_PREVIEW;
}
SceneModule module;
for (int i = 0; i < mSelectableModes.length; i++) {
module = new SceneModule();
module.mode = CameraMode.values()[i];
mSceneCameraIds.add(module);
}
mPostProcessor = new PostProcessor(mActivity, this);
mFrameProcessor = new FrameProcessor(mActivity, this);
mContentResolver = mActivity.getContentResolver();
initModeByIntent();
initCameraIds();
mUI = new CaptureUI(activity, this, parent);
mUI.initializeControlByIntent();
mFocusStateListener = new FocusStateListener(mUI);
mLocationManager = new LocationManager(mActivity, this);
}
执行一些初始化操作,初始化mSettingsManager、判断前后摄、初始化各摄像头状态、根据Intent信息初始化模式设置、初始化CameraID相关信息、构建UI处理对象CaptureUI、初始化mFocusStateListener、mLocationManager;
继续回到onCreate()方法:
初始化mStorage,主要处理图片数据保存:
mStorage = new Storage(this);
继续进行初始化、加载布局等操作,这里不一一赘述;
注册图片、视频数据观察者:
mLocalImagesObserver = new LocalMediaObserver();
mLocalVideosObserver = new LocalMediaObserver();
getContentResolver().registerContentObserver(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI, true,
mLocalImagesObserver);
getContentResolver().registerContentObserver(
MediaStore.Video.Media.EXTERNAL_CONTENT_URI, true,
mLocalVideosObserver);
根据屏幕尺寸计算设置列表的显示宽:
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int width = size.x;
int height = size.y;
int lower = Math.min(width, height);
int offset = lower * 7 / 100;
SETTING_LIST_WIDTH_1 = lower / 2 + offset;
SETTING_LIST_WIDTH_2 = lower / 2 - offset;
注册SD card广播事件接收者,监听SD card状态:
registerSDcardMountedReceiver();
// update the status of storage space when SD card status changed.
private BroadcastReceiver mSDcardMountedReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "SDcard status changed, update storage space");
updateStorageSpaceAndHint();
}
};
private void registerSDcardMountedReceiver() {
// filter for SDcard status
IntentFilter filter = new IntentFilter(Intent.ACTION_MEDIA_MOUNTED);
filter.addAction(Intent.ACTION_MEDIA_SHARED);
filter.addAction(Intent.ACTION_MEDIA_UNMOUNTED);
filter.addDataScheme("file");
registerReceiver(mSDcardMountedReceiver, filter);
}
onStart()
这部分比较简单,主要就是绑定启动MediaSaveService:
@Override
public void onStart() {
super.onStart();
if (mSecureCamera && !hasCriticalPermissions()) {
return;
}
bindMediaSaveService();
mPanoramaViewHelper.onStart();
}
private void bindMediaSaveService() {
Intent intent = new Intent(this, MediaSaveService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
初始化mMediaSaveService,并将其赋值给mCurrentModule:
private MediaSaveService mMediaSaveService;
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className, IBinder b) {
mMediaSaveService = ((MediaSaveService.LocalBinder) b).getService();
mCurrentModule.onMediaSaveServiceConnected(mMediaSaveService);
}
@Override
public void onServiceDisconnected(ComponentName className) {
if (mMediaSaveService != null) {
mMediaSaveService.setListener(null);
mMediaSaveService = null;
}
}
};
onResume()
判断是否申请权限,是否存在可用Camera devices:
if (mSecureCamera && !hasCriticalPermissions()) {
super.onResume();
showOpenCameraErrorDialog();
return;
}
if (isStartRequsetPermission()) {
super.onResume();
Log.v(TAG, "onResume: Missing critical permissions.");
finish();
return;
}
if (!cameraConnected()) {
super.onResume();
Log.v(TAG, "onResume: No camera devices connected.");
finish();
}
实例化mSettingsManager:
mSettingsManager = SettingsManager.getInstance();
if (mSettingsManager == null) {
mSettingsManager = SettingsManager.createInstance(this);
}
private SettingsManager(Context context) {
mListeners = new ArrayList<>();
mCharacteristics = new ArrayList<>();
mPrepNameKeys = new ArrayList<>();
mContext = context;
mPreferences = ComboPreferences.get(mContext);
if (mPreferences == null) {
mPreferences = new ComboPreferences(mContext);
}
upgradeGlobalPreferences(mPreferences.getGlobal(), mContext);
CameraManager manager = (CameraManager) mContext.getSystemService(Context.CAMERA_SERVICE);
try {
String[] cameraIdList = manager.getCameraIdList();
boolean isFirstBackCameraId = true;
boolean isRearCameraPresent = false;
for (int i = 0; i < cameraIdList.length; i++) {
String cameraId = cameraIdList[i];
CameraCharacteristics characteristics
= manager.getCameraCharacteristics(cameraId);
Log.d(TAG,"cameraIdList size ="+cameraIdList.length);
byte monoOnly = 0;
try {
monoOnly = characteristics.get(CaptureModule.MetaDataMonoOnlyKey);
}catch(Exception e) {
}
if (monoOnly == 1) {
CaptureModule.MONO_ID = i;
mIsMonoCameraPresent = true;
}
int facing = characteristics.get(CameraCharacteristics.LENS_FACING);
if (facing == CameraCharacteristics.LENS_FACING_FRONT) {
CaptureModule.FRONT_ID = i;
mIsFrontCameraPresent = true;
}
if (facing == CameraCharacteristics.LENS_FACING_BACK) {
isRearCameraPresent = true;
if (isFirstBackCameraId) {
isFirstBackCameraId = false;
mHasMultiCamera = true;
upgradeCameraId(mPreferences.getGlobal(), i);
}
}
mCharacteristics.add(i, characteristics);
}
if (isRearCameraPresent) {
initPrepNameKeys(CameraCharacteristics.LENS_FACING_BACK);
}
if (mIsFrontCameraPresent) {
initPrepNameKeys(CameraCharacteristics.LENS_FACING_FRONT);
}
} catch (CameraAccessException e) {
e.printStackTrace();
}
mDependency = parseJson("dependency.json");
mHeifWriterSupported = isHeifWriterSupported();
}
public void reloadCharacteristics(int cameraId){
CameraManager manager = (CameraManager) mContext.getSystemService(Context.CAMERA_SERVICE);
try {
CameraCharacteristics characteristics
= manager.getCameraCharacteristics(String.valueOf(cameraId));
mCharacteristics.set(cameraId, characteristics);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
public static SettingsManager createInstance(Context context) {
if (sInstance == null) {
sInstance = new SettingsManager(context.getApplicationContext());
}
return sInstance;
}
public static SettingsManager getInstance() {
return sInstance;
}
初始化、读取所有可用Camera Devices设备信息;
继续回到onResume():
开始监听屏幕方向事件:
mOrientationListener.enable();
调用mCurrentModule的onResumeBeforeSuper()、onResumeAfterSuper()方法,从上面可知初次进入应用时mCurrentModule实为CaptureModule:
mCurrentModule.onResumeBeforeSuper();
super.onResume();
mPaused = false;
mCurrentModule.onResumeAfterSuper();
主要设置界面显示、创建Session等,不做具体赘述,后续再具体分析;
可以看到在CameraActivity的onResume()方法中,最关键的就是mCurrentModule.onResumeBeforeSuper()和mCurrentModule.onResumeAfterSuper(),这两句主要就是用来通知各模式开始处理Camera相关业务逻辑的,如开始预览等。
onPause()
停止监听屏幕方向事件:
mOrientationListener.disable();
在生命周期的这个方法内,最主要的其实也跟onResume()方法内对应,也是这两句:
mCurrentModule.onPauseBeforeSuper();
super.onPause();
mCurrentModule.onPauseAfterSuper();
主要也是用来通知各模式停止处理Camera相关业务逻辑,如停止预览、关闭Camera等操作;
后续分析Camera流程时再详细描述。
onStop()
@Override
protected void onStop() {
super.onStop();
if (mSecureCamera && !hasCriticalPermissions()) {
return;
}
mPanoramaViewHelper.onStop();
unbindMediaSaveService();
}
对应onStart(),解绑MediaSaveService服务;
onDestory()
@Override
public void onDestroy() {
if (mWakeLock != null && mWakeLock.isHeld()) {
mWakeLock.release();
Log.d(TAG, "wake lock release");
}
if (mCursor != null) {
getContentResolver().unregisterContentObserver(mLocalImagesObserver);
getContentResolver().unregisterContentObserver(mLocalVideosObserver);
unregisterReceiver(mSDcardMountedReceiver);
mCursor.close();
mCursor=null;
}
if (mAutoTestEnabled) {
unregisterReceiver(mAutoTestReceiver);
}
if(mCurrentModule != null){
mCurrentModule.onDestroy();
}
super.onDestroy();
}
1、释放电源锁;
2、注销图片、视频等观察者;注销 SDcard广播监听;关闭回收数据库Cursor。
3、通知各模式去进行善后收尾操作。
从上可以看到,CameraActivity逻辑比较简单,只是用来接收一些系统事件,进而通知、调度到各模式,使其各模式自已进行逻辑功能控制。