OSDN Git Service

Fix NPE in SlotView.
authorOwen Lin <owenlin@google.com>
Tue, 17 Apr 2012 07:38:36 +0000 (15:38 +0800)
committerOwen Lin <owenlin@google.com>
Wed, 18 Apr 2012 09:35:40 +0000 (17:35 +0800)
This NPE is actually a concurrent issue. We shall lock renderring when we clean up
the slots' data. But it didn't, so it may access to null data.

Change-Id: I2a8abfbb77f83bd9a240477fa53216ce69b7774d
fix: 6302487
fix: 6308873

src/com/android/gallery3d/app/AlbumPage.java
src/com/android/gallery3d/app/AlbumSetPage.java
src/com/android/gallery3d/app/ManageCachePage.java
src/com/android/gallery3d/ui/ActionModeHandler.java
src/com/android/gallery3d/ui/SlotView.java

index 0fcd7a7..158070f 100644 (file)
@@ -343,7 +343,7 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster
         mSelectionManager = new SelectionManager(mActivity, false);
         mSelectionManager.setSelectionListener(this);
         Config.AlbumPage config = Config.AlbumPage.get((Context) mActivity);
-        mSlotView = new SlotView((Context) mActivity, config.slotViewSpec);
+        mSlotView = new SlotView(mActivity, config.slotViewSpec);
         mAlbumView = new AlbumSlotRenderer(mActivity, mSlotView, mSelectionManager);
         mSlotView.setSlotRenderer(mAlbumView);
         mRootPane.addComponent(mSlotView);
index c66f538..4c5a49b 100644 (file)
@@ -344,7 +344,7 @@ public class AlbumSetPage extends ActivityState implements
         mSelectionManager.setSelectionListener(this);
 
         Config.AlbumSetPage config = Config.AlbumSetPage.get((Context) mActivity);
-        mSlotView = new SlotView((Context) mActivity, config.slotViewSpec);
+        mSlotView = new SlotView(mActivity, config.slotViewSpec);
         mAlbumSetView = new AlbumSetSlotRenderer(
                 mActivity, mSelectionManager, mSlotView, config.labelSpec);
         mSlotView.setSlotRenderer(mAlbumSetView);
index 5793b70..94ebf92 100644 (file)
@@ -17,7 +17,6 @@
 package com.android.gallery3d.app;
 
 import android.app.Activity;
-import android.content.Context;
 import android.content.res.Configuration;
 import android.os.Bundle;
 import android.os.Handler;
@@ -38,6 +37,7 @@ import com.android.gallery3d.data.MediaSet;
 import com.android.gallery3d.data.Path;
 import com.android.gallery3d.ui.CacheStorageUsageInfo;
 import com.android.gallery3d.ui.GLCanvas;
+import com.android.gallery3d.ui.GLRoot;
 import com.android.gallery3d.ui.GLView;
 import com.android.gallery3d.ui.ManageCacheDrawer;
 import com.android.gallery3d.ui.MenuExecutor;
@@ -286,7 +286,7 @@ public class ManageCachePage extends ActivityState implements
         mSelectionManager.setSelectionListener(this);
 
         Config.ManageCachePage config = Config.ManageCachePage.get(activity);
-        mSlotView = new SlotView((Context) mActivity, config.slotViewSpec);
+        mSlotView = new SlotView(mActivity, config.slotViewSpec);
         mSelectionDrawer = new ManageCacheDrawer(mActivity, mSelectionManager, mSlotView,
                 config.labelSpec, config.cachePinSize, config.cachePinMargin);
         mSlotView.setSlotRenderer(mSelectionDrawer);
