Home | History | Annotate | Download | only in pipeline
      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