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.MasterImage; 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 70 public void setFiltershowActivity(FilterShowActivity filtershowActivity) { 71 mFiltershowActivity = filtershowActivity; 72 } 73 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 84 public void updatePreviewBuffer() { 85 mHighresRenderingRequestTask.stop(); 86 mFullresRenderingRequestTask.stop(); 87 mUpdatePreviewTask.updatePreview(); 88 } 89 90 public void postRenderingRequest(RenderingRequest request) { 91 mRenderingRequestTask.postRenderingRequest(request); 92 } 93 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 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 123 public void setHighresPreviewScaleFactor(float highResPreviewScale) { 124 mHighresRenderingRequestTask.setHighresPreviewScaleFactor(highResPreviewScale); 125 } 126 127 public void setPreviewScaleFactor(float previewScale) { 128 mHighresRenderingRequestTask.setPreviewScaleFactor(previewScale); 129 mFullresRenderingRequestTask.setPreviewScaleFactor(previewScale); 130 mRenderingRequestTask.setPreviewScaleFactor(previewScale); 131 } 132 133 public void setOriginalBitmapHighres(Bitmap originalHires) { 134 mHighresRenderingRequestTask.setOriginalBitmapHighres(originalHires); 135 } 136 137 public class LocalBinder extends Binder { 138 public ProcessingService getService() { 139 return ProcessingService.this; 140 } 141 } 142 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 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 184 public void onDestroy() { 185 tearDownPipeline(); 186 mProcessingTaskController.quit(); 187 } 188 189 @Override 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 MasterImage.getImage().getHighresImage(), 218 flatten, quality, sizeFactor, exit); 219 } 220 return START_REDELIVER_INTENT; 221 } 222 223 @Override 224 public IBinder onBind(Intent intent) { 225 return mBinder; 226 } 227 228 public void onStart() { 229 mNeedsAlive = true; 230 if (!mSaving && mFiltershowActivity != null) { 231 mFiltershowActivity.updateUIAfterServiceStarted(); 232 } 233 } 234 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 257 public void updateNotificationWithBitmap(Bitmap bitmap) { 258 mBuilder.setLargeIcon(bitmap); 259 mNotifyMgr.notify(mNotificationId, mBuilder.build()); 260 } 261 262 public void updateProgress(int max, int current) { 263 mBuilder.setProgress(max, current, false); 264 mNotifyMgr.notify(mNotificationId, mBuilder.build()); 265 } 266 267 public void completePreviewSaveImage(Uri result, boolean exit) { 268 if (exit && !mNeedsAlive && !mFiltershowActivity.isSimpleEditAction()) { 269 mFiltershowActivity.completeSaveImage(result); 270 } 271 } 272 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 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 315 private void tearDownPipeline() { 316 ImageFilter.resetStatics(); 317 FiltersManager.getPreviewManager().freeRSFilterScripts(); 318 FiltersManager.getManager().freeRSFilterScripts(); 319 FiltersManager.getHighresManager().freeRSFilterScripts(); 320 FiltersManager.reset(); 321 CachingPipeline.destroyRenderScriptContext(); 322 } 323 324 static { 325 System.loadLibrary("jni_filtershow_filters"); 326 } 327 } 328