@@ -324,17 +324,22 @@ public class ManageCachePage extends ActivityState implements
     @Override
     public void onClick(View view) {
         Utils.assertTrue(view.getId() == R.id.done);
+        GLRoot root = mActivity.getGLRoot();
+        root.lockRenderThread();
+        try {
+            ArrayList<Path> ids = mSelectionManager.getSelected(false);
+            if (ids.size() == 0) {
+                onBackPressed();
+                return;
+            }
+            showToast();
 
-        ArrayList<Path> ids = mSelectionManager.getSelected(false);
-        if (ids.size() == 0) {
-            onBackPressed();
-            return;
+            MenuExecutor menuExecutor = new MenuExecutor(mActivity, mSelectionManager);
+            menuExecutor.startAction(R.id.action_toggle_full_caching,
+                    R.string.process_caching_requests, this);
+        } finally {
+            root.unlockRenderThread();
         }
-        showToast();
-
-        MenuExecutor menuExecutor = new MenuExecutor(mActivity, mSelectionManager);
-        menuExecutor.startAction(R.id.action_toggle_full_caching,
-                R.string.process_caching_requests, this);
     }
 
     private void showToast() {
index 9a66675..32820f3 100644 (file)
@@ -88,6 +88,7 @@ public class ActionModeHandler implements ActionMode.Callback {
                 R.menu.selection);
         updateSelectionMenu();
         customMenu.setOnMenuItemClickListener(new OnMenuItemClickListener() {
+            @Override
             public boolean onMenuItemClick(MenuItem item) {
                 return onActionItemClicked(actionMode, item);
             }
@@ -103,25 +104,32 @@ public class ActionModeHandler implements ActionMode.Callback {
         mListener = listener;
     }
 
+    @Override
     public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
-        boolean result;
-        if (mListener != null) {
-            result = mListener.onActionItemClicked(item);
-            if (result) {
-                mSelectionManager.leaveSelectionMode();
-                return result;
+        GLRoot root = mActivity.getGLRoot();
+        root.lockRenderThread();
+        try {
+            boolean result;
+            if (mListener != null) {
+                result = mListener.onActionItemClicked(item);
+                if (result) {
+                    mSelectionManager.leaveSelectionMode();
+                    return result;
+                }
             }
+            ProgressListener listener = null;
+            if (item.getItemId() == R.id.action_import) {
+                listener = new ImportCompleteListener(mActivity);
+            }
+            result = mMenuExecutor.onMenuClicked(item, listener);
+            if (item.getItemId() == R.id.action_select_all) {
+                updateSupportedOperation();
+                updateSelectionMenu();
+            }
+            return result;
+        } finally {
+            root.unlockRenderThread();
         }
-        ProgressListener listener = null;
-        if (item.getItemId() == R.id.action_import) {
-            listener = new ImportCompleteListener(mActivity);
-        }
-        result = mMenuExecutor.onMenuClicked(item, listener);
-        if (item.getItemId() == R.id.action_select_all) {
-            updateSupportedOperation();
-            updateSelectionMenu();
-        }
-        return result;
     }
 
     private void updateSelectionMenu() {
index 5e12c74..26e885f 100644 (file)
@@ -24,6 +24,7 @@ import android.view.MotionEvent;
 import android.view.animation.DecelerateInterpolator;
 
 import com.android.gallery3d.anim.Animation;
+import com.android.gallery3d.app.GalleryActivity;
 import com.android.gallery3d.common.Utils;
 
 public class SlotView extends GLView {
@@ -87,11 +88,11 @@ public class SlotView extends GLView {
     // to prevent allocating memory
     private final Rect mTempRect = new Rect();
 
-    public SlotView(Context context, Spec spec) {
-        mGestureDetector =
-                new GestureDetector(context, new MyGestureListener());
-        mScroller = new ScrollerHelper(context);
-        mHandler = new Handler(context.getMainLooper());
+    public SlotView(GalleryActivity activity, Spec spec) {
+        mGestureDetector = new GestureDetector(
+                (Context) activity, new MyGestureListener());
+        mScroller = new ScrollerHelper((Context) activity);
+        mHandler = new SynchronizedHandler(activity.getGLRoot());
         setSlotSpec(spec);
     }
 
@@ -631,19 +632,24 @@ public class SlotView extends GLView {
         }
     }
 
-    private class MyGestureListener implements
-            GestureDetector.OnGestureListener {
+    private class MyGestureListener implements GestureDetector.OnGestureListener {
         private boolean isDown;
 
         // We call the listener's onDown() when our onShowPress() is called and
         // call the listener's onUp() when we receive any further event.
         @Override
         public void onShowPress(MotionEvent e) {
-            if (isDown) return;
-            int index = mLayout.getSlotIndexByPosition(e.getX(), e.getY());
-            if (index != INDEX_NONE) {
-                isDown = true;
-                mListener.onDown(index);
+            GLRoot root = getGLRoot();
+            root.lockRenderThread();
+            try {
+                if (isDown) return;
+                int index = mLayout.getSlotIndexByPosition(e.getX(), e.getY());
+                if (index != INDEX_NONE) {
+                    isDown = true;
+                    mListener.onDown(index);
+                }
+            } finally {
+                root.unlockRenderThread();
             }
         }