summaryrefslogtreecommitdiffstats
path: root/src/com/android/gallery3d/filtershow/pipeline
diff options
context:
space:
mode:
authornicolasroard <nicolasroard@google.com>2013-07-12 18:27:54 -0700
committernicolasroard <nicolasroard@google.com>2013-07-16 17:07:33 -0700
commit24d6ec7beb37eb3a5449f1fa49b4adb123391d24 (patch)
tree4faa84bdb70e9284e9b1cf11c8cb4c1efd005a03 /src/com/android/gallery3d/filtershow/pipeline
parentdda606af6d6a18c31b1da3f8885e06b51982b601 (diff)
downloadandroid_packages_apps_Gallery2-24d6ec7beb37eb3a5449f1fa49b4adb123391d24.tar.gz
android_packages_apps_Gallery2-24d6ec7beb37eb3a5449f1fa49b4adb123391d24.tar.bz2
android_packages_apps_Gallery2-24d6ec7beb37eb3a5449f1fa49b4adb123391d24.zip
Add background processing service
bug:7298624 Change-Id: Ie79f88fd84fdf8f4dab6a8071f06a819e247b357
Diffstat (limited to 'src/com/android/gallery3d/filtershow/pipeline')
-rw-r--r--src/com/android/gallery3d/filtershow/pipeline/CachingPipeline.java4
-rw-r--r--src/com/android/gallery3d/filtershow/pipeline/FilteringPipeline.java1
-rw-r--r--src/com/android/gallery3d/filtershow/pipeline/ImagePreset.java4
-rw-r--r--src/com/android/gallery3d/filtershow/pipeline/ImageSavingTask.java123
-rw-r--r--src/com/android/gallery3d/filtershow/pipeline/ProcessingService.java217
-rw-r--r--src/com/android/gallery3d/filtershow/pipeline/ProcessingTask.java72
-rw-r--r--src/com/android/gallery3d/filtershow/pipeline/ProcessingTaskController.java98
7 files changed, 514 insertions, 5 deletions
diff --git a/src/com/android/gallery3d/filtershow/pipeline/CachingPipeline.java b/src/com/android/gallery3d/filtershow/pipeline/CachingPipeline.java
index a7580a835..535d02f0b 100644
--- a/src/com/android/gallery3d/filtershow/pipeline/CachingPipeline.java
+++ b/src/com/android/gallery3d/filtershow/pipeline/CachingPipeline.java
@@ -16,7 +16,7 @@
package com.android.gallery3d.filtershow.pipeline;
-import android.app.Activity;
+import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.support.v8.renderscript.Allocation;
@@ -68,7 +68,7 @@ public class CachingPipeline implements PipelineInterface {
return sRS;
}
- public static synchronized void createRenderscriptContext(Activity context) {
+ public static synchronized void createRenderscriptContext(Context context) {
if (sRS != null) {
Log.w(LOGTAG, "A prior RS context exists when calling setRenderScriptContext");
destroyRenderScriptContext();
diff --git a/src/com/android/gallery3d/filtershow/pipeline/FilteringPipeline.java b/src/com/android/gallery3d/filtershow/pipeline/FilteringPipeline.java
index a302b1907..0e9b83d7f 100644
--- a/src/com/android/gallery3d/filtershow/pipeline/FilteringPipeline.java
+++ b/src/com/android/gallery3d/filtershow/pipeline/FilteringPipeline.java
@@ -21,7 +21,6 @@ import android.os.*;
import android.os.Process;
import android.util.Log;
-import com.android.gallery3d.filtershow.cache.ImageLoader;
import com.android.gallery3d.filtershow.filters.FiltersManager;
import com.android.gallery3d.filtershow.imageshow.MasterImage;
diff --git a/src/com/android/gallery3d/filtershow/pipeline/ImagePreset.java b/src/com/android/gallery3d/filtershow/pipeline/ImagePreset.java
index 78a4d211d..2b9e3701f 100644
--- a/src/com/android/gallery3d/filtershow/pipeline/ImagePreset.java
+++ b/src/com/android/gallery3d/filtershow/pipeline/ImagePreset.java
@@ -55,7 +55,7 @@ public class ImagePreset {
private boolean mPartialRendering = false;
private Rect mPartialRenderingBounds;
- private static final boolean DEBUG = true;
+ private static final boolean DEBUG = false;
public ImagePreset() {
}
@@ -607,7 +607,7 @@ public class ImagePreset {
if (DEBUG) {
Log.v(LOGTAG, "Serialization: " + sname);
if (sname == null) {
- Log.v(LOGTAG, "Serialization: " + filter);
+ Log.v(LOGTAG, "Serialization name null for filter: " + filter);
}
}
writer.name(sname);
diff --git a/src/com/android/gallery3d/filtershow/pipeline/ImageSavingTask.java b/src/com/android/gallery3d/filtershow/pipeline/ImageSavingTask.java
new file mode 100644
index 000000000..e93ec1687
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/pipeline/ImageSavingTask.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2013 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.filtershow.pipeline;
+
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.net.Uri;
+import com.android.gallery3d.filtershow.cache.ImageLoader;
+import com.android.gallery3d.filtershow.filters.FiltersManager;
+import com.android.gallery3d.filtershow.tools.SaveImage;
+
+import java.io.File;
+
+public class ImageSavingTask extends ProcessingTask {
+ private ProcessingService mProcessingService;
+
+ static class SaveRequest implements Request {
+ Uri sourceUri;
+ Uri selectedUri;
+ File destinationFile;
+ ImagePreset preset;
+ }
+
+ static class UpdateBitmap implements Update {
+ Bitmap bitmap;
+ }
+
+ static class UpdateProgress implements Update {
+ int max;
+ int current;
+ }
+
+ static class URIResult implements Result {
+ Uri uri;
+ }
+
+ public ImageSavingTask(ProcessingService service) {
+ mProcessingService = service;
+ }
+
+ public void saveImage(Uri sourceUri, Uri selectedUri,
+ File destinationFile, ImagePreset preset) {
+ SaveRequest request = new SaveRequest();
+ request.sourceUri = sourceUri;
+ request.selectedUri = selectedUri;
+ request.destinationFile = destinationFile;
+ request.preset = preset;
+ postRequest(request);
+ }
+
+ public Result doInBackground(Request message) {
+ SaveRequest request = (SaveRequest) message;
+ Uri sourceUri = request.sourceUri;
+ Uri selectedUri = request.selectedUri;
+ File destinationFile = request.destinationFile;
+ ImagePreset preset = request.preset;
+
+ // We create a small bitmap showing the result that we can
+ // give to the notification
+ UpdateBitmap updateBitmap = new UpdateBitmap();
+ updateBitmap.bitmap = createNotificationBitmap(sourceUri, preset);
+ postUpdate(updateBitmap);
+
+ SaveImage saveImage = new SaveImage(mProcessingService, sourceUri,
+ selectedUri, destinationFile,
+ new SaveImage.Callback() {
+ @Override
+ public void onProgress(int max, int current) {
+ UpdateProgress updateProgress = new UpdateProgress();
+ updateProgress.max = max;
+ updateProgress.current = current;
+ postUpdate(updateProgress);
+ }
+ });
+
+ Uri uri = saveImage.processAndSaveImage(preset);
+ URIResult result = new URIResult();
+ result.uri = uri;
+ return result;
+ }
+
+ @Override
+ public void onResult(Result message) {
+ URIResult result = (URIResult) message;
+ mProcessingService.completeSaveImage(result.uri);
+ }
+
+ @Override
+ public void onUpdate(Update message) {
+ if (message instanceof UpdateBitmap) {
+ Bitmap bitmap = ((UpdateBitmap) message).bitmap;
+ mProcessingService.updateNotificationWithBitmap(bitmap);
+ }
+ if (message instanceof UpdateProgress) {
+ UpdateProgress progress = (UpdateProgress) message;
+ mProcessingService.updateProgress(progress.max, progress.current);
+ }
+ }
+
+ private Bitmap createNotificationBitmap(Uri sourceUri, ImagePreset preset) {
+ int notificationBitmapSize = Resources.getSystem().getDimensionPixelSize(
+ android.R.dimen.notification_large_icon_width);
+ Bitmap bitmap = ImageLoader.loadConstrainedBitmap(sourceUri, getContext(),
+ notificationBitmapSize, null, true);
+ CachingPipeline pipeline = new CachingPipeline(FiltersManager.getManager(), "Thumb");
+ return pipeline.renderFinalImage(bitmap, preset);
+ }
+
+}
diff --git a/src/com/android/gallery3d/filtershow/pipeline/ProcessingService.java b/src/com/android/gallery3d/filtershow/pipeline/ProcessingService.java
new file mode 100644
index 000000000..032024746
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/pipeline/ProcessingService.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2013 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.filtershow.pipeline;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.IBinder;
+import android.util.Log;
+import com.android.gallery3d.R;
+import com.android.gallery3d.filtershow.FilterShowActivity;
+import com.android.gallery3d.filtershow.filters.FiltersManager;
+import com.android.gallery3d.filtershow.filters.ImageFilter;
+import com.android.gallery3d.filtershow.tools.SaveImage;
+
+import java.io.File;
+
+public class ProcessingService extends Service {
+ private static final String LOGTAG = "ProcessingService";
+ private static final boolean SHOW_IMAGE = false;
+ private int mNotificationId;
+ private NotificationManager mNotifyMgr = null;
+ private Notification.Builder mBuilder = null;
+
+ private static final String PRESET = "preset";
+ private static final String SOURCE_URI = "sourceUri";
+ private static final String SELECTED_URI = "selectedUri";
+ private static final String DESTINATION_FILE = "destinationFile";
+ private static final String SAVING = "saving";
+
+ private ProcessingTaskController mProcessingTaskController;
+ private ImageSavingTask mImageSavingTask;
+
+ private final IBinder mBinder = new LocalBinder();
+ private FilterShowActivity mFiltershowActivity;
+
+ private boolean mSaving = false;
+ private boolean mNeedsAlive = false;
+
+ public void setFiltershowActivity(FilterShowActivity filtershowActivity) {
+ mFiltershowActivity = filtershowActivity;
+ }
+
+ public class LocalBinder extends Binder {
+ public ProcessingService getService() {
+ return ProcessingService.this;
+ }
+ }
+
+ public static Intent getSaveIntent(Context context, ImagePreset preset, File destination,
+ Uri selectedImageUri, Uri sourceImageUri) {
+ Intent processIntent = new Intent(context, ProcessingService.class);
+ processIntent.putExtra(ProcessingService.SOURCE_URI,
+ sourceImageUri.toString());
+ processIntent.putExtra(ProcessingService.SELECTED_URI,
+ selectedImageUri.toString());
+ if (destination != null) {
+ processIntent.putExtra(ProcessingService.DESTINATION_FILE, destination.toString());
+ }
+ processIntent.putExtra(ProcessingService.PRESET,
+ preset.getJsonString(context.getString(R.string.saved)));
+ processIntent.putExtra(ProcessingService.SAVING, true);
+ return processIntent;
+ }
+
+
+ @Override
+ public void onCreate() {
+ mProcessingTaskController = new ProcessingTaskController(this);
+ mImageSavingTask = new ImageSavingTask(this);
+ mProcessingTaskController.add(mImageSavingTask);
+ setupPipeline();
+ }
+
+ @Override
+ public void onDestroy() {
+ tearDownPipeline();
+ mProcessingTaskController.quit();
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ mNeedsAlive = true;
+ if (intent != null && intent.getBooleanExtra(SAVING, false)) {
+ // we save using an intent to keep the service around after the
+ // activity has been destroyed.
+ String presetJson = intent.getStringExtra(PRESET);
+ String source = intent.getStringExtra(SOURCE_URI);
+ String selected = intent.getStringExtra(SELECTED_URI);
+ String destination = intent.getStringExtra(DESTINATION_FILE);
+ Uri sourceUri = Uri.parse(source);
+ Uri selectedUri = null;
+ if (selected != null) {
+ selectedUri = Uri.parse(selected);
+ }
+ File destinationFile = null;
+ if (destination != null) {
+ destinationFile = new File(destination);
+ }
+ ImagePreset preset = new ImagePreset();
+ preset.readJsonFromString(presetJson);
+ mNeedsAlive = false;
+ mSaving = true;
+ handleSaveRequest(sourceUri, selectedUri, destinationFile, preset);
+ }
+ return START_REDELIVER_INTENT;
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return mBinder;
+ }
+
+ public void onStart() {
+ mNeedsAlive = true;
+ if (!mSaving && mFiltershowActivity != null) {
+ mFiltershowActivity.updateUIAfterServiceStarted();
+ }
+ }
+
+ public void handleSaveRequest(Uri sourceUri, Uri selectedUri,
+ File destinationFile, ImagePreset preset) {
+ mNotifyMgr = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
+
+ mNotificationId++;
+
+ mBuilder =
+ new Notification.Builder(this)
+ .setSmallIcon(R.drawable.filtershow_button_fx)
+ .setContentTitle(getString(R.string.filtershow_notification_label))
+ .setContentText(getString(R.string.filtershow_notification_message));
+
+ startForeground(mNotificationId, mBuilder.build());
+
+ updateProgress(SaveImage.MAX_PROCESSING_STEPS, 0);
+
+ // Process the image
+
+ mImageSavingTask.saveImage(sourceUri, selectedUri, destinationFile, preset);
+ }
+
+ public void updateNotificationWithBitmap(Bitmap bitmap) {
+ mBuilder.setLargeIcon(bitmap);
+ mNotifyMgr.notify(mNotificationId, mBuilder.build());
+ }
+
+ public void updateProgress(int max, int current) {
+ mBuilder.setProgress(max, current, false);
+ mNotifyMgr.notify(mNotificationId, mBuilder.build());
+ }
+
+ public void completeSaveImage(Uri result) {
+ if (SHOW_IMAGE) {
+ // TODO: we should update the existing image in Gallery instead
+ Intent viewImage = new Intent(Intent.ACTION_VIEW, result);
+ viewImage.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ startActivity(viewImage);
+ }
+ stopForeground(true);
+ stopSelf();
+ if (mNeedsAlive) {
+ // If the app has been restarted while we were saving...
+ mFiltershowActivity.updateUIAfterServiceStarted();
+ } else if (mFiltershowActivity.isSimpleEditAction()) {
+ // terminate now
+ mFiltershowActivity.completeSaveImage(result);
+ }
+ }
+
+ private void setupPipeline() {
+ Resources res = getResources();
+ FiltersManager.setResources(res);
+ CachingPipeline.createRenderscriptContext(this);
+
+ FiltersManager filtersManager = FiltersManager.getManager();
+ filtersManager.addLooks(this);
+ filtersManager.addBorders(this);
+ filtersManager.addTools(this);
+ filtersManager.addEffects();
+ }
+
+ private void tearDownPipeline() {
+ FilteringPipeline.getPipeline().turnOnPipeline(false);
+ FilteringPipeline.reset();
+ ImageFilter.resetStatics();
+ FiltersManager.getPreviewManager().freeRSFilterScripts();
+ FiltersManager.getManager().freeRSFilterScripts();
+ FiltersManager.getHighresManager().freeRSFilterScripts();
+ FiltersManager.reset();
+ CachingPipeline.destroyRenderScriptContext();
+ }
+
+ static {
+ System.loadLibrary("jni_filtershow_filters");
+ }
+}
diff --git a/src/com/android/gallery3d/filtershow/pipeline/ProcessingTask.java b/src/com/android/gallery3d/filtershow/pipeline/ProcessingTask.java
new file mode 100644
index 000000000..c3687ee6a
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/pipeline/ProcessingTask.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2013 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.filtershow.pipeline;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.Message;
+
+public abstract class ProcessingTask {
+ private ProcessingTaskController mTaskController;
+ private Handler mProcessingHandler;
+ private Handler mResultHandler;
+ private int mType;
+
+ static interface Request {}
+ static interface Update {}
+ static interface Result {}
+
+ public void postRequest(Request message) {
+ Message msg = mProcessingHandler.obtainMessage(mType);
+ msg.obj = message;
+ mProcessingHandler.sendMessage(msg);
+ }
+
+ public void postUpdate(Update message) {
+ Message msg = mResultHandler.obtainMessage(mType);
+ msg.obj = message;
+ msg.arg1 = ProcessingTaskController.UPDATE;
+ mResultHandler.sendMessage(msg);
+ }
+
+ public void processRequest(Request message) {
+ Object result = doInBackground(message);
+ Message msg = mResultHandler.obtainMessage(mType);
+ msg.obj = result;
+ msg.arg1 = ProcessingTaskController.RESULT;
+ mResultHandler.sendMessage(msg);
+ }
+
+ public void added(ProcessingTaskController taskController) {
+ mTaskController = taskController;
+ mResultHandler = taskController.getResultHandler();
+ mProcessingHandler = taskController.getProcessingHandler();
+ mType = taskController.getReservedType();
+ }
+
+ public int getType() {
+ return mType;
+ }
+
+ public Context getContext() {
+ return mTaskController.getContext();
+ }
+
+ public abstract Result doInBackground(Request message);
+ public abstract void onResult(Result message);
+ public void onUpdate(Update message) {}
+}
diff --git a/src/com/android/gallery3d/filtershow/pipeline/ProcessingTaskController.java b/src/com/android/gallery3d/filtershow/pipeline/ProcessingTaskController.java
new file mode 100644
index 000000000..218ea630a
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/pipeline/ProcessingTaskController.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2013 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.filtershow.pipeline;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Message;
+import android.util.Log;
+
+import java.util.HashMap;
+
+public class ProcessingTaskController implements Handler.Callback {
+ private static final String LOGTAG = "ProcessingTaskController";
+
+ private Context mContext;
+ private HandlerThread mHandlerThread = null;
+ private Handler mProcessingHandler = null;
+ private int mCurrentType;
+ private HashMap<Integer, ProcessingTask> mTasks = new HashMap<Integer, ProcessingTask>();
+
+ public final static int RESULT = 1;
+ public final static int UPDATE = 2;
+
+ private final Handler mResultHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ ProcessingTask task = mTasks.get(msg.what);
+ if (task != null) {
+ if (msg.arg1 == RESULT) {
+ task.onResult((ProcessingTask.Result) msg.obj);
+ } else if (msg.arg1 == UPDATE) {
+ task.onUpdate((ProcessingTask.Update) msg.obj);
+ } else {
+ Log.w(LOGTAG, "received unknown message! " + msg.arg1);
+ }
+ }
+ }
+ };
+
+ @Override
+ public boolean handleMessage(Message msg) {
+ ProcessingTask task = mTasks.get(msg.what);
+ if (task != null) {
+ task.processRequest((ProcessingTask.Request) msg.obj);
+ return true;
+ }
+ return false;
+ }
+
+ public ProcessingTaskController(Context context) {
+ mContext = context;
+ mHandlerThread = new HandlerThread("ProcessingTaskController",
+ android.os.Process.THREAD_PRIORITY_FOREGROUND);
+ mHandlerThread.start();
+ mProcessingHandler = new Handler(mHandlerThread.getLooper(), this);
+ }
+
+ public Handler getProcessingHandler() {
+ return mProcessingHandler;
+ }
+
+ public Handler getResultHandler() {
+ return mResultHandler;
+ }
+
+ public int getReservedType() {
+ return mCurrentType++;
+ }
+
+ public Context getContext() {
+ return mContext;
+ }
+
+ public void add(ProcessingTask task) {
+ task.added(this);
+ mTasks.put(task.getType(), task);
+ }
+
+ public void quit() {
+ mHandlerThread.quit();
+ }
+}