1 /* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.gallery3d.filtershow.pipeline; 18 19 import android.app.Notification; 20 import android.app.NotificationManager; 21 import android.app.Service; 22 import android.content.Context; 23 import android.content.Intent; 24 import android.content.res.Resources; 25 import android.graphics.Bitmap; 26 import android.graphics.Rect; 27 import android.net.Uri; 28 import android.os.Binder; 29 import android.os.IBinder; 30 import android.util.Log; 31 import com.android.gallery3d.R; 32 import com.android.gallery3d.filtershow.FilterShowActivity; 33 import com.android.gallery3d.filtershow.filters.FiltersManager; 34 import com.android.gallery3d.filtershow.filters.ImageFilter; 35 import com.android.gallery3d.filtershow.imageshow.PrimaryImage; 36 import com.android.gallery3d.filtershow.tools.SaveImage; 37 38 import java.io.File; 39 40 public class ProcessingService extends Service { 41 private static final String LOGTAG = "ProcessingService"; 42 private static final boolean SHOW_IMAGE = false; 43 private int mNotificationId; 44 private NotificationManager mNotifyMgr = null; 45 private Notification.Builder mBuilder = null; 46 47 private static final String PRESET = "preset"; 48 private static final String QUALITY = "quality"; 49 private static final String SOURCE_URI = "sourceUri"; 50 private static final String SELECTED_URI = "selectedUri"; 51 private static final String DESTINATION_FILE = "destinationFile"; 52 private static final String SAVING = "saving"; 53 private static final String FLATTEN = "flatten"; 54 private static final String SIZE_FACTOR = "sizeFactor"; 55 private static final String EXIT = "exit"; 56 57 private ProcessingTaskController mProcessingTaskController; 58 private ImageSavingTask mImageSavingTask; 59 private UpdatePreviewTask mUpdatePreviewTask; 60 private HighresRenderingRequestTask mHighresRenderingRequestTask; 61 private FullresRenderingRequestTask mFullresRenderingRequestTask; 62 private RenderingRequestTask mRenderingRequestTask; 63 64 private final IBinder mBinder = new LocalBinder(); 65 private FilterShowActivity mFiltershowActivity; 66 67 private boolean mSaving = false; 68 private boolean mNeedsAlive = false; 69 setFiltershowActivity(FilterShowActivity filtershowActivity)70 public void setFiltershowActivity(FilterShowActivity filtershowActivity) { 71 mFiltershowActivity = filtershowActivity; 72 } 73 setOriginalBitmap(Bitmap originalBitmap)74 public void setOriginalBitmap(Bitmap originalBitmap) { 75 if (mUpdatePreviewTask == null) { 76 return; 77 } 78 mUpdatePreviewTask.setOriginal(originalBitmap); 79 mHighresRenderingRequestTask.setOriginal(originalBitmap); 80 mFullresRenderingRequestTask.setOriginal(originalBitmap); 81 mRenderingRequestTask.setOriginal(originalBitmap); 82 } 83 updatePreviewBuffer()84 public void updatePreviewBuffer() { 85 mHighresRenderingRequestTask.stop(); 86 mFullresRenderingRequestTask.stop(); 87 mUpdatePreviewTask.updatePreview(); 88 } 89 postRenderingRequest(RenderingRequest request)90 public void postRenderingRequest(RenderingRequest request) { 91 mRenderingRequestTask.postRenderingRequest(request); 92 } 93 postHighresRenderingRequest(ImagePreset preset, float scaleFactor, RenderingRequestCaller caller)94 public void postHighresRenderingRequest(ImagePreset preset, float scaleFactor, 95 RenderingRequestCaller caller) { 96 RenderingRequest request = new RenderingRequest(); 97 // TODO: use the triple buffer preset as UpdatePreviewTask does instead of creating a copy 98 ImagePreset passedPreset = new ImagePreset(preset); 99 request.setOriginalImagePreset(preset); 100 request.setScaleFactor(scaleFactor); 101 request.setImagePreset(passedPreset); 102 request.setType(RenderingRequest.HIGHRES_RENDERING); 103 request.setCaller(caller); 104 mHighresRenderingRequestTask.postRenderingRequest(request); 105 } 106 postFullresRenderingRequest(ImagePreset preset, float scaleFactor, Rect bounds, Rect destination, RenderingRequestCaller caller)107 public void postFullresRenderingRequest(ImagePreset preset, float scaleFactor, 108 Rect bounds, Rect destination, 109 RenderingRequestCaller caller) { 110 RenderingRequest request = new RenderingRequest(); 111 ImagePreset passedPreset = new ImagePreset(preset); 112 request.setOriginalImagePreset(preset); 113 request.setScaleFactor(scaleFactor); 114 request.setImagePreset(passedPreset); 115 request.setType(RenderingRequest.PARTIAL_RENDERING); 116 request.setCaller(caller); 117 request.setBounds(bounds); 118 request.setDestination(destination); 119 passedPreset.setPartialRendering(true, bounds); 120 mFullresRenderingRequestTask.postRenderingRequest(request); 121 } 122 setHighresPreviewScaleFactor(float highResPreviewScale)123 public void setHighresPreviewScaleFactor(float highResPreviewScale) { 124 mHighresRenderingRequestTask.setHighresPreviewScaleFactor(highResPreviewScale); 125 } 126 setPreviewScaleFactor(float previewScale)127 public void setPreviewScaleFactor(float previewScale) { 128 mHighresRenderingRequestTask.setPreviewScaleFactor(previewScale); 129 mFullresRenderingRequestTask.setPreviewScaleFactor(previewScale); 130 mRenderingRequestTask.setPreviewScaleFactor(previewScale); 131 } 132 setOriginalBitmapHighres(Bitmap originalHires)133 public void setOriginalBitmapHighres(Bitmap originalHires) { 134 mHighresRenderingRequestTask.setOriginalBitmapHighres(originalHires); 135 } 136 137 public class LocalBinder extends Binder { getService()138 public ProcessingService getService() { 139 return ProcessingService.this; 140 } 141 } 142 getSaveIntent(Context context, ImagePreset preset, File destination, Uri selectedImageUri, Uri sourceImageUri, boolean doFlatten, int quality, float sizeFactor, boolean needsExit)143 public static Intent getSaveIntent(Context context, ImagePreset preset, File destination, 144 Uri selectedImageUri, Uri sourceImageUri, boolean doFlatten, int quality, 145 float sizeFactor, boolean needsExit) { 146 Intent processIntent = new Intent(context, ProcessingService.class); 147 processIntent.putExtra(ProcessingService.SOURCE_URI, 148 sourceImageUri.toString()); 149 processIntent.putExtra(ProcessingService.SELECTED_URI, 150 selectedImageUri.toString()); 151 processIntent.putExtra(ProcessingService.QUALITY, quality); 152 processIntent.putExtra(ProcessingService.SIZE_FACTOR, sizeFactor); 153 if (destination != null) { 154 processIntent.putExtra(ProcessingService.DESTINATION_FILE, destination.toString()); 155 } 156 processIntent.putExtra(ProcessingService.PRESET, 157 preset.getJsonString(ImagePreset.JASON_SAVED)); 158 processIntent.putExtra(ProcessingService.SAVING, true); 159 processIntent.putExtra(ProcessingService.EXIT, needsExit); 160 if (doFlatten) { 161 processIntent.putExtra(ProcessingService.FLATTEN, true); 162 } 163 return processIntent; 164 } 165 166 167 @Override onCreate()168 public void onCreate() { 169 mProcessingTaskController = new ProcessingTaskController(this); 170 mImageSavingTask = new ImageSavingTask(this); 171 mUpdatePreviewTask = new UpdatePreviewTask(); 172 mHighresRenderingRequestTask = new HighresRenderingRequestTask(); 173 mFullresRenderingRequestTask = new FullresRenderingRequestTask(); 174 mRenderingRequestTask = new RenderingRequestTask(); 175 mProcessingTaskController.add(mImageSavingTask); 176 mProcessingTaskController.add(mUpdatePreviewTask); 177 mProcessingTaskController.add(mHighresRenderingRequestTask); 178 mProcessingTaskController.add(mFullresRenderingRequestTask); 179 mProcessingTaskController.add(mRenderingRequestTask); 180 setupPipeline(); 181 } 182 183 @Override onDestroy()184 public void onDestroy() { 185 tearDownPipeline(); 186 mProcessingTaskController.quit(); 187 } 188 189 @Override onStartCommand(Intent intent, int flags, int startId)190 public int onStartCommand(Intent intent, int flags, int startId) { 191 mNeedsAlive = true; 192 if (intent != null && intent.getBooleanExtra(SAVING, false)) { 193 // we save using an intent to keep the service around after the 194 // activity has been destroyed. 195 String presetJson = intent.getStringExtra(PRESET); 196 String source = intent.getStringExtra(SOURCE_URI); 197 String selected = intent.getStringExtra(SELECTED_URI); 198 String destination = intent.getStringExtra(DESTINATION_FILE); 199 int quality = intent.getIntExtra(QUALITY, 100); 200 float sizeFactor = intent.getFloatExtra(SIZE_FACTOR, 1); 201 boolean flatten = intent.getBooleanExtra(FLATTEN, false); 202 boolean exit = intent.getBooleanExtra(EXIT, false); 203 Uri sourceUri = Uri.parse(source); 204 Uri selectedUri = null; 205 if (selected != null) { 206 selectedUri = Uri.parse(selected); 207 } 208 File destinationFile = null; 209 if (destination != null) { 210 destinationFile = new File(destination); 211 } 212 ImagePreset preset = new ImagePreset(); 213 preset.readJsonFromString(presetJson); 214 mNeedsAlive = false; 215 mSaving = true; 216 handleSaveRequest(sourceUri, selectedUri, destinationFile, preset, 217 PrimaryImage.getImage().getHighresImage(), 218 flatten, quality, sizeFactor, exit); 219 } 220 return START_REDELIVER_INTENT; 221 } 222 223 @Override onBind(Intent intent)224 public IBinder onBind(Intent intent) { 225 return mBinder; 226 } 227 onStart()228 public void onStart() { 229 mNeedsAlive = true; 230 if (!mSaving && mFiltershowActivity != null) { 231 mFiltershowActivity.updateUIAfterServiceStarted(); 232 } 233 } 234 handleSaveRequest(Uri sourceUri, Uri selectedUri, File destinationFile, ImagePreset preset, Bitmap previewImage, boolean flatten, int quality, float sizeFactor, boolean exit)235 public void handleSaveRequest(Uri sourceUri, Uri selectedUri, 236 File destinationFile, ImagePreset preset, Bitmap previewImage, 237 boolean flatten, int quality, float sizeFactor, boolean exit) { 238 mNotifyMgr = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); 239 mNotifyMgr.cancelAll(); 240 241 mBuilder = 242 new Notification.Builder(this) 243 .setSmallIcon(R.drawable.filtershow_button_fx) 244 .setContentTitle(getString(R.string.filtershow_notification_label)) 245 .setContentText(getString(R.string.filtershow_notification_message)); 246 247 startForeground(mNotificationId, mBuilder.build()); 248 249 updateProgress(SaveImage.MAX_PROCESSING_STEPS, 0); 250 251 // Process the image 252 253 mImageSavingTask.saveImage(sourceUri, selectedUri, destinationFile, 254 preset, previewImage, flatten, quality, sizeFactor, exit); 255 } 256 updateNotificationWithBitmap(Bitmap bitmap)257 public void updateNotificationWithBitmap(Bitmap bitmap) { 258 mBuilder.setLargeIcon(bitmap); 259 mNotifyMgr.notify(mNotificationId, mBuilder.build()); 260 } 261 updateProgress(int max, int current)262 public void updateProgress(int max, int current) { 263 mBuilder.setProgress(max, current, false); 264 mNotifyMgr.notify(mNotificationId, mBuilder.build()); 265 } 266 completePreviewSaveImage(Uri result, boolean exit)267 public void completePreviewSaveImage(Uri result, boolean exit) { 268 if (exit && !mNeedsAlive && !mFiltershowActivity.isSimpleEditAction()) { 269 mFiltershowActivity.completeSaveImage(result); 270 } 271 } 272 completeSaveImage(Uri result, boolean exit)273 public void completeSaveImage(Uri result, boolean exit) { 274 if (SHOW_IMAGE) { 275 // TODO: we should update the existing image in Gallery instead 276 Intent viewImage = new Intent(Intent.ACTION_VIEW, result); 277 viewImage.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 278 startActivity(viewImage); 279 } 280 mNotifyMgr.cancel(mNotificationId); 281 if (!exit) { 282 stopForeground(true); 283 stopSelf(); 284 return; 285 } 286 stopForeground(true); 287 stopSelf(); 288 if (mNeedsAlive) { 289 // If the app has been restarted while we were saving... 290 mFiltershowActivity.updateUIAfterServiceStarted(); 291 } else if (exit || mFiltershowActivity.isSimpleEditAction()) { 292 // terminate now 293 mFiltershowActivity.completeSaveImage(result); 294 } 295 } 296 setupPipeline()297 private void setupPipeline() { 298 Resources res = getResources(); 299 FiltersManager.setResources(res); 300 CachingPipeline.createRenderscriptContext(this); 301 302 FiltersManager filtersManager = FiltersManager.getManager(); 303 filtersManager.addLooks(this); 304 filtersManager.addBorders(this); 305 filtersManager.addTools(this); 306 filtersManager.addEffects(); 307 308 FiltersManager highresFiltersManager = FiltersManager.getHighresManager(); 309 highresFiltersManager.addLooks(this); 310 highresFiltersManager.addBorders(this); 311 highresFiltersManager.addTools(this); 312 highresFiltersManager.addEffects(); 313 } 314 tearDownPipeline()315 private void tearDownPipeline() { 316 ImageFilter.resetStatics(); 317 FiltersManager.reset(); 318 CachingPipeline.destroyRenderScriptContext(); 319 } 320 321 static { 322 System.loadLibrary("jni_filtershow_filters"); 323 } 324 } 325