@OverrideprotectedvoidonCreate(BundlesavedInstanceState){DebugLog.LOGD("cameraDemo","cameraDemo::onCreate");super.onCreate(savedInstanceState);// Load any sample specific textures:// mTextures = new Vector<Texture>();// loadTextures();// Query the QCAR initialization flags:mQCARFlags=getInitializationFlags();// Creates the GestureDetector listener for processing double tap// mGestureDetector = new GestureDetector(this, new GestureListener());// Update the application status to start initializing application:updateApplicationStatus(APPSTATUS_INIT_APP);}
/** Configure QCAR with the desired version of OpenGL ES. */privateintgetInitializationFlags(){intflags=0;// Query the native code:if(getOpenGlEsVersionNative()==1){flags=QCAR.GL_11;}else{flags=QCAR.GL_20;}returnflags;}
// Application status constants:
private static final int APPSTATUS_UNINITED = -1;
private static final int APPSTATUS_INIT_APP = 0;
private static final int APPSTATUS_INIT_QCAR = 1;
private static final int APPSTATUS_INIT_TRACKER = 2;
private static final int APPSTATUS_INIT_APP_AR = 3;
private static final int APPSTATUS_LOAD_TRACKER = 4;
private static final int APPSTATUS_INITED = 5;
private static final int APPSTATUS_CAMERA_STOPPED = 6;
private static final int APPSTATUS_CAMERA_RUNNING = 7;
/** Initialize application GUI elements that are not related to AR. */privatevoidinitApplication(){// Set the screen orientation:// NOTE: Use SCREEN_ORIENTATION_LANDSCAPE or SCREEN_ORIENTATION_PORTRAIT// to lock the screen orientation for this activity.intscreenOrientation=ActivityInfo.SCREEN_ORIENTATION_SENSOR;// This is necessary for enabling AutoRotation in the Augmented Viewif(screenOrientation==ActivityInfo.SCREEN_ORIENTATION_SENSOR){// NOTE: We use reflection here to see if the current platform// supports the full sensor mode (available only on Gingerbread// and above.try{// SCREEN_ORIENTATION_FULL_SENSOR is required to allow all// 4 screen rotations if API level >= 9:FieldfullSensorField=ActivityInfo.class.getField("SCREEN_ORIENTATION_FULL_SENSOR");screenOrientation=fullSensorField.getInt(null);}catch(NoSuchFieldExceptione){// App is running on API level < 9, do nothing.}catch(Exceptione){e.printStackTrace();}}// Apply screen orientationsetRequestedOrientation(screenOrientation);updateActivityOrientation();// Query display dimensions:storeScreenDimensions();// As long as this window is visible to the user, keep the device's// screen turned on and bright:getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);}
在這段function似乎沒有進行什麼特別的init,全不可以看到的就是偵測目前裝置的方向就是你是拿直的還是橫的情況,而也會有一個function來記錄目前screen的狀態,應該是可以不用特別去了解細節。可能是因為要Render東西需要考慮方向性問題吧!好了,既然知道這邊是確定螢幕的方向內容,那可以先繼續下一步,也就是updateApplicationStatus(APPSTATUS_INIT_QCAR);,這邊在case APPSTATUS_INIT_QCAR當中主要是建立一個Task而這個Task為InitQCARTask(),接下來就進入我們InitQCARTask()來進行說明。然而需要注意一點就是,這邊在實現上為另外建立一個Task所以這邊是先mInitQCARTask = new InitQCARTask();接著mInitQCARTask.execute()。
/** An async task to initialize QCAR asynchronously. */privateclassInitQCARTaskextendsAsyncTask<Void,Integer,Boolean>{// Initialize with invalid value:privateintmProgressValue=-1;protectedBooleandoInBackground(Void...params){// Prevent the onDestroy() method to overlap with initialization:synchronized(mShutdownLock){QCAR.setInitParameters(cameraDemo.this,mQCARFlags);do{// QCAR.init() blocks until an initialization step is// complete, then it proceeds to the next step and reports// progress in percents (0 ... 100%).// If QCAR.init() returns -1, it indicates an error.// Initialization is done when progress has reached 100%.mProgressValue=QCAR.init();// Publish the progress value:publishProgress(mProgressValue);// We check whether the task has been canceled in the// meantime (by calling AsyncTask.cancel(true)).// and bail out if it has, thus stopping this thread.// This is necessary as the AsyncTask will run to completion// regardless of the status of the component that// started is.}while(!isCancelled()&&mProgressValue>=0&&mProgressValue<100);return(mProgressValue>0);}}protectedvoidonProgressUpdate(Integer...values){// Do something with the progress value "values[0]", e.g. update// splash screen, progress bar, etc.}protectedvoidonPostExecute(Booleanresult){// Done initializing QCAR, proceed to next application// initialization status:if(result){DebugLog.LOGD("cameraDemo","InitQCARTask::onPostExecute: QCAR "+"initialization successful");updateApplicationStatus(APPSTATUS_INIT_TRACKER);}else{// Create dialog box for display error:AlertDialogdialogError=newAlertDialog.Builder(cameraDemo.this).create();dialogError.setButton(DialogInterface.BUTTON_POSITIVE,"Close",newDialogInterface.OnClickListener(){publicvoidonClick(DialogInterfacedialog,intwhich){// Exiting application:System.exit(1);}});StringlogMessage;// NOTE: Check if initialization failed because the device is// not supported. At this point the user should be informed// with a message.if(mProgressValue==QCAR.INIT_DEVICE_NOT_SUPPORTED){logMessage="Failed to initialize QCAR because this "+"device is not supported.";}else{logMessage="Failed to initialize QCAR.";}// Log error:DebugLog.LOGE("cameraDemo","InitQCARTask::onPostExecute: "+logMessage+" Exiting.");// Show dialog box with error message:dialogError.setMessage(logMessage);dialogError.show();}}}
在這段InitQCARTask()主要的protected Boolean doInBackground(Void... params)裡面,就兩件事情比較重要QCAR.setInitParameters(cameraDemo.this, mQCARFlags);和QCAR.init()但是!QCAR.setInitParameters()有點奇怪,因為在官方API當中裡面參數只有一個,這是官方API寫的int QCAR_API QCAR::setInitParameters ( int flags )所以讓我覺得有點奇怪,為什麼會多一個Activity的參數,不過既然都需要,就塞進去吧。最後還需要一個QCAR.init()在這邊官方API說明為Initializes QCAR.詳細怎樣Initializes也沒有說明很清楚。不過有一個iOS的說明,整段說明為:iOS: Called to initialize QCAR. Initialization is progressive, so this function should be called repeatedly until it returns 100 or a negative value. Returns an integer representing the percentage complete (negative on error).,所以,看來就是這一個doInBackground(Void… params)會一直執行直到mProgressValue為100!整個就是讀取條,很酷。那基本上這邊就是只有進行Initialization QCAR的功用,最後完成時會進入到onPostExecute(),然後呼叫updateApplicationStatus(APPSTATUS_INIT_TRACKER);這邊又是另外一段function的開始,我在想,不要搞Task直接用應該也是可以,只是可能比較不保險!?接下來我們看一下case APPSTATUS_INIT_TRACKER:主要有一個function就是initTracker()這個是native code不得已只好先跳到native code來trace。
cameraDemo.cpp
1234567891011121314151617
JNIEXPORTintJNICALLJava_com_qualcomm_QCARSamples_ImageTargets_ImageTargets_initTracker(JNIEnv*,jobject){LOG("Java_com_qualcomm_QCARSamples_ImageTargets_ImageTargets_initTracker");// Initialize the image tracker:QCAR::TrackerManager&trackerManager=QCAR::TrackerManager::getInstance();QCAR::Tracker*tracker=trackerManager.initTracker(QCAR::Tracker::IMAGE_TRACKER);if(tracker==NULL){LOG("Failed to initialize ImageTracker.");return0;}LOG("Successfully initialized ImageTracker.");return1;}
在native code當中,主要有兩個用來Initialize的function,QCAR::TrackerManager和QCAR::Tracker* tracker在這邊參考一下官方的API和這個,雖然官方API有些說明很兩光或是不清楚,但是大致上還是可以理解。首先在QCAR::TrackerManager當中,主要就是需要取得一個TrackerManager的Instance()接著針對這個Instance進行操作。接著設定Tracker用來追蹤所偵測到的目標而在所追蹤的目標也需要初始化它的類型,這就是trackerManager.initTracker()所做的事情。在這邊當中只有兩種IMAGE_TRACKER-Tracks ImageTargets and MultiTargets.以及MARKER_TRACKER-Tracks Markers.這兩種,那關於Image Targets、MultiTargets以及Tracks Markers在Vuforia-I有說明。OK,這邊想要補充一下什麼是Instance這是軟工的一個名詞,定義說明如下。
1
Instance:An instanceis an object created from a class. The class describes the (behavior and information)structure of the instance, while the current state of the instance is defined by the operations performed on the instance.
/** * NOTE: this method is synchronized because of a potential concurrent * access by ImageTargets::onResume() and InitQCARTask::onPostExecute(). */privatesynchronizedvoidupdateApplicationStatus(intappStatus){// Exit if there is no change in status:if(mAppStatus==appStatus)return;// Store new status value:mAppStatus=appStatus;// Execute application state-specific actions:switch(mAppStatus){caseAPPSTATUS_INIT_APP:// Initialize application elements that do not rely on QCAR// initialization:initApplication();// Proceed to next application initialization status:updateApplicationStatus(APPSTATUS_INIT_QCAR);break;caseAPPSTATUS_INIT_QCAR:// Initialize QCAR SDK asynchronously to avoid blocking the// main (UI) thread.//// NOTE: This task instance must be created and invoked on the// UI thread and it can be executed only once!try{mInitQCARTask=newInitQCARTask();mInitQCARTask.execute();}catch(Exceptione){DebugLog.LOGE("cameraDemo","Initializing QCAR SDK failed");}break;caseAPPSTATUS_INIT_TRACKER:// Initialize the ImageTracker:if(initTracker()>0){// Proceed to next application initialization status:updateApplicationStatus(APPSTATUS_INIT_APP_AR);}break;caseAPPSTATUS_INIT_APP_AR:// Initialize Augmented Reality-specific application elements// that may rely on the fact that the QCAR SDK has been// already initialized:initApplicationAR();// Proceed to next application initialization status:updateApplicationStatus(APPSTATUS_LOAD_TRACKER);break;caseAPPSTATUS_LOAD_TRACKER:// Load the tracking data set://// NOTE: This task instance must be created and invoked on the// UI thread and it can be executed only once!try{mLoadTrackerTask=newLoadTrackerTask();mLoadTrackerTask.execute();}catch(Exceptione){DebugLog.LOGE("cameraDemo","Loading tracking data set failed");}break;caseAPPSTATUS_INITED:// Hint to the virtual machine that it would be a good time to// run the garbage collector://// NOTE: This is only a hint. There is no guarantee that the// garbage collector will actually be run.System.gc();// Native post initialization:onQCARInitializedNative();// Activate the renderer:mRenderer.mIsActive=true;// Now add the GL surface view. It is important// that the OpenGL ES surface view gets added// BEFORE the camera is started and video// background is configured.addContentView(mGlView,newLayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT));// Sets the UILayout to be drawn in front of the camera// mUILayout.bringToFront();// Start the camera:updateApplicationStatus(APPSTATUS_CAMERA_RUNNING);break;caseAPPSTATUS_CAMERA_STOPPED:// Call the native function to stop the camera:stopCamera();break;caseAPPSTATUS_CAMERA_RUNNING:// Call the native function to start the camera:startCamera();// Hides the Loading Dialog// loadingDialogHandler.sendEmptyMessage(HIDE_LOADING_DIALOG);// Sets the layout background to transparent// mUILayout.setBackgroundColor(Color.TRANSPARENT);// Set continuous auto-focus if supported by the device,// otherwise default back to regular auto-focus mode.// This will be activated by a tap to the screen in this// application.if(!setFocusMode(FOCUS_MODE_CONTINUOUS_AUTO)){mContAutofocus=false;setFocusMode(FOCUS_MODE_NORMAL);}else{mContAutofocus=true;}break;default:thrownewRuntimeException("Invalid application state");}}