Adopt the new error handling mechanism in portability.

Show camera fatal dialog to guide users exiting the app when
1) camera framework throws RTE or
2) DispatchThread job is timeout.

If users hit home button while error dialog is shown, just exit
the app.

Bug: 16189216
Change-Id: Ia0f1c64d452735ec62549f50ab62646d8d873c65
diff --git a/src/com/android/camera/CameraActivity.java b/src/com/android/camera/CameraActivity.java
index ffd04c9..8775887 100644
--- a/src/com/android/camera/CameraActivity.java
+++ b/src/com/android/camera/CameraActivity.java
@@ -136,6 +136,7 @@
 import com.android.camera2.R;
 import com.android.ex.camera2.portability.CameraAgent;
 import com.android.ex.camera2.portability.CameraAgentFactory;
+import com.android.ex.camera2.portability.CameraExceptionHandler;
 import com.android.ex.camera2.portability.CameraSettings;
 import com.bumptech.glide.Glide;
 import com.bumptech.glide.GlideBuilder;
@@ -186,6 +187,13 @@
     private Context mAppContext;
 
     /**
+     * Camera fatal error handling:
+     * 1) Present error dialog to guide users to exit the app.
+     * 2) If users hit home button, onPause should just call finish() to exit the app.
+     */
+    private boolean mCameraFatalError = false;
+
+    /**
      * Whether onResume should reset the view to the preview.
      */
     private boolean mResetToPreviewOnResume = true;
@@ -1309,11 +1317,25 @@
         }
     }
 
