目录
1.检查进入的方式:launchCamera,然后打开后摄像头。
一、UI界面加载分析
(1)host/AndroidManifest.xml
<activity
android:name="com.mediatek.camera.CameraActivity"
android:clearTaskOnLaunch="true"
android:screenOrientation="portrait"
android:configChanges="orientation|screenSize|keyboardHidden|mnc|mcc|smallestScreenSize|uiMode|screenLayout|navigation|keyboard|touchscreen"
android:label="@string/camera_label"
android:launchMode="singleTask"
android:taskAffinity="com.mediatek.camera.CameraActivity"
android:windowSoftInputMode="stateAlwaysHidden|adjustPan">
入口Activity:CameraActivity,利用Actvity的生命周期进入分析
(2)host/src/com/mediatek/camera/CameraActivity.java
public class CameraActivity extends PermissionActivity implements IApp {
}
public abstract class PermissionActivity extends QuickActivity implements
ActivityCompat.OnRequestPermissionsResultCallback {
}
public abstract class QuickActivity extends AppCompatActivity {
}
由此继承关系可知cameraActivity继承自QuickActivity,分析QcickActivity的生命周期
(3)代码执行顺序:
onCreate QuickActivity
onPermissionCreateTasks PermissionActivity
onCreateTasks CameraActivity
mCameraAppUI.onCreate(); CameraActivity
(4)setContentView(R.layout.activity_main);///mCameraAppUI.onCreate();加载布局
/**
* Called when activity's onCreate() is invoked.
*/
public void onCreate() {
ViewGroup rootView = (ViewGroup) mApp.getActivity()
.findViewById(R.id.app_ui_root);
ViewGroup parentView = (ViewGroup) mApp.getActivity().getLayoutInflater()
.inflate(R.layout.camera_ui_root, rootView, true);
View appUI = parentView.findViewById(R.id.camera_ui_root);
if (CameraUtil.isHasNavigationBar(mApp.getActivity())) {
//get navigation bar height.
int navigationBarHeight = CameraUtil.getNavigationBarHeight(mApp.getActivity());
//set root view bottom margin to let the UI above the navigation bar.
FrameLayout.LayoutParams params =
(FrameLayout.LayoutParams) appUI.getLayoutParams();
if (CameraUtil.isTablet()) {
int displayRotation = CameraUtil.getDisplayRotation(mApp.getActivity());
LogHelper.d(TAG, " onCreate displayRotation " + displayRotation);
if (displayRotation == 90 || displayRotation == 270) {
params.leftMargin += navigationBarHeight;
appUI.setLayoutParams(params);
} else {
params.bottomMargin += navigationBarHeight;
appUI.setLayoutParams(params);
}
} else {
params.bottomMargin += navigationBarHeight;
appUI.setLayoutParams(params);
}
}
mModeProvider = new ModeProvider();
String action = mApp.getActivity().getIntent().getAction();
mGestureManager = new GestureManager(mApp.getActivity());
mAnimationManager = new AnimationManager(mApp, this);
mShutterManager = new ShutterButtonManager(mApp, parentView);
mShutterManager.setVisibility(View.VISIBLE);
mShutterManager.setOnShutterChangedListener(new OnShutterChangeListenerImpl());
mViewManagers.add(mShutterManager);
if (!(MediaStore.ACTION_IMAGE_CAPTURE.equals(action)
|| MediaStore.ACTION_VIDEO_CAPTURE.equals(action))) {
mThumbnailViewManager = new ThumbnailViewManager(mApp, parentView);
mViewManagers.add(mThumbnailViewManager);
mThumbnailViewManager.setVisibility(View.VISIBLE);
}
mPreviewManager = new PreviewManager(mApp);
//Set gesture listener to receive touch event.
mPreviewManager.setOnTouchListener(new OnTouchListenerImpl());
mModePickerManager = new ModePickerManager(mApp, parentView);
mModePickerManager.setSettingClickedListener(new OnSettingClickedListenerImpl());
mModePickerManager.setModeChangeListener(new OnModeChangedListenerImpl());
mModePickerManager.setVisibility(View.VISIBLE);
mViewManagers.add(mModePickerManager);
mQuickSwitcherManager = new QuickSwitcherManager(mApp, parentView);
mQuickSwitcherManager.setVisibility(View.VISIBLE);
mViewManagers.add(mQuickSwitcherManager);
mIndicatorViewManager = new IndicatorViewManager(mApp, parentView);
mIndicatorViewManager.setVisibility(View.VISIBLE);
mViewManagers.add(mIndicatorViewManager);
mSettingFragment = new SettingFragment();
mSettingFragment.setStateListener(new SettingStateListener());
layoutSettingUI();
mEffectViewManager = new EffectViewManager(mApp, parentView);
mEffectViewManager.setVisibility(View.VISIBLE);
mViewManagers.add(mEffectViewManager);
mOnScreenHintManager = new OnScreenHintManager(mApp, parentView);
//call each manager's onCreate()
for (int count = 0; count < mViewManagers.size(); count ++) {
mViewManagers.get(count).onCreate();
}
mApp.registerOnOrientationChangeListener(mOrientationChangeListener);
}
二、camera 初始化
1.检查进入的方式:launchCamera,然后打开后摄像头。
初始化cameraID为0,检查camera的api等级,初始化设置成photomode,然后打开camera
public static void launchCamera(Activity activity) {
LogHelper.d(TAG, "[launchCamera]+");
String defaultMode = "com.mediatek.camera.common.mode.photo.PhotoMode";
String cameraId = "0";
CameraDeviceManagerFactory.CameraApi apiType =
CameraApiHelper.getCameraApiType(null);
//TODO enable API2, remove this
if (CameraApi.API2.equals(apiType)) {
LogHelper.w(TAG, "[launchCamera]- API2 current not support preWarm open camera.");
return;
}
FeatureLoader.updateSettingCurrentModeKey(activity, defaultMode);
CameraDeviceManagerFactory deviceManagerFactory = CameraDeviceManagerFactory.getInstance();
try {
deviceManagerFactory.getCameraDeviceManager(activity, apiType).openCamera(
cameraId, null, null);
} catch (CameraOpenException e) {
LogHelper.e(TAG, "[launchCamera] e:" + e);
e.printStackTrace();
}
LogHelper.i(TAG, "[launchCamera]- id:" + cameraId + ", api:" + apiType);
}
检查打开camera的前提条件并打开camera:
common/src/com/mediatek/camera/common/device/v2/Camera2DeviceManagerImpl.java
@Override
public void openCamera(@Nonnull String cameraId, @Nonnull CameraStateCallback callback,
@Nullable Handler handler) throws CameraOpenException {
LogHelper.i(TAG, "[openCamera] cameraId = " + cameraId);
checkPreconditionsAndOpen(cameraId, callback, false);//isSync=flase
}
private void checkPreconditionsAndOpen(String cameraId, CameraStateCallback callback,
boolean isSync) throws CameraOpenException {
checkDevicePolicy();//检查权限
LogHelper.d(TAG, "[checkPreconditions] mProxyCreatorMap size = " + mProxyCreatorMap.size());
Camera2ProxyCreatorImpl proxyCreator = mProxyCreatorMap.get(cameraId);
if (proxyCreator == null) {
proxyCreator = new Camera2ProxyCreatorImpl(cameraId);
mProxyCreatorMap.put(cameraId, proxyCreator);
}
if (isSync) {
proxyCreator.doOpenCameraSync(callback);
} else {
proxyCreator.doOpenCamera(callback);
}
}
private void doOpenCamera(CameraStateCallback callback) {
mOpenHandler.obtainMessage(
RespondCameraHandler.MSG_OPEN_CAMERA, callback).sendToTarget();
}
common/src/com/mediatek/camera/common/device/v2/Camera2DeviceManagerImpl.java
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case MSG_OPEN_CAMERA:
LogHelper.d(TAG, "handle open camera msg +");
Camera2Proxy.StateCallback stateCallback
= (Camera2Proxy.StateCallback) msg.obj;
mOpenStateCallback =
stateCallback == null ? mDummyCameraStateCallback : stateCallback;
if (mCamera2Proxy == null) {
openCamera();
}
if (mCameraDevice != null) {
mOpenStateCallback.onOpened(mCamera2Proxy);
}
LogHelper.d(TAG, "handle open camera msg -");
break;
default:
break;
}
}
private void openCamera() {
try {
mIsOnOpenCallback = false;
mCameraManager.openCamera(mCameraId, mStateCallback, mRespondHandler);
waitStateCallback();
} catch (CameraAccessException e) {
LogHelper.e(mHandlerTag, "[openCamera] error:" + e.getMessage());
doOpenException();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
2.进入预览模式
1.加载基本布局
setContentView(R.layout.activity_main);
mCameraAppUI.onCreate();
2.基本配置加载
mIModeListener.create(this);
@Override
public void create(@Nonnull IApp app) {
LogHelper.d(TAG, "[create]+");
CameraSysTrace.onEventSystrace("ModeManager.create", true, true);
mApp = app;
HandlerThread th = new HandlerThread("mode thread",
android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY);
th.start();
mModeHandler = new ModeHandler(th.getLooper());
CameraSysTrace.onEventSystrace("CameraContext.create", true);
mCameraContext = new CameraContext();
mCameraContext.create(mApp, mApp.getActivity());
CameraSysTrace.onEventSystrace("CameraContext.create", false);
mAppUi = app.getAppUi();
mAppUi.setModeChangeListener(this);
String defaultModeKey = getDefaultModeKey();
LogHelper.i(TAG, "[create], default mode:" + defaultModeKey);
mNewMode = createMode(defaultModeKey);
mModeHandler.obtainMessage(MSG_MODE_INIT,
new MsgParam(mNewMode, true)).sendToTarget();
//this can't be after mOldMode = mNewMode;
mCurrentModeDeviceUsage = createDeviceUsage(mNewMode);
mCurrentCameraApi = mNewMode.getCameraApi();
mOldMode = mNewMode;
mCameraContext.getFeatureProvider().registerFeatureLoadDoneListener(mPluginLoadListener);
CameraSysTrace.onEventSystrace("ModeManager.create", false, true);
LogHelper.d(TAG, "[create]-");
}
(1)mCameraContext.create(mApp, mApp.getActivity());
@Override
public void create(IApp app, Activity activity) {
mActivity = activity;
mSoundPlayback = new SoundPlaybackImpl(activity);//声音
mLocationManager = new LocationManager(activity);//位置
mMediaSaver = new MediaSaver(activity);//保存视频图片
mDataStore = new DataStore(activity);//shared preferences
mStatusMonitorFactory = new StatusMonitorFactory();
mFeatureProvider = new FeatureProvider(app);//提供加载moudles
mCameraDeviceManagerFactory = CameraDeviceManagerFactory.getInstance();
mSettingManagerFactory = new SettingManagerFactory(app, this);
mStorageService = new StorageServiceImpl(app, this);//保存位置
mThermalThrottle = new ThermalThrottle(app);
boolean isForceDisableBGService =
SystemProperties.getInt("vendor.debug.camera.bgservice.mode", 0) == 2
? true : false;
DeviceDescription deviceDescription = CameraApiHelper.getDeviceSpec(
mActivity.getApplicationContext()).getDeviceDescriptionMap().get("0");//获取spec
if (deviceDescription != null) {
mIsBGServiceEnabled = deviceDescription.isBGServiceSupport()
&& !isForceDisableBGService;
}
if (mIsBGServiceEnabled) {
mBGServiceKeeper = ((CameraApplication) mActivity.getApplication())
.getBGServiceKeeper(this);
}
mCamPostAlgo = new CamPostAlgo();
if (CameraUtil.getAppVersionLevel() == MTK_CAMERA_APP_VERSION_SEVEN) {
//start camerapostalgo service in background thread since the service start slowly
startBGCamPostAlgoThread();
}
}
视频图片存储位置初始化:
public StorageServiceImpl(IApp app, CameraContext cameraContext) {
mStorage = Storage.getStorage(app.getActivity());
mStorageMonitor = new StorageMonitor(app.getActivity(), mStorage);
mStorage.updateDefaultDirectory();///
mApp = app;
mAppUi = app.getAppUi();
cameraContext.getMediaSaver().addMediaSaverListener(mMediaSaverListener);
mStorageHint = new IAppUi.HintInfo();
int id = app.getActivity().getResources().getIdentifier("hint_text_background",
"drawable", app.getActivity().getPackageName());
mStorageHint.mBackground = app.getActivity().getDrawable(id);
mStorageHint.mType = IAppUi.HintType.TYPE_ALWAYS_BOTTOM;
}
private static final String DCIM_CAMERA_FOLDER_ABSOLUTE_PATH =
Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DCIM).toString() + "/Camera";
(2)获取spec
DeviceDescription deviceDescription = CameraApiHelper.getDeviceSpec(mActivity.getApplicationContext()).getDeviceDescriptionMap().get("0");//获取spec
@SuppressWarnings("deprecation")
private static void createDeviceSpec(Context context) {
if (!sForceCreate && sDeviceSpec.getDefaultCameraApi() != null) {
return;
}
LogHelper.i(TAG, "[createDeviceSpec]+");
CameraApi defaultCameraApi = getCameraApiType(null);//获取api等级
int cameraNum = 0;
String[] idList = null;
try {
idList = CameraUtil.getCameraManager(context).getCameraIdList();//获取cameraId
} catch (Exception e) {
e.printStackTrace();
LogHelper.e(TAG, "[createDeviceSpec] camera id list null");
}
if (idList == null || idList.length == 0) {
LogHelper.e(TAG, "camera process killed due to camera num is 0," +
" mostly camerahalserver happened some error" +
" and still in progress of relaunch");
Process.killProcess(Process.myPid());
}
cameraNum = idList.length;
ConcurrentHashMap<String, DeviceDescription>
deviceDescriptionMap = new ConcurrentHashMap<>();
if (cameraNum > 0) {
for (String id : idList) {
DeviceDescription deviceDescription = new DeviceDescription(null);//camera信息
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
CameraCharacteristics characteristics = CameraUtil.getCharatics(context, id);
if (characteristics != null) {
deviceDescription.setCameraCharacteristics(characteristics);
deviceDescription.storeCameraCharacKeys(characteristics);
CameraUtil.initLogicalCameraId(deviceDescription, id);
}
}
deviceDescriptionMap.put(id, deviceDescription);
}
sDeviceSpec.setDefaultCameraApi(defaultCameraApi);
sDeviceSpec.setDeviceDescriptions(deviceDescriptionMap);
}
LogHelper.i(TAG, "[createDeviceSpec]- context: " + context + ", default api:"
+ defaultCameraApi + ", deviceDescriptionMap:"
+ deviceDescriptionMap + " cameraNum " + cameraNum);
}
(3)初始化entrykey,FeatureProvider
mNewMode = createMode(defaultModeKey);
...
mCurrentModeDeviceUsage = createDeviceUsage(mNewMode);
/************************************************************************************************/
private ICameraMode createMode(String entryKey) {
String tempEntryKey = entryKey;
ICameraMode cameraMode = mCameraContext.getFeatureProvider().getInstance(
new FeatureProvider.Key<>(tempEntryKey, ICameraMode.class),
null,
false);
// if current entry key can not create mode, back to default camera mode.
if (cameraMode == null) {
tempEntryKey = DEFAULT_CAPTURE_MODE;
cameraMode = mCameraContext.getFeatureProvider().getInstance(
new FeatureProvider.Key<>(tempEntryKey, ICameraMode.class),
null,
false); // don't check support, because camera may not opened.
}
mCurrentEntryKey = tempEntryKey;
mCameraContext.getFeatureProvider().updateCurrentModeKey(cameraMode.getModeKey());
LogHelper.i(TAG, "[createMode] entryKey:" + mCurrentEntryKey);
return cameraMode;
}
/************************************************************************************************/
private DeviceUsage createDeviceUsage(ICameraMode currentMode) {
if (mOldMode != null) {
//update current old mode device usage again.
mCurrentModeDeviceUsage = mOldMode.getDeviceUsage(mCameraContext.getDataStore(), null);
mCurrentModeDeviceUsage = mCameraContext.getFeatureProvider().updateDeviceUsage(
mOldMode.getModeKey(), mCurrentModeDeviceUsage);
}
DeviceUsage newDeviceUsage = currentMode.getDeviceUsage(mCameraContext.getDataStore(),
mCurrentModeDeviceUsage);
String modeKey = currentMode.getModeKey();
return mCameraContext.getFeatureProvider().updateDeviceUsage(modeKey, newDeviceUsage);
}
/************************************************************************************************/
common/src/com/mediatek/camera/common/loader/FeatureProvider.java
public DeviceUsage updateDeviceUsage(String modeKey, DeviceUsage originalDeviceUsage) {
LogHelper.d(TAG, "[updateDeviceUsage] mode key:" + modeKey +
", device type:" + originalDeviceUsage.getDeviceType());
DeviceUsage tempDeviceUsage = originalDeviceUsage;
Iterator iterator = mBuildInEntries.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry item = (Map.Entry) iterator.next();
IFeatureEntry entry = (IFeatureEntry) item.getValue();
if (ICameraSetting.class.equals(entry.getType())) {
tempDeviceUsage =
entry.updateDeviceUsage(modeKey, tempDeviceUsage);
}
}
return tempDeviceUsage;
}
/************************************************************************************************/
(4)模式初始化
...
switch (msg.what) {
case MSG_MODE_INIT:
Boolean isFromLaunch = (Boolean) param.mObj;
CameraSysTrace.onEventSystrace("ModeManager.ModeInit", true);
param.mMode.init(mApp, mCameraContext, isFromLaunch.booleanValue());
CameraSysTrace.onEventSystrace("ModeManager.ModeInit", false);
break;
....
}
(5)get All Mode Items
mCameraContext.getFeatureProvider().registerFeatureLoadDoneListener(mPluginLoadListener);
private class FeatureLoadListener implements FeatureLoadDoneListener {
@Override
public void onBuildInLoadDone(String cameraId, CameraApi cameraApi) {
LogHelper.d(TAG, "[onBuildInLoadDone]+ api:" + cameraApi +
", current api:" + mCurrentCameraApi +
",camId:" + cameraId);
List<IAppUi.ModeItem> modeItems = new ArrayList<>();
if (cameraApi.equals(mCurrentCameraApi)) {
modeItems =
mCameraContext.getFeatureProvider().getAllModeItems(mCurrentCameraApi);//重点
if (modeItems.size() > 0) {
mAppUi.registerMode(modeItems);
mAppUi.updateCurrentMode(mCurrentEntryKey);
}
}
LogHelper.d(TAG, "[onBuildInLoadDone]- modes:" + modeItems.size());
}
@Override
public void onPluginLoadDone(String cameraId, CameraApi cameraApi) {
LogHelper.d(TAG, "[onPluginLoadDone]+ api:" + cameraApi +
", current api:" + mCurrentCameraApi +
",camId:" + cameraId);
List<IAppUi.ModeItem> modeItems = new ArrayList<>();
if (cameraApi.equals(mCurrentCameraApi)) {
modeItems =
mCameraContext.getFeatureProvider().getAllModeItems(mCurrentCameraApi);
if (modeItems.size() > 0) {
mAppUi.registerMode(modeItems);
mAppUi.updateCurrentMode(mCurrentEntryKey);
}
}
LogHelper.d(TAG, "[onPluginLoadDone]- mode num:" + modeItems.size());
}
}
/**
* Get all the mode items.you must be after the onPluginLoadDone() notify done.
* @param currentCameraApi current camera api.
* @return all the mode items.
*/
public List<ModeItem> getAllModeItems(@Nonnull CameraApi currentCameraApi) {
ArrayList list = new ArrayList();
// get the values from hashMap use iterator method.
Iterator iterator = mAllEntries.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry item = (Map.Entry) iterator.next();
IFeatureEntry entry = (IFeatureEntry) item.getValue();
if (entry.isSupport(currentCameraApi, mActivity)) { //重要
ModeItem modeItem = entry.getModeItem();
if (modeItem != null) {
list.add(modeItem);
}
}
}
return list;
}
乱七八糟:
/********************************************************************************************************/
1.加载初始化默认模式:getDefaultModeKey:
com.mediatek.camera.common.mode.photo.PhotoModeEntry
mIModeListener.create(this);
@Override
public void create(@Nonnull IApp app) {
LogHelper.d(TAG, "[create]+");
mApp = app;
mCameraContext = new CameraContext();
mCameraContext.create(mApp, mApp.getActivity());
mAppUi = app.getAppUi();
mAppUi.setModeChangeListener(this);
String defaultModeKey = getDefaultModeKey();
LogHelper.i(TAG, "[create], default mode:" + defaultModeKey);
mNewMode = createMode(defaultModeKey);
//this can't be after mOldMode = mNewMode;
mCurrentModeDeviceUsage = createDeviceUsage(mNewMode);
mCurrentCameraApi = mNewMode.getCameraApi();
mOldMode = mNewMode;
mCameraContext.getFeatureProvider().registerFeatureLoadDoneListener(mPluginLoadListener);
mNewMode.init(mApp, mCameraContext, true);
LogHelper.d(TAG, "[create]-");
}
2.初始化加载cameraServices,设置MODE_CAMERA。更新mode的entry
private void startPreWarmService() {
if (!CameraUtil.isServiceRun(getApplicationContext(),
"com.mediatek.camera.CameraAppService")) {
Intent appServiceIntent = new Intent(getApplicationContext(),
CameraAppService.class);
CameraUtil.startService(getApplicationContext(), appServiceIntent);
}
}
public static void enterCameraMode() {
PictureQuality.setMode(PictureQuality.MODE_CAMERA);
}
@Override
public void resume() {
LogHelper.i(TAG, "[resume]");
mCameraContext.resume();
mResumed = true;
mCameraContext.getFeatureProvider().updateCurrentModeKey(mNewMode.getModeKey());
mNewMode.resume(mCurrentModeDeviceUsage);
}
此函数用来更新mode,切换各个摄像模式时用到,已经初始化时会用到。
public void updateCurrentModeKey(String currentModeKey) {
LogHelper.d(TAG, "[updateCurrentModeKey] current mode key:" + currentModeKey);
if (mBuildInEntries.size() <= 0) {
mBuildInLoadCondition.block();
}
Iterator iterator = mBuildInEntries.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry item = (Map.Entry) iterator.next();
IFeatureEntry entry = (IFeatureEntry) item.getValue();
if (ICameraSetting.class.equals(entry.getType())) {
entry.updateCurrentModeKey(currentModeKey);
}
}
}
保持屏幕开启:
keepScreenOnForAWhile
private void keepScreenOnForAWhile() {
mMainHandler.removeMessages(MSG_CLEAR_SCREEN_ON_FLAG);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
mMainHandler.sendEmptyMessageDelayed(MSG_CLEAR_SCREEN_ON_FLAG,
DELAY_MSG_SCREEN_SWITCH);
}
private void checkPreconditionsAndOpen(String cameraId, CameraStateCallback callback,
boolean isSync) throws CameraOpenException {
checkDevicePolicy();//检查权限
LogHelper.d(TAG, "[checkPreconditions] mProxyCreatorMap size = " + mProxyCreatorMap.size());
Camera2ProxyCreatorImpl proxyCreator = mProxyCreatorMap.get(cameraId);
if (proxyCreator == null) {
proxyCreator = new Camera2ProxyCreatorImpl(cameraId);
mProxyCreatorMap.put(cameraId, proxyCreator);
}
if (isSync) {
proxyCreator.doOpenCameraSync(callback);
} else {
proxyCreator.doOpenCamera(callback);
}
}
/*************************************************************************************/
单独加载某个模式:
feature/mode/piportrait/src/com/mediatek/camera/feature/mode/piportrait/PiPortraitEntry.java
isSupport()->getModeItem()->