Move MenuExecutor operations into Service

Bug: 6680729
Change-Id: I538bb0a8783f7c1ff467ba8d8eb0deefdc0b6ea2
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 25fe9dd..1234bfc 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -400,5 +400,6 @@
         <activity android:name="com.android.camera.ProxyLauncher"
                 android:theme="@android:style/Theme.NoDisplay">
         </activity>
+        <service android:name="com.android.gallery3d.app.BatchService" />
     </application>
 </manifest>
diff --git a/src/com/android/gallery3d/app/AbstractGalleryActivity.java b/src/com/android/gallery3d/app/AbstractGalleryActivity.java
index 8f824cf..081b87a 100644
--- a/src/com/android/gallery3d/app/AbstractGalleryActivity.java
+++ b/src/com/android/gallery3d/app/AbstractGalleryActivity.java
@@ -19,14 +19,17 @@
 import android.annotation.TargetApi;
 import android.app.AlertDialog;
 import android.content.BroadcastReceiver;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.DialogInterface.OnCancelListener;
 import android.content.DialogInterface.OnClickListener;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.ServiceConnection;
 import android.content.res.Configuration;
 import android.os.Bundle;
+import android.os.IBinder;
 import android.view.Window;
 import android.view.WindowManager;
 
@@ -40,8 +43,8 @@
 import com.android.gallery3d.data.MediaItem;
 import com.android.gallery3d.ui.GLRoot;
 import com.android.gallery3d.ui.GLRootView;
-import com.android.gallery3d.util.ThreadPool;
 import com.android.gallery3d.util.LightCycleHelper.PanoramaViewHelper;
+import com.android.gallery3d.util.ThreadPool;
 
 public class AbstractGalleryActivity extends SherlockActivity implements GalleryContext {
     @SuppressWarnings("unused")
@@ -71,6 +74,7 @@
         getWindow().setBackgroundDrawable(null);
         mPanoramaViewHelper = new PanoramaViewHelper(this);
         mPanoramaViewHelper.onCreate();
+        doBindBatchService();
     }
 
     @Override
@@ -237,6 +241,7 @@
         } finally {
             mGLRootView.unlockRenderThread();
         }
+        doUnbindBatchService();
     }
 
     @Override
@@ -308,4 +313,39 @@
         return (getWindow().getAttributes().flags
                 & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0;
     }
+
+    private BatchService mBatchService;
+    private boolean mBatchServiceIsBound = false;
+    private ServiceConnection mBatchServiceConnection = new ServiceConnection() {
+        public void onServiceConnected(ComponentName className, IBinder service) {
+            mBatchService = ((BatchService.LocalBinder)service).getService();
+        }
+
+        public void onServiceDisconnected(ComponentName className) {
+            mBatchService = null;
+        }
+    };
+
+    private void doBindBatchService() {
+        bindService(new Intent(this, BatchService.class), mBatchServiceConnection, Context.BIND_AUTO_CREATE);
+        mBatchServiceIsBound = true;
+    }
+
+    private void doUnbindBatchService() {
+        if (mBatchServiceIsBound) {
+            // Detach our existing connection.
+            unbindService(mBatchServiceConnection);
+            mBatchServiceIsBound = false;
+        }
+    }
+
+    public ThreadPool getBatchServiceThreadPoolIfAvailable() {
+        if (mBatchServiceIsBound && mBatchService != null) {
+            return mBatchService.getThreadPool();
+        } else {
+            // Fall back on the old behavior if for some reason the
+            // service is not available.
+            return getThreadPool();
+        }
+    }
 }
diff --git a/src/com/android/gallery3d/app/AlbumPage.java b/src/com/android/gallery3d/app/AlbumPage.java
index e1c0613..50f5e02 100644
--- a/src/com/android/gallery3d/app/AlbumPage.java
+++ b/src/com/android/gallery3d/app/AlbumPage.java
@@ -441,7 +441,7 @@
             mSelectionManager.leaveSelectionMode();
         }
         mAlbumView.setSlotFilter(null);
-
+        mActionModeHandler.pause();
         mAlbumDataAdapter.pause();
         mAlbumView.pause();
         DetailsHelper.pause();
@@ -454,7 +454,6 @@
             mSyncTask = null;
             clearLoadingBit(BIT_LOADING_SYNC);
         }
-        mActionModeHandler.pause();
     }
 
     @Override
@@ -463,6 +462,7 @@
         if (mAlbumDataAdapter != null) {
             mAlbumDataAdapter.setLoadingListener(null);
         }
