diff options
author | Owen Lin <owenlin@google.com> | 2010-04-01 15:42:33 +0800 |
---|---|---|
committer | Owen Lin <owenlin@google.com> | 2010-04-08 09:10:37 +0800 |
commit | 1aaf351f6bbaa0b1dc6c08bd5a590e1930e2ef07 (patch) | |
tree | ea265cb602ca36bcbbf5dc05ea3ef2e959ef686e /src/com/android/camera/ui | |
parent | 82544b4564c079ece1a9065d19add36b2635bb8f (diff) | |
download | LegacyCamera-1aaf351f6bbaa0b1dc6c08bd5a590e1930e2ef07.zip LegacyCamera-1aaf351f6bbaa0b1dc6c08bd5a590e1930e2ef07.tar.gz LegacyCamera-1aaf351f6bbaa0b1dc6c08bd5a590e1930e2ef07.tar.bz2 |
Fix the ANR after switching between Camera and Camcorder.
The reason of this bug is we try to queue an event in the GLThread, but the thread
has already dead when the GLRootView detacched from the window. So, we are
waiting a task that will never be executed.
I have seen a similar ANR in GLRootView.onTouch(), so I also fix the that issue
in this change.
Bug: 2559472
Change-Id: I49efd9ca01f1f6cce73320c31448ebaa7687469f
Diffstat (limited to 'src/com/android/camera/ui')
-rw-r--r-- | src/com/android/camera/ui/GLRootView.java | 39 | ||||
-rw-r--r-- | src/com/android/camera/ui/HeadUpDisplay.java | 42 | ||||
-rw-r--r-- | src/com/android/camera/ui/IndicatorBar.java | 8 |
3 files changed, 56 insertions, 33 deletions
diff --git a/src/com/android/camera/ui/GLRootView.java b/src/com/android/camera/ui/GLRootView.java index e3c066b..33aa736 100644 --- a/src/com/android/camera/ui/GLRootView.java +++ b/src/com/android/camera/ui/GLRootView.java @@ -1,13 +1,14 @@ package com.android.camera.ui; +import com.android.camera.Util; + import android.app.Activity; import android.content.Context; import android.graphics.Matrix; import android.graphics.PixelFormat; import android.opengl.GLSurfaceView; import android.opengl.GLU; -import android.os.Handler; -import android.os.HandlerThread; +import android.os.ConditionVariable; import android.os.Looper; import android.os.Process; import android.os.SystemClock; @@ -18,8 +19,6 @@ import android.view.MotionEvent; import android.view.animation.Animation; import android.view.animation.Transformation; -import com.android.camera.Util; - import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.ArrayList; @@ -75,11 +74,13 @@ public class GLRootView extends GLSurfaceView private Thread mGLThread; + private boolean mIsQueueActive = true; + // TODO: move this part (handler) into GLSurfaceView private final Looper mLooper; public GLRootView(Context context) { - this(context, null); + this(context, null); } public GLRootView(Context context, AttributeSet attrs) { @@ -437,9 +438,11 @@ public class GLRootView extends GLSurfaceView @Override public boolean dispatchTouchEvent(MotionEvent event) { + // If this has been detached from root, we don't need to handle event + if (mIsQueueActive) return false; FutureTask<Boolean> task = new FutureTask<Boolean>( new TouchEventHandler(event)); - queueEvent(task); + queueEventOrThrowException(task); try { return task.get(); } catch (Exception e) { @@ -521,6 +524,30 @@ public class GLRootView extends GLSurfaceView (float) width / newWidth, (float) height / newHeight); } + public synchronized void queueEventOrThrowException(Runnable runnable) { + if (!mIsQueueActive) { + throw new IllegalStateException("GLThread has exit"); + } + super.queueEvent(runnable); + } + + @Override + protected void onDetachedFromWindow() { + final ConditionVariable var = new ConditionVariable(); + synchronized (this) { + mIsQueueActive = false; + queueEvent(new Runnable() { + public void run() { + var.open(); + } + }); + } + + // Make sure all the runnables in the event queue is executed. + var.block(); + super.onDetachedFromWindow(); + } + protected Looper getTimerLooper() { return mLooper; } diff --git a/src/com/android/camera/ui/HeadUpDisplay.java b/src/com/android/camera/ui/HeadUpDisplay.java index 0e43ebe..ac2928f 100644 --- a/src/com/android/camera/ui/HeadUpDisplay.java +++ b/src/com/android/camera/ui/HeadUpDisplay.java @@ -1,6 +1,11 @@ package com.android.camera.ui; import static com.android.camera.ui.GLRootView.dpToPixel; + +import java.util.ArrayList; +import java.util.concurrent.Callable; +import java.util.concurrent.FutureTask; + import android.content.Context; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; @@ -11,7 +16,6 @@ import android.os.Handler; import android.os.Message; import android.preference.PreferenceManager; import android.util.DisplayMetrics; -import android.util.Log; import android.view.MotionEvent; import android.view.View.MeasureSpec; import android.view.animation.AlphaAnimation; @@ -23,10 +27,6 @@ import com.android.camera.ListPreference; import com.android.camera.PreferenceGroup; import com.android.camera.R; -import java.util.ArrayList; -import java.util.concurrent.Callable; -import java.util.concurrent.FutureTask; - // This is the UI for the on-screen settings. It mainly run in the GLThread. It // will modify the shared-preferences. The concurrency rule is: The shared- // preference will be updated in the GLThread. And an event will be trigger in @@ -88,22 +88,16 @@ public class HeadUpDisplay extends GLView { @Override public void handleMessage(Message msg) { GLRootView root = getGLRootView(); - FutureTask<Void> task = null; + Runnable runnable = null; switch(msg.what) { case DESELECT_INDICATOR: - task = new FutureTask<Void>(mDeselectIndicator); + runnable = mDeselectIndicator; break; case DEACTIVATE_INDICATOR_BAR: - task = new FutureTask<Void>(mDeactivateIndicatorBar); + runnable = mDeactivateIndicatorBar; break; } - if (task == null) return; - try { - root.queueEvent(task); - task.get(); - } catch (Exception e) { - Log.e(TAG, "error in concurrent code", e); - } + if (runnable != null) root.queueEvent(runnable); } }; } @@ -116,17 +110,15 @@ public class HeadUpDisplay extends GLView { sPopupTriangleOffset = dpToPixel(context, POPUP_TRIANGLE_OFFSET); } - private final Callable<Void> mDeselectIndicator = new Callable<Void> () { - public Void call() throws Exception { + private final Runnable mDeselectIndicator = new Runnable () { + public void run() { mIndicatorBar.setSelectedIndex(IndicatorBar.INDEX_NONE); - return null; - } + } }; - private final Callable<Void> mDeactivateIndicatorBar = new Callable<Void> () { - public Void call() throws Exception { + private final Runnable mDeactivateIndicatorBar = new Runnable () { + public void run() { if (mIndicatorBar != null) mIndicatorBar.setActivated(false); - return null; } }; @@ -367,9 +359,9 @@ public class HeadUpDisplay extends GLView { private final Callable<Boolean> mCollapse = new Callable<Boolean>() { public Boolean call() { - if (mIndicatorBar.getSelectedIndex() == IndicatorBar.INDEX_NONE) { - return false; - } + if (!mIndicatorBar.isActivated()) return false; + mHandler.removeMessages(DESELECT_INDICATOR); + mHandler.removeMessages(DEACTIVATE_INDICATOR_BAR); mIndicatorBar.setSelectedIndex(IndicatorBar.INDEX_NONE); mIndicatorBar.setActivated(false); return true; diff --git a/src/com/android/camera/ui/IndicatorBar.java b/src/com/android/camera/ui/IndicatorBar.java index 28c4eab..e5ee82a 100644 --- a/src/com/android/camera/ui/IndicatorBar.java +++ b/src/com/android/camera/ui/IndicatorBar.java @@ -1,12 +1,12 @@ package com.android.camera.ui; +import javax.microedition.khronos.opengles.GL11; + import android.graphics.Rect; import android.view.MotionEvent; import android.view.View.MeasureSpec; import android.view.animation.AlphaAnimation; -import javax.microedition.khronos.opengles.GL11; - public class IndicatorBar extends GLView { public static final int INDEX_NONE = -1; @@ -148,6 +148,10 @@ public class IndicatorBar extends GLView { } } + public boolean isActivated() { + return mActivated; + } + @Override protected boolean dispatchTouchEvent(MotionEvent event) { // Do not pass motion events to children |