-    private final CameraAgent.CameraExceptionCallback mCameraDefaultExceptionCallback
-        = new CameraAgent.CameraExceptionCallback() {
+    private final CameraExceptionHandler.CameraExceptionCallback mCameraExceptionCallback
+        = new CameraExceptionHandler.CameraExceptionCallback() {
                 @Override
-                public void onCameraException(RuntimeException e) {
-                    Log.e(TAG, "Camera Exception", e);
+                public void onCameraException(RuntimeException ex) {
+                    Log.e(TAG, "Camera Exception", ex);
+                    onFatalError(ex);
+                }
+                @Override
+                public void onDispatchThreadException(RuntimeException ex) {
+                    Log.e(TAG, "DispatchThread Exception", ex);
+                    onFatalError(ex);
+                }
+                private void onFatalError(RuntimeException ex) {
+                    mCameraFatalError = true;
+                    // If the activity receives exception during onPause, just exit the app.
+                    if (mPaused && !isFinishing()) {
+                        Log.v(TAG, "Fatal error during onPause, call Activity.finish()");
+                        finish();
+                    }
                     CameraUtil.showErrorAndFinish(CameraActivity.this,
                             R.string.cannot_connect_camera);
                 }
@@ -1372,8 +1394,8 @@
         mCameraController = new CameraController(mAppContext, this, mMainHandler,
                 CameraAgentFactory.getAndroidCameraAgent(this, CameraAgentFactory.CameraApi.API_1),
                 CameraAgentFactory.getAndroidCameraAgent(this, CameraAgentFactory.CameraApi.AUTO));
-        mCameraController.setCameraDefaultExceptionCallback(mCameraDefaultExceptionCallback,
-                mMainHandler);
+        mCameraController.setCameraExceptionHandler(
+                new CameraExceptionHandler(mCameraExceptionCallback, mMainHandler));
 
         mModeListView = (ModeListView) findViewById(R.id.mode_list_layout);
         mModeListView.init(mModuleManager.getSupportedModeIndexList());
@@ -1661,16 +1683,14 @@
 
         UsageStatistics.instance().backgrounded();
 
-        // Close the camera and wait for the operation done. But if we time out
-        // via RuntimeException, just continue pausing, and request a finish().
-        try {
-            mCameraController.closeCamera(true);
-        } catch (RuntimeException e) {
-            Log.e(TAG, "Exception while closing camera", e);
-            if (!isFinishing()) {
-                finish();
-            }
+        // Camera is in fatal state. A fatal dialog is presented to users, but users just hit home
+        // button. Let's just kill the process.
+        if (mCameraFatalError && !isFinishing()) {
+            Log.v(TAG, "onPause when camera is in fatal state, call Activity.finish()");
+            finish();
         }
+        // Close the camera and wait for the operation done.
+        mCameraController.closeCamera(true);
     }
 
     @Override
@@ -1878,13 +1898,8 @@
         mOrientationManager = null;
         mButtonManager = null;
         mSoundPlayer.release();
-        mCurrentModule.destroy();
-        try {
-            CameraAgentFactory.recycle(CameraAgentFactory.CameraApi.API_1);
-            CameraAgentFactory.recycle(CameraAgentFactory.CameraApi.AUTO);
-        } catch (RuntimeException e) {
-            Log.e(TAG, "CameraAgentFactory exception during destroy", e);
-        }
+        CameraAgentFactory.recycle(CameraAgentFactory.CameraApi.API_1);
+        CameraAgentFactory.recycle(CameraAgentFactory.CameraApi.AUTO);
     }
 
     @Override
diff --git a/src/com/android/camera/app/CameraController.java b/src/com/android/camera/app/CameraController.java
index 019bb94..26cc394 100644
--- a/src/com/android/camera/app/CameraController.java
+++ b/src/com/android/camera/app/CameraController.java
@@ -24,8 +24,8 @@
 import com.android.camera.util.CameraUtil;
 import com.android.camera.util.GservicesHelper;
 import com.android.ex.camera2.portability.CameraAgent;
-import com.android.ex.camera2.portability.CameraAgent.CameraExceptionCallback;
 import com.android.ex.camera2.portability.CameraDeviceInfo;
+import com.android.ex.camera2.portability.CameraExceptionHandler;
 
 /**
  * A class which implements {@link com.android.camera.app.CameraProvider} used
@@ -83,11 +83,10 @@
     }
 
     @Override
-    public void setCameraDefaultExceptionCallback(CameraExceptionCallback callback,
-            Handler handler) {
-        mCameraAgent.setCameraDefaultExceptionCallback(callback, handler);
+    public void setCameraExceptionHandler(CameraExceptionHandler exceptionHandler) {
+        mCameraAgent.setCameraExceptionHandler(exceptionHandler);
         if (mCameraAgentNg != null) {
-            mCameraAgentNg.setCameraDefaultExceptionCallback(callback, handler);
+            mCameraAgentNg.setCameraExceptionHandler(exceptionHandler);
         }
     }
 
diff --git a/src/com/android/camera/app/CameraProvider.java b/src/com/android/camera/app/CameraProvider.java
index 40c602f..9b98b67 100644
--- a/src/com/android/camera/app/CameraProvider.java
+++ b/src/com/android/camera/app/CameraProvider.java
@@ -19,8 +19,8 @@
 import android.hardware.Camera;
 import android.os.Handler;
 
-import com.android.ex.camera2.portability.CameraAgent.CameraExceptionCallback;
 import com.android.ex.camera2.portability.CameraDeviceInfo.Characteristics;
+import com.android.ex.camera2.portability.CameraExceptionHandler;
 
 /**
  * An interface which defines the camera provider.
@@ -57,8 +57,7 @@
      * Sets a callback for handling camera api runtime exceptions on
      * a handler.
      */
-    public void setCameraDefaultExceptionCallback(CameraExceptionCallback callback,
-            Handler handler);
+    public void setCameraExceptionHandler(CameraExceptionHandler exceptionHandler);
 
     /**
      * Get the {@link Characteristics} of the given camera.
diff --git a/src/com/android/camera/debug/DebugCameraProxy.java b/src/com/android/camera/debug/DebugCameraProxy.java
index cf6952c..b847d87 100644
--- a/src/com/android/camera/debug/DebugCameraProxy.java
+++ b/src/com/android/camera/debug/DebugCameraProxy.java
@@ -66,6 +66,12 @@
     }
 
     @Override
+    public CameraAgent getAgent() {
+        log("getAgent");
+        return mProxy.getAgent();
+    }
+
+    @Override
     public CameraCapabilities getCapabilities() {
         log("getCapabilities");
         return mProxy.getCapabilities();