本博文是基於Android 4.4講解
1、application 層:
當我們Android工程師想打開camera時通常直接調用Camera.java中的 Camer.open(cameraId)靜態函數
camera.java 位於 frameworks/base/core/java/android/hardware目錄下
//以下是部分代碼
public static Camera open(int cameraId) {
return new Camera(cameraId);
}
</pre><pre code_snippet_id="1846209" snippet_file_name="blog_20160823_3_8904287" name="code" class="html"><pre name="code" class="html">Camera(int cameraId) {
mShutterCallback = null;
mRawImageCallback = null;
mJpegCallback = null;
mPreviewCallback = null;
mPostviewCallback = null;
mUsingPreviewAllocation = false;
mZoomListener = null;
Looper looper;
if ((looper = Looper.myLooper()) != null) {
mEventHandler = new EventHandler(this, looper);
} else if ((looper = Looper.getMainLooper()) != null) {
mEventHandler = new EventHandler(this, looper);
} else {
mEventHandler = null;
}
String packageName = ActivityThread.currentPackageName();
<span style="color:#ff0000;">native_setup(new WeakReference<Camera>(this), cameraId, packageName);</span>
}
其中native_setup接口是native接口其函數聲明如下
private native final void native_setup(Object camera_this, int cameraId,
String packageName);
2、jni層
在camera.java中會調用到native_setup函數,此jni接口定義在 frameworks/base/core/jni下面的android_hardware_Camera.cpp中
// connect to camera service
static void android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz,
jobject weak_this, jint cameraId, jstring clientPackageName)
{
// Convert jstring to String16
const char16_t *rawClientName = env->GetStringChars(clientPackageName, NULL);
jsize rawClientNameLen = env->GetStringLength(clientPackageName);
String16 clientName(rawClientName, rawClientNameLen);
env->ReleaseStringChars(clientPackageName, rawClientName);
<span style="color:#ff0000;"> sp<Camera> camera = Camera::connect(cameraId, clientName,
Camera::USE_CALLING_UID);
</span>
if (camera == NULL) {
jniThrowRuntimeException(env, "Fail to connect to camera service");
return;
}
// make sure camera hardware is alive
if (camera->getStatus() != NO_ERROR) {
jniThrowRuntimeException(env, "Camera initialization failed");
return;
}
jclass clazz = env->GetObjectClass(thiz);
if (clazz == NULL) {
jniThrowRuntimeException(env, "Can't find android/hardware/Camera");
return;
}
// We use a weak reference so the Camera object can be garbage collected.
// The reference is only used as a proxy for callbacks.
sp<JNICameraContext> context = new JNICameraContext(env, weak_this, clazz, camera);
context->incStrong((void*)android_hardware_Camera_native_setup);
camera->setListener(context);
// save context in opaque field
env->SetIntField(thiz, fields.context, (int)context.get());
}
其中上面會調Camera::connect接口此類是frameworks/av/camera/Camera.cpp
sp<Camera> Camera::connect(int cameraId, const String16& clientPackageName,
int clientUid)
{
return <span style="color:#ff0000;">CameraBaseT::connect</span>(cameraId, clientPackageName, clientUid);//調用了父類的connect接口
}
frameworks/av/camera/CameraBase.cpp
template <typename TCam, typename TCamTraits>
sp<TCam> CameraBase<TCam, TCamTraits>::connect(int cameraId,
const String16& clientPackageName,
int clientUid)
{
ALOGV("%s: connect", __FUNCTION__);
sp<TCam> c = new TCam(cameraId);
sp<TCamCallbacks> cl = c;
status_t status = NO_ERROR;
<span style="color:#ff0000;">const sp<ICameraService>& cs = getCameraService(); //得到CameraService.cpp實例</span>
if (cs != 0) {
<span style="color:#ff0000;"> TCamConnectService fnConnectService = TCamTraits::fnConnectService;
status = (cs.get()->*fnConnectService)(cl, cameraId, clientPackageName, clientUid,
/*out*/ c->mCamera); //此行最終會調用到CameraService.cpp中的connect接口</span>
}
if (status == OK && c->mCamera != 0) {
c->mCamera->asBinder()->linkToDeath(c);
c->mStatus = NO_ERROR;
} else {
ALOGW("An error occurred while connecting to camera: %d", cameraId);
c.clear();
}
return c;
}
frameworks/av/services/camera/libcameraservicw/CameraService.cpp
status_t CameraService::connect(
const sp<ICameraClient>& cameraClient,
int cameraId,
const String16& clientPackageName,
int clientUid,
/*out*/
sp<ICamera>& device) {
String8 clientName8(clientPackageName);
int callingPid = getCallingPid();
LOG1("CameraService::connect E (pid %d \"%s\", id %d)", callingPid,
clientName8.string(), cameraId);
status_t status = validateConnect(cameraId, /*inout*/clientUid);
if (status != OK) {
return status;
}
sp<Client> client;
{
Mutex::Autolock lock(mServiceLock);
sp<BasicClient> clientTmp;
if (!canConnectUnsafe(cameraId, clientPackageName,
cameraClient->asBinder(),
/*out*/clientTmp)) {
return -EBUSY;
} else if (client.get() != NULL) {
device = static_cast<Client*>(clientTmp.get());
return OK;
}
int facing = -1;
int deviceVersion = getDeviceVersion(cameraId, &facing);
// If there are other non-exclusive users of the camera,
// this will tear them down before we can reuse the camera
if (isValidCameraId(cameraId)) {
// transition from PRESENT -> NOT_AVAILABLE
updateStatus(ICameraServiceListener::STATUS_NOT_AVAILABLE,
cameraId);
}
switch(deviceVersion) {
case CAMERA_DEVICE_API_VERSION_1_0:
<span style="color:#ff0000;">client = new CameraClient(this, cameraClient,
clientPackageName, cameraId,
facing, callingPid, clientUid, getpid()); //我用的是camer1</span>
break;
case CAMERA_DEVICE_API_VERSION_2_0:
case CAMERA_DEVICE_API_VERSION_2_1:
case CAMERA_DEVICE_API_VERSION_3_0:
client = new Camera2Client(this, cameraClient,
clientPackageName, cameraId,
facing, callingPid, clientUid, getpid(),
deviceVersion);
break;
case -1:
ALOGE("Invalid camera id %d", cameraId);
return BAD_VALUE;
default:
ALOGE("Unknown camera device HAL version: %d", deviceVersion);
return INVALID_OPERATION;
}
<span style="color:#ff0000;"> status_t status = connectFinishUnsafe(client, client->getRemote()); //見下面定義</span>
if (status != OK) {
// this is probably not recoverable.. maybe the client can try again
// OK: we can only get here if we were originally in PRESENT state
updateStatus(ICameraServiceListener::STATUS_PRESENT, cameraId);
return status;
}
mClient[cameraId] = client;
LOG1("CameraService::connect X (id %d, this pid is %d)", cameraId,
getpid());
}
// important: release the mutex here so the client can call back
// into the service from its destructor (can be at the end of the call)
device = client;
return OK;
}
status_t CameraService::connectFinishUnsafe(const sp<BasicClient>& client,
const sp<IBinder>& remoteCallback) {
<span style="color:#ff0000;"> status_t status = client->initialize(mModule); //其中 camera_module_t *mModule爲一個結構體指針,此指針會在onFirstRef()接口中初始化見下面代碼</span>
if (status != OK) {
return status;
}
remoteCallback->linkToDeath(this);
return OK;
}
//此接口會在CameraService實例化後調用,其中用到了sp機制,目前尚未研究通。
void CameraService::onFirstRef()
{
LOG1("CameraService::onFirstRef");
BnCameraService::onFirstRef();
if (<span style="color:#ff0000;">hw_get_module</span>(CAMERA_HARDWARE_MODULE_ID,//此句代碼是關鍵之處
(const hw_module_t **)&mModule) < 0) {
ALOGE("Could not load camera HAL module");
mNumberOfCameras = 0;
}
else {
ALOGI("Loaded \"%s\" camera module", mModule->common.name);
mNumberOfCameras = mModule->get_number_of_cameras();
if (mNumberOfCameras > MAX_CAMERAS) {
ALOGE("Number of cameras(%d) > MAX_CAMERAS(%d).",
mNumberOfCameras, MAX_CAMERAS);
mNumberOfCameras = MAX_CAMERAS;
}
for (int i = 0; i < mNumberOfCameras; i++) {
setCameraFree(i);
}
if (mModule->common.module_api_version >=
CAMERA_MODULE_API_VERSION_2_1) {
mModule->set_callbacks(this);
}
CameraDeviceFactory::registerService(this);
}
}
hw_get_module位於Android源碼目錄下 hardware/libhardware/Hardware.c
int hw_get_module(const char *id, const struct hw_module_t **module)
{
return hw_get_module_by_class(id, NULL, module);
}
//此函數會加載動態庫"/system/lib/hw"下面有名字爲class_id的動態庫
int hw_get_module_by_class(const char *class_id, const char *inst,
const struct hw_module_t **module)
{
int status;
int i;
const struct hw_module_t *hmi = NULL;
char prop[PATH_MAX];
char path[PATH_MAX];
char name[PATH_MAX];
if (inst)
snprintf(name, PATH_MAX, "%s.%s", class_id, inst);
else
strlcpy(name, class_id, PATH_MAX);
/*
* Here we rely on the fact that calling dlopen multiple times on
* the same .so will simply increment a refcount (and not load
* a new copy of the library).
* We also assume that dlopen() is thread-safe.
*/
/* Loop through the configuration variants looking for a module */
for (i=0 ; i<HAL_VARIANT_KEYS_COUNT+1 ; i++) {
if (i < HAL_VARIANT_KEYS_COUNT) {
if (property_get(variant_keys[i], prop, NULL) == 0) {
continue;
}
snprintf(path, sizeof(path), "%s/%s.%s.so",
HAL_LIBRARY_PATH2, name, prop); // PATH2: "/vendor/lib/hw"
if (access(path, R_OK) == 0) break;
snprintf(path, sizeof(path), "%s/%s.%s.so",
HAL_LIBRARY_PATH1, name, prop); //PATH1: "/system/lib/hw"
if (access(path, R_OK) == 0) break;
} else {
snprintf(path, sizeof(path), "%s/%s.default.so",
HAL_LIBRARY_PATH2, name);
if (access(path, R_OK) == 0) break;
snprintf(path, sizeof(path), "%s/%s.default.so",
HAL_LIBRARY_PATH1, name);
if (access(path, R_OK) == 0) break;
}
}
status = -ENOENT;
if (i < HAL_VARIANT_KEYS_COUNT+1) {
/* load the module, if this fails, we're doomed, and we should not try
* to load a different variant. */
status = load(class_id, path, module);
}
return status;
}
<span style="color:#ff0000;">//</span>
static int load(const char *id,
const char *path,
const struct hw_module_t **pHmi)
{
int status;
void *handle;
struct hw_module_t *hmi;
/*
* load the symbols resolving undefined symbols before
* dlopen returns. Since RTLD_GLOBAL is not or'd in with
* RTLD_NOW the external symbols will not be global
*/
handle = dlopen(path, RTLD_NOW);
if (handle == NULL) {
char const *err_str = dlerror();
ALOGE("load: module=%s\n%s", path, err_str?err_str:"unknown");
status = -EINVAL;
goto done;
}
/* Get the address of the struct hal_module_info. */
const char *sym = HAL_MODULE_INFO_SYM_AS_STR; //HAL_MODULE_INFO_SYM_AS_STR 爲 "HMI"
<span style="color:#ff0000;">//dlsym根據sym去實例化hmi,其中Camera_Moduel.cpp下有"HMI"名字的camera_module_t變量,見下面代碼</span>
hmi = (struct hw_module_t *)dlsym(handle, sym);
if (hmi == NULL) {
ALOGE("load: couldn't find symbol %s", sym);
status = -EINVAL;
goto done;
}
/* Check that the id matches */
if (strcmp(id, hmi->id) != 0) {
ALOGE("load: id=%s != hmi->id=%s", id, hmi->id);
status = -EINVAL;
goto done;
}
hmi->dso = handle;
/* success */
status = 0;
done:
if (status != 0) {
hmi = NULL;
if (handle != NULL) {
dlclose(handle);
handle = NULL;
}
} else {
ALOGV("loaded HAL id=%s path=%s hmi=%p handle=%p",
id, path, *pHmi, handle);
}
*pHmi = hmi;
return status;
}
CameraHal_Module.cpp //此類位於hardware/rk29/camera/camerahal目錄下,這是我的源代碼camera模塊
camera_module_t HAL_MODULE_INFO_SYM = {
common: {
tag: HARDWARE_MODULE_TAG,
version_major: ((CONFIG_CAMERAHAL_VERSION&0xff00)>>8),
version_minor: CONFIG_CAMERAHAL_VERSION&0xff,
id: CAMERA_HARDWARE_MODULE_ID,
name: CAMERA_MODULE_NAME,
author: "RockChip",
<span style="color:#ff0000;">methods: &camera_module_methods,</span>
dso: NULL, /* remove compilation warnings */
reserved: {0}, /* remove compilation warnings */
},
get_number_of_cameras: camera_get_number_of_cameras,
get_camera_info: camera_get_camera_info,
set_callbacks:NULL,
get_vendor_tag_ops:NULL,
reserved: {0}
};
到此frameworks/av/services/camera/libcameraservicw/CameraService.cpp下的mModule實例化完成
我們在進入到CameraClient.cpp(frameworks/av/services/camera/libcameraservice/api1)中(上面的CameraService.cpp實例化了CameraClient並且調用了它內部的initialize(camera_module_t *module)接口)
status_t CameraClient::initialize(camera_module_t *module) {
int callingPid = getCallingPid();
status_t res;
LOG1("CameraClient::initialize E (pid %d, id %d)", callingPid, mCameraId);
// Verify ops permissions
res = startCameraOps();
if (res != OK) {
return res;
}
char camera_device_name[10];
snprintf(camera_device_name, sizeof(camera_device_name), "%d", mCameraId);
<span style="color:#ff0000;">mHardware = new CameraHardwareInterface(camera_device_name);</span>
res = mHardware->initialize(&module->common);
if (res != OK) {
ALOGE("%s: Camera %d: unable to initialize device: %s (%d)",
__FUNCTION__, mCameraId, strerror(-res), res);
mHardware.clear();
return NO_INIT;
}
mHardware->setCallbacks(notifyCallback,
dataCallback,
dataCallbackTimestamp,
(void *)mCameraId);
// Enable zoom, error, focus, and metadata messages by default
enableMsgType(CAMERA_MSG_ERROR | CAMERA_MSG_ZOOM | CAMERA_MSG_FOCUS |
CAMERA_MSG_PREVIEW_METADATA | CAMERA_MSG_FOCUS_MOVE);
LOG1("CameraClient::initialize X (pid %d, id %d)", callingPid, mCameraId);
return OK;
}
CameraHardwareInterface.h位於 frameworks/av/services/camera/libcameraservice/device1
status_t initialize(hw_module_t *module)
{
ALOGI("Opening camera %s", mName.string());
<span style="color:#ff0000;">int rc = module->methods->open(module, mName.string(),
(hw_device_t **)&mDevice); //調用了上面CameraHal_Module.cpp下的</span><span style="color: rgb(255, 0, 0); font-family: Arial, Helvetica, sans-serif;">camera_module_t HAL_MODULE_INFO_SYM的open函數</span><span style="color:#ff0000;">,此函數定義見下面代碼</span>
if (rc != OK) {
ALOGE("Could not open camera %s: %d", mName.string(), rc);
return rc;
}
initHalPreviewWindow();
return rc;
}
static struct hw_module_methods_t camera_module_methods = {
open: camera_device_open
};
int camera_device_open(const hw_module_t* module, const char* name,
hw_device_t** device)
{
int rv = 0;
int cameraid;
rk_camera_device_t* camera_device = NULL;
camera_device_ops_t* camera_ops = NULL;
android::CameraHal* camera = NULL;
android::Mutex::Autolock lock(gCameraHalDeviceLock);
LOGI("camera_device open");
if (name != NULL) {
cameraid = atoi(name);
if(cameraid > gCamerasNumber) {
LOGE("camera service provided cameraid out of bounds, "
"cameraid = %d, num supported = %d",
cameraid, gCamerasNumber);
rv = -EINVAL;
goto fail;
}
if(gCamerasOpen >= CAMERAS_SUPPORTED_SIMUL_MAX) {
LOGE("maximum number(%d) of cameras already open",gCamerasOpen);
rv = -ENOMEM;
goto fail;
}
camera_device = (rk_camera_device_t*)malloc(sizeof(*camera_device));
if(!camera_device) {
LOGE("camera_device allocation fail");
rv = -ENOMEM;
goto fail;
}
camera_ops = (camera_device_ops_t*)malloc(sizeof(*camera_ops));
if(!camera_ops) {
LOGE("camera_ops allocation fail");
rv = -ENOMEM;
goto fail;
}
memset(camera_device, 0, sizeof(*camera_device));
memset(camera_ops, 0, sizeof(*camera_ops));
camera_device->base.common.tag = HARDWARE_DEVICE_TAG;
camera_device->base.common.version = 0;
camera_device->base.common.module = (hw_module_t *)(module);
camera_device->base.common.close = camera_device_close;
camera_device->base.ops = camera_ops;
camera_ops->set_preview_window = camera_set_preview_window;
camera_ops->set_callbacks = camera_set_callbacks;
camera_ops->enable_msg_type = camera_enable_msg_type;
camera_ops->disable_msg_type = camera_disable_msg_type;
camera_ops->msg_type_enabled = camera_msg_type_enabled;
camera_ops->start_preview = camera_start_preview;
camera_ops->stop_preview = camera_stop_preview;
camera_ops->preview_enabled = camera_preview_enabled;
camera_ops->store_meta_data_in_buffers = camera_store_meta_data_in_buffers;
camera_ops->start_recording = camera_start_recording;
camera_ops->stop_recording = camera_stop_recording;
camera_ops->recording_enabled = camera_recording_enabled;
camera_ops->release_recording_frame = camera_release_recording_frame;
camera_ops->auto_focus = camera_auto_focus;
camera_ops->cancel_auto_focus = camera_cancel_auto_focus;
camera_ops->take_picture = camera_take_picture;
camera_ops->cancel_picture = camera_cancel_picture;
camera_ops->set_parameters = camera_set_parameters;
camera_ops->get_parameters = camera_get_parameters;
camera_ops->put_parameters = camera_put_parameters;
camera_ops->send_command = camera_send_command;
camera_ops->release = camera_release;
camera_ops->dump = camera_dump;
*device = &camera_device->base.common;
// -------- RockChip specific stuff --------
camera_device->cameraid = cameraid;
<span style="color:#ff0000;">camera = new android::CameraHal(cameraid); //進入hal層</span>
if(!camera) {
LOGE("Couldn't create instance of CameraHal class");
rv = -ENOMEM;
goto fail;
}
gCameraHals[cameraid] = camera;
gCamerasOpen++;
}
return rv;
fail:
if(camera_device) {
free(camera_device);
camera_device = NULL;
}
if(camera_ops) {
free(camera_ops);
camera_ops = NULL;
}
if(camera) {
delete camera;
camera = NULL;
}
*device = NULL;
return rv;
}
3、hal層
hardware/rk29/camera/camerahal/CameraHal.cpp
//以下會根據camera硬件分類uvc soc isp等,實例化成對應的adapter.cpp(數據適配器,此類會調用iotrl系統接口和驅動層進行通信)
CameraHal::CameraHal(int cameraId)
:commandThreadCommandQ("commandCmdQ")
{
LOG_FUNCTION_NAME
{
char trace_level[PROPERTY_VALUE_MAX];
int level;
property_get(CAMERAHAL_TRACE_LEVEL_PROPERTY_KEY, trace_level, "0");
sscanf(trace_level,"%d",&level);
setTracerLevel(level);
}
mCamId = cameraId;
mCamFd = -1;
mCommandRunning = -1;
mCameraStatus = 0;
#if (CONFIG_CAMERA_MEM == CAMERA_MEM_ION)
mCamMemManager = new IonMemManager();
LOG1("%s(%d): Camera Hal memory is alloced from ION device",__FUNCTION__,__LINE__);
#elif(CONFIG_CAMERA_MEM == CAMERA_MEM_IONDMA)
if((strcmp(gCamInfos[cameraId].driver,"uvcvideo") == 0) //uvc camera
|| (gCamInfos[cameraId].pcam_total_info->mHardInfo.mSensorInfo.mPhy.type == CamSys_Phy_end)// soc cif
) {
gCamInfos[cameraId].pcam_total_info->mIsIommuEnabled = (IOMMU_ENABLED == 1)? true:false;
}
mCamMemManager = new IonDmaMemManager(gCamInfos[cameraId].pcam_total_info->mIsIommuEnabled);
LOG1("%s(%d): Camera Hal memory is alloced from ION device",__FUNCTION__,__LINE__);
#elif(CONFIG_CAMERA_MEM == CAMERA_MEM_PMEM)
if(access(CAMERA_PMEM_NAME, O_RDWR) < 0) {
LOGE("%s(%d): %s isn't registered, CameraHal_Mem current configuration isn't support ION memory!!!",
__FUNCTION__,__LINE__,CAMERA_PMEM_NAME);
} else {
mCamMemManager = new PmemManager((char*)CAMERA_PMEM_NAME);
LOG1("%s(%d): Camera Hal memory is alloced from %s device",__FUNCTION__,__LINE__,CAMERA_PMEM_NAME);
}
#endif
mPreviewBuf = new PreviewBufferProvider(mCamMemManager);
mVideoBuf = new BufferProvider(mCamMemManager);
mRawBuf = new BufferProvider(mCamMemManager);
mJpegBuf = new BufferProvider(mCamMemManager);
char value[PROPERTY_VALUE_MAX];
property_get(/*CAMERAHAL_TYPE_PROPERTY_KEY*/"sys.cam_hal.type", value, "none");
if (!strcmp(value, "fakecamera")) {
LOGD("it is a fake camera!");
mCameraAdapter = new CameraFakeAdapter(cameraId);
} else {
if((strcmp(gCamInfos[cameraId].driver,"uvcvideo") == 0)) {
LOGD("it is a uvc camera!");
mCameraAdapter = new CameraUSBAdapter(cameraId);
}
else if(gCamInfos[cameraId].pcam_total_info->mHardInfo.mSensorInfo.mPhy.type == CamSys_Phy_Cif){
LOGD("it is a isp soc camera");
if(gCamInfos[cameraId].pcam_total_info->mHardInfo.mSensorInfo.mPhy.info.cif.fmt == CamSys_Fmt_Raw_10b)
mCameraAdapter = new CameraIspSOCAdapter(cameraId);
else
mCameraAdapter = new CameraIspAdapter(cameraId);
}
else if(gCamInfos[cameraId].pcam_total_info->mHardInfo.mSensorInfo.mPhy.type == CamSys_Phy_Mipi){
LOGD("it is a isp camera");
mCameraAdapter = new CameraIspAdapter(cameraId);
}
else{
LOGD("it is a soc camera!");
mCameraAdapter = new CameraSOCAdapter(cameraId);
}
}
//initialize
{
char *call_process = getCallingProcess();
if(strstr(call_process,"com.android.cts.verifier")) {
mCameraAdapter->setImageAllFov(true);
} else {
mCameraAdapter->setImageAllFov(false);
}
}
mDisplayAdapter = new DisplayAdapter();
mEventNotifier = new AppMsgNotifier(mCameraAdapter);
mCameraAdapter->setEventNotifierRef(*mEventNotifier);
mCameraAdapter->initialize();
updateParameters(mParameters);
mCameraAdapter->setPreviewBufProvider(mPreviewBuf);
mCameraAdapter->setDisplayAdapterRef(*mDisplayAdapter);
mDisplayAdapter->setFrameProvider(mCameraAdapter);
mEventNotifier->setPictureRawBufProvider(mRawBuf);
mEventNotifier->setPictureJpegBufProvider(mJpegBuf);
mEventNotifier->setVideoBufProvider(mVideoBuf);
mEventNotifier->setFrameProvider(mCameraAdapter);
//command thread
mCommandThread = new CommandThread(this);
mCommandThread->run("CameraCmdThread", ANDROID_PRIORITY_URGENT_DISPLAY);
bool dataCbFrontMirror;
bool dataCbFrontFlip;
#if CONFIG_CAMERA_FRONT_MIRROR_MDATACB
if (gCamInfos[cameraId].facing_info.facing == CAMERA_FACING_FRONT) {
#if CONFIG_CAMERA_FRONT_MIRROR_MDATACB_ALL
dataCbFrontMirror = true;
#else
const char* cameraCallProcess = getCallingProcess();
if (strstr(CONFIG_CAMERA_FRONT_MIRROR_MDATACB_APK,cameraCallProcess)) {
dataCbFrontMirror = true;
} else {
dataCbFrontMirror = false;
}
if (strstr(CONFIG_CAMERA_FRONT_FLIP_MDATACB_APK,cameraCallProcess)) {
dataCbFrontFlip = true;
} else {
dataCbFrontFlip = false;
}
#endif
} else {
dataCbFrontMirror = false;
dataCbFrontFlip = false;
}
#else
dataCbFrontMirror = false;
#endif
mEventNotifier->setDatacbFrontMirrorFlipState(dataCbFrontMirror,dataCbFrontFlip);
// register for sensor events
mSensorListener = new SensorListener();
if (mSensorListener.get()) {
if (mSensorListener->initialize() == NO_ERROR) {
mSensorListener->setCallbacks(gsensor_orientation_cb, this);
mSensorListener->enableSensor(SensorListener::SENSOR_ORIENTATION);
} else {
LOGE("Error initializing SensorListener. not fatal, continuing");
mSensorListener.clear();
mSensorListener = NULL;
}
}
LOG_FUNCTION_NAME_EXIT
}