summaryrefslogtreecommitdiffstats
path: root/src/com/android/camera/ui
diff options
context:
space:
mode:
authorOwen Lin <owenlin@google.com>2010-04-01 15:42:33 +0800
committerOwen Lin <owenlin@google.com>2010-04-08 09:10:37 +0800
commit1aaf351f6bbaa0b1dc6c08bd5a590e1930e2ef07 (patch)
treeea265cb602ca36bcbbf5dc05ea3ef2e959ef686e /src/com/android/camera/ui
parent82544b4564c079ece1a9065d19add36b2635bb8f (diff)
downloadLegacyCamera-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.java39
-rw-r--r--src/com/android/camera/ui/HeadUpDisplay.java42
-rw-r--r--src/com/android/camera/ui/IndicatorBar.java8
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