+        mActionModeHandler.destroy();
     }
 
     private void initializeViews() {
diff --git a/src/com/android/gallery3d/app/AlbumSetPage.java b/src/com/android/gallery3d/app/AlbumSetPage.java
index ed06f46..df68ffb 100644
--- a/src/com/android/gallery3d/app/AlbumSetPage.java
+++ b/src/com/android/gallery3d/app/AlbumSetPage.java
@@ -351,8 +351,9 @@
 
     @Override
     public void onDestroy() {
-        cleanupCameraButton();
         super.onDestroy();
+        cleanupCameraButton();
+        mActionModeHandler.destroy();
     }
 
     private boolean setupCameraButton() {
@@ -437,9 +438,9 @@
     public void onPause() {
         super.onPause();
         mIsActive = false;
-        mActionModeHandler.pause();
         mAlbumSetDataAdapter.pause();
         mAlbumSetView.pause();
+        mActionModeHandler.pause();
         mEyePosition.pause();
         DetailsHelper.pause();
         // Call disableClusterMenu to avoid receiving callback after paused.
diff --git a/src/com/android/gallery3d/app/BatchService.java b/src/com/android/gallery3d/app/BatchService.java
new file mode 100644
index 0000000..98a1d82
--- /dev/null
+++ b/src/com/android/gallery3d/app/BatchService.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.app;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.Binder;
+import android.os.IBinder;
+
+import com.android.gallery3d.util.ThreadPool;
+
+public class BatchService extends Service {
+
+    public class LocalBinder extends Binder {
+        BatchService getService() {
+            return BatchService.this;
+        }
+    }
+
+    private final IBinder mBinder = new LocalBinder();
+    private ThreadPool mThreadPool = new ThreadPool(1, 1);
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return mBinder;
+    }
+
+    public ThreadPool getThreadPool() {
+        return mThreadPool;
+    }
+}
diff --git a/src/com/android/gallery3d/ui/ActionModeHandler.java b/src/com/android/gallery3d/ui/ActionModeHandler.java
index 0a3318d..d90fc20 100644
--- a/src/com/android/gallery3d/ui/ActionModeHandler.java
+++ b/src/com/android/gallery3d/ui/ActionModeHandler.java
@@ -475,7 +475,12 @@
         mMenuExecutor.pause();
     }
 
+    public void destroy() {
+        mMenuExecutor.destroy();
+    }
+
     public void resume() {
         if (mSelectionManager.inSelectionMode()) updateSupportedOperation();
+        mMenuExecutor.resume();
     }
 }
diff --git a/src/com/android/gallery3d/ui/MenuExecutor.java b/src/com/android/gallery3d/ui/MenuExecutor.java
index 3d088d1..847ec89 100644
--- a/src/com/android/gallery3d/ui/MenuExecutor.java
+++ b/src/com/android/gallery3d/ui/MenuExecutor.java
@@ -63,6 +63,7 @@
     private Future<?> mTask;
     // wait the operation to finish when we want to stop it.
     private boolean mWaitOnStop;
+    private boolean mPaused;
 
     private final AbstractGalleryActivity mActivity;
     private final SelectionManager mSelectionManager;
@@ -114,7 +115,7 @@
                         break;
                     }
                     case MSG_TASK_UPDATE: {
-                        if (mDialog != null) mDialog.setProgress(message.arg1);
+                        if (mDialog != null && !mPaused) mDialog.setProgress(message.arg1);
                         if (message.obj != null) {
                             ProgressListener listener = (ProgressListener) message.obj;
                             listener.onProgressUpdate(message.arg1);
@@ -134,13 +135,23 @@
         if (mTask != null) {
             if (!mWaitOnStop) mTask.cancel();
             mTask.waitDone();
-            mDialog.dismiss();
+            if (mDialog != null && mDialog.isShowing()) mDialog.dismiss();
             mDialog = null;
             mTask = null;
         }
     }
 
+    public void resume() {
+        mPaused = false;
+        if (mDialog != null) mDialog.show();
+    }
+
     public void pause() {
+        mPaused = true;
+        if (mDialog != null && mDialog.isShowing()) mDialog.hide();
+    }
+
+    public void destroy() {
         stopTaskAndDismissDialog();
     }
 
@@ -335,7 +346,7 @@
             mDialog.show();
         }
         MediaOperation operation = new MediaOperation(action, ids, listener);
-        mTask = mActivity.getThreadPool().submit(operation, null);
+        mTask = mActivity.getBatchServiceThreadPoolIfAvailable().submit(operation, null);
         mWaitOnStop = waitOnStop;
     }