OSDN Git Service

c7de0183757d6738c5031064663998951d87715d
[android-x86/packages-apps-Gallery2.git] / src / com / android / gallery3d / filtershow / FilterShowActivity.java
1 /*
2  * Copyright (C) 2012 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;
18
19 import android.annotation.TargetApi;
20 import android.app.ActionBar;
21 import android.app.Activity;
22 import android.app.ProgressDialog;
23 import android.app.WallpaperManager;
24 import android.content.ContentValues;
25 import android.content.Intent;
26 import android.content.res.Configuration;
27 import android.content.res.Resources;
28 import android.graphics.Bitmap;
29 import android.graphics.BitmapFactory;
30 import android.graphics.Color;
31 import android.graphics.Point;
32 import android.graphics.drawable.Drawable;
33 import android.net.Uri;
34 import android.os.AsyncTask;
35 import android.os.Bundle;
36 import android.provider.MediaStore;
37 import android.util.DisplayMetrics;
38 import android.util.Log;
39 import android.util.TypedValue;
40 import android.view.Display;
41 import android.view.Menu;
42 import android.view.MenuItem;
43 import android.view.View;
44 import android.view.View.OnClickListener;
45 import android.view.WindowManager;
46 import android.widget.AdapterView;
47 import android.widget.AdapterView.OnItemClickListener;
48 import android.widget.ImageButton;
49 import android.widget.LinearLayout;
50 import android.widget.ListView;
51 import android.widget.SeekBar;
52 import android.widget.ShareActionProvider;
53 import android.widget.ShareActionProvider.OnShareTargetSelectedListener;
54 import android.widget.Toast;
55
56 import com.android.gallery3d.R;
57 import com.android.gallery3d.data.LocalAlbum;
58 import com.android.gallery3d.filtershow.cache.ImageLoader;
59 import com.android.gallery3d.filtershow.filters.ImageFilter;
60 import com.android.gallery3d.filtershow.filters.ImageFilterBorder;
61 import com.android.gallery3d.filtershow.filters.ImageFilterBwFilter;
62 import com.android.gallery3d.filtershow.filters.ImageFilterContrast;
63 import com.android.gallery3d.filtershow.filters.ImageFilterCurves;
64 import com.android.gallery3d.filtershow.filters.ImageFilterExposure;
65 import com.android.gallery3d.filtershow.filters.ImageFilterFx;
66 import com.android.gallery3d.filtershow.filters.ImageFilterHue;
67 import com.android.gallery3d.filtershow.filters.ImageFilterParametricBorder;
68 import com.android.gallery3d.filtershow.filters.ImageFilterRS;
69 import com.android.gallery3d.filtershow.filters.ImageFilterSaturated;
70 import com.android.gallery3d.filtershow.filters.ImageFilterShadows;
71 import com.android.gallery3d.filtershow.filters.ImageFilterSharpen;
72 import com.android.gallery3d.filtershow.filters.ImageFilterTinyPlanet;
73 import com.android.gallery3d.filtershow.filters.ImageFilterVibrance;
74 import com.android.gallery3d.filtershow.filters.ImageFilterVignette;
75 import com.android.gallery3d.filtershow.filters.ImageFilterWBalance;
76 import com.android.gallery3d.filtershow.imageshow.ImageBorder;
77 import com.android.gallery3d.filtershow.imageshow.ImageCrop;
78 import com.android.gallery3d.filtershow.imageshow.ImageFlip;
79 import com.android.gallery3d.filtershow.imageshow.ImageRedEyes;
80 import com.android.gallery3d.filtershow.imageshow.ImageRotate;
81 import com.android.gallery3d.filtershow.imageshow.ImageShow;
82 import com.android.gallery3d.filtershow.imageshow.ImageSmallBorder;
83 import com.android.gallery3d.filtershow.imageshow.ImageSmallFilter;
84 import com.android.gallery3d.filtershow.imageshow.ImageStraighten;
85 import com.android.gallery3d.filtershow.imageshow.ImageTinyPlanet;
86 import com.android.gallery3d.filtershow.imageshow.ImageZoom;
87 import com.android.gallery3d.filtershow.presets.ImagePreset;
88 import com.android.gallery3d.filtershow.provider.SharedImageProvider;
89 import com.android.gallery3d.filtershow.tools.SaveCopyTask;
90 import com.android.gallery3d.filtershow.ui.FramedTextButton;
91 import com.android.gallery3d.filtershow.ui.ImageButtonTitle;
92 import com.android.gallery3d.filtershow.ui.ImageCurves;
93 import com.android.gallery3d.filtershow.ui.Spline;
94 import com.android.gallery3d.util.GalleryUtils;
95
96 import java.io.File;
97 import java.io.IOException;
98 import java.lang.ref.WeakReference;
99 import java.util.Vector;
100
101 @TargetApi(16)
102 public class FilterShowActivity extends Activity implements OnItemClickListener,
103         OnShareTargetSelectedListener {
104
105     // fields for supporting crop action
106     public static final String CROP_ACTION = "com.android.camera.action.CROP";
107     private CropExtras mCropExtras = null;
108
109     public static final String TINY_PLANET_ACTION = "com.android.camera.action.TINY_PLANET";
110     public static final String LAUNCH_FULLSCREEN = "launch-fullscreen";
111     public static final int MAX_BMAP_IN_INTENT = 990000;
112     private final PanelController mPanelController = new PanelController();
113     private ImageLoader mImageLoader = null;
114     private ImageShow mImageShow = null;
115     private ImageCurves mImageCurves = null;
116     private ImageBorder mImageBorders = null;
117     private ImageRedEyes mImageRedEyes = null;
118     private ImageStraighten mImageStraighten = null;
119     private ImageZoom mImageZoom = null;
120     private ImageCrop mImageCrop = null;
121     private ImageRotate mImageRotate = null;
122     private ImageFlip mImageFlip = null;
123     private ImageTinyPlanet mImageTinyPlanet = null;
124
125     private View mListFx = null;
126     private View mListBorders = null;
127     private View mListGeometry = null;
128     private View mListColors = null;
129     private View mListFilterButtons = null;
130     private View mSaveButton = null;
131
132     private ImageButton mFxButton = null;
133     private ImageButton mBorderButton = null;
134     private ImageButton mGeometryButton = null;
135     private ImageButton mColorsButton = null;
136
137     private ImageSmallFilter mCurrentImageSmallFilter = null;
138     private static final int SELECT_PICTURE = 1;
139     private static final String LOGTAG = "FilterShowActivity";
140     protected static final boolean ANIMATE_PANELS = true;
141     private static int mImageBorderSize = 4; // in percent
142
143     private boolean mShowingHistoryPanel = false;
144     private boolean mShowingImageStatePanel = false;
145
146     private final Vector<ImageShow> mImageViews = new Vector<ImageShow>();
147     private final Vector<View> mListViews = new Vector<View>();
148     private final Vector<ImageButton> mBottomPanelButtons = new Vector<ImageButton>();
149
150     private ShareActionProvider mShareActionProvider;
151     private File mSharedOutputFile = null;
152
153     private boolean mSharingImage = false;
154
155     private WeakReference<ProgressDialog> mSavingProgressDialog;
156     private static final int SEEK_BAR_MAX = 600;
157
158     private LoadBitmapTask mLoadBitmapTask;
159     private ImageSmallFilter mNullFxFilter;
160     private ImageSmallFilter mNullBorderFilter;
161
162     @Override
163     public void onCreate(Bundle savedInstanceState) {
164         super.onCreate(savedInstanceState);
165
166         ImageFilterRS.setRenderScriptContext(this);
167
168         ImageShow.setDefaultBackgroundColor(getResources().getColor(R.color.background_screen));
169         ImageSmallFilter.setDefaultBackgroundColor(getResources().getColor(
170                 R.color.background_main_toolbar));
171         // TODO: get those values from XML.
172         ImageZoom.setZoomedSize(getPixelsFromDip(256));
173         FramedTextButton.setTextSize((int) getPixelsFromDip(14));
174         FramedTextButton.setTrianglePadding((int) getPixelsFromDip(4));
175         FramedTextButton.setTriangleSize((int) getPixelsFromDip(10));
176         ImageShow.setTextSize((int) getPixelsFromDip(12));
177         ImageShow.setTextPadding((int) getPixelsFromDip(10));
178         ImageShow.setOriginalTextMargin((int) getPixelsFromDip(4));
179         ImageShow.setOriginalTextSize((int) getPixelsFromDip(18));
180         ImageShow.setOriginalText(getResources().getString(R.string.original_picture_text));
181         ImageButtonTitle.setTextSize((int) getPixelsFromDip(12));
182         ImageButtonTitle.setTextPadding((int) getPixelsFromDip(10));
183         ImageSmallFilter.setMargin((int) getPixelsFromDip(3));
184         ImageSmallFilter.setTextMargin((int) getPixelsFromDip(4));
185         Drawable curveHandle = getResources().getDrawable(R.drawable.camera_crop);
186         int curveHandleSize = (int) getResources().getDimension(R.dimen.crop_indicator_size);
187         Spline.setCurveHandle(curveHandle, curveHandleSize);
188         Spline.setCurveWidth((int) getPixelsFromDip(3));
189
190         setContentView(R.layout.filtershow_activity);
191         ActionBar actionBar = getActionBar();
192         actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
193         actionBar.setCustomView(R.layout.filtershow_actionbar);
194
195         mSaveButton = actionBar.getCustomView();
196         mSaveButton.setOnClickListener(new OnClickListener() {
197             @Override
198             public void onClick(View view) {
199                 saveImage();
200             }
201         });
202
203         mImageLoader = new ImageLoader(this, getApplicationContext());
204
205         LinearLayout listFilters = (LinearLayout) findViewById(R.id.listFilters);
206         LinearLayout listBorders = (LinearLayout) findViewById(R.id.listBorders);
207         LinearLayout listColors = (LinearLayout) findViewById(R.id.listColorsFx);
208
209         mImageShow = (ImageShow) findViewById(R.id.imageShow);
210         mImageCurves = (ImageCurves) findViewById(R.id.imageCurves);
211         mImageBorders = (ImageBorder) findViewById(R.id.imageBorder);
212         mImageStraighten = (ImageStraighten) findViewById(R.id.imageStraighten);
213         mImageZoom = (ImageZoom) findViewById(R.id.imageZoom);
214         mImageCrop = (ImageCrop) findViewById(R.id.imageCrop);
215         mImageRotate = (ImageRotate) findViewById(R.id.imageRotate);
216         mImageFlip = (ImageFlip) findViewById(R.id.imageFlip);
217         mImageTinyPlanet = (ImageTinyPlanet) findViewById(R.id.imageTinyPlanet);
218         mImageRedEyes = (ImageRedEyes) findViewById(R.id.imageRedEyes);
219
220         mImageCrop.setAspectTextSize((int) getPixelsFromDip(18));
221         ImageCrop.setTouchTolerance((int) getPixelsFromDip(25));
222         ImageCrop.setMinCropSize((int) getPixelsFromDip(55));
223         mImageViews.add(mImageShow);
224         mImageViews.add(mImageCurves);
225         mImageViews.add(mImageBorders);
226         mImageViews.add(mImageStraighten);
227         mImageViews.add(mImageZoom);
228         mImageViews.add(mImageCrop);
229         mImageViews.add(mImageRotate);
230         mImageViews.add(mImageFlip);
231         mImageViews.add(mImageTinyPlanet);
232         mImageViews.add(mImageRedEyes);
233         for (ImageShow imageShow : mImageViews) {
234             mImageLoader.addCacheListener(imageShow);
235         }
236
237         mListFx = findViewById(R.id.fxList);
238         mListBorders = findViewById(R.id.bordersList);
239         mListGeometry = findViewById(R.id.geometryList);
240         mListFilterButtons = findViewById(R.id.filterButtonsList);
241         mListColors = findViewById(R.id.colorsFxList);
242         mListViews.add(mListFx);
243         mListViews.add(mListBorders);
244         mListViews.add(mListGeometry);
245         mListViews.add(mListFilterButtons);
246         mListViews.add(mListColors);
247
248         mFxButton = (ImageButton) findViewById(R.id.fxButton);
249         mBorderButton = (ImageButton) findViewById(R.id.borderButton);
250         mGeometryButton = (ImageButton) findViewById(R.id.geometryButton);
251         mColorsButton = (ImageButton) findViewById(R.id.colorsButton);
252
253         mImageShow.setImageLoader(mImageLoader);
254         mImageCurves.setImageLoader(mImageLoader);
255         mImageCurves.setMaster(mImageShow);
256         mImageBorders.setImageLoader(mImageLoader);
257         mImageBorders.setMaster(mImageShow);
258         mImageStraighten.setImageLoader(mImageLoader);
259         mImageStraighten.setMaster(mImageShow);
260         mImageZoom.setImageLoader(mImageLoader);
261         mImageZoom.setMaster(mImageShow);
262         mImageCrop.setImageLoader(mImageLoader);
263         mImageCrop.setMaster(mImageShow);
264         mImageRotate.setImageLoader(mImageLoader);
265         mImageRotate.setMaster(mImageShow);
266         mImageFlip.setImageLoader(mImageLoader);
267         mImageFlip.setMaster(mImageShow);
268         mImageTinyPlanet.setImageLoader(mImageLoader);
269         mImageTinyPlanet.setMaster(mImageShow);
270         mImageRedEyes.setImageLoader(mImageLoader);
271         mImageRedEyes.setMaster(mImageShow);
272
273         mPanelController.setActivity(this);
274
275         mPanelController.addImageView(findViewById(R.id.imageShow));
276         mPanelController.addImageView(findViewById(R.id.imageCurves));
277         mPanelController.addImageView(findViewById(R.id.imageBorder));
278         mPanelController.addImageView(findViewById(R.id.imageStraighten));
279         mPanelController.addImageView(findViewById(R.id.imageCrop));
280         mPanelController.addImageView(findViewById(R.id.imageRotate));
281         mPanelController.addImageView(findViewById(R.id.imageFlip));
282         mPanelController.addImageView(findViewById(R.id.imageZoom));
283         mPanelController.addImageView(findViewById(R.id.imageTinyPlanet));
284         mPanelController.addImageView(findViewById(R.id.imageRedEyes));
285
286         mPanelController.addPanel(mFxButton, mListFx, 0);
287         mPanelController.addPanel(mBorderButton, mListBorders, 1);
288
289         mPanelController.addPanel(mGeometryButton, mListGeometry, 2);
290         mPanelController.addComponent(mGeometryButton, findViewById(R.id.straightenButton));
291         mPanelController.addComponent(mGeometryButton, findViewById(R.id.cropButton));
292         mPanelController.addComponent(mGeometryButton, findViewById(R.id.rotateButton));
293         mPanelController.addComponent(mGeometryButton, findViewById(R.id.flipButton));
294         mPanelController.addComponent(mGeometryButton, findViewById(R.id.redEyeButton));
295
296         mPanelController.addPanel(mColorsButton, mListColors, 3);
297
298         ImageFilter[] filters = {
299                 new ImageFilterTinyPlanet(),
300                 new ImageFilterWBalance(),
301                 new ImageFilterExposure(),
302                 new ImageFilterVignette(),
303                 new ImageFilterContrast(),
304                 new ImageFilterShadows(),
305                 new ImageFilterVibrance(),
306                 new ImageFilterSharpen(),
307                 new ImageFilterCurves(),
308                 new ImageFilterHue(),
309                 new ImageFilterSaturated(),
310                 new ImageFilterBwFilter()
311         };
312
313         for (int i = 0; i < filters.length; i++) {
314             ImageSmallFilter fView = new ImageSmallFilter(this);
315             filters[i].setParameter(filters[i].getPreviewParameter());
316             filters[i].setName(getString(filters[i].getTextId()));
317             fView.setImageFilter(filters[i]);
318             fView.setController(this);
319             fView.setImageLoader(mImageLoader);
320             fView.setId(filters[i].getButtonId());
321             if (filters[i].getOverlayBitmaps() != 0) {
322                 Bitmap bitmap = BitmapFactory.decodeResource(getResources(),
323                         filters[i].getOverlayBitmaps());
324                 fView.setOverlayBitmap(bitmap);
325             }
326             mPanelController.addComponent(mColorsButton, fView);
327             mPanelController.addFilter(filters[i]);
328             listColors.addView(fView);
329         }
330
331         mPanelController.addView(findViewById(R.id.applyEffect));
332         mPanelController.addView(findViewById(R.id.pickCurvesChannel));
333         mPanelController.addView(findViewById(R.id.aspect));
334         findViewById(R.id.resetOperationsButton).setOnClickListener(
335                 createOnClickResetOperationsButton());
336
337         ListView operationsList = (ListView) findViewById(R.id.operationsList);
338         operationsList.setAdapter(mImageShow.getHistory());
339         operationsList.setOnItemClickListener(this);
340         ListView imageStateList = (ListView) findViewById(R.id.imageStateList);
341         imageStateList.setAdapter(mImageShow.getImageStateAdapter());
342         mImageLoader.setAdapter(mImageShow.getHistory());
343
344         fillListImages(listFilters);
345         fillListBorders(listBorders);
346
347         SeekBar seekBar = (SeekBar) findViewById(R.id.filterSeekBar);
348         seekBar.setMax(SEEK_BAR_MAX);
349
350         mImageShow.setSeekBar(seekBar);
351         mImageZoom.setSeekBar(seekBar);
352         mImageTinyPlanet.setSeekBar(seekBar);
353         mPanelController.setRowPanel(findViewById(R.id.secondRowPanel));
354         mPanelController.setUtilityPanel(this, findViewById(R.id.filterButtonsList),
355                 findViewById(R.id.applyEffect), findViewById(R.id.aspect),
356                 findViewById(R.id.pickCurvesChannel));
357         mPanelController.setMasterImage(mImageShow);
358         mPanelController.setCurrentPanel(mFxButton);
359         Intent intent = getIntent();
360         if (intent.getBooleanExtra(LAUNCH_FULLSCREEN, false)) {
361             getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
362         }
363
364         if (intent.getData() != null) {
365             startLoadBitmap(intent.getData());
366         } else {
367             pickImage();
368         }
369
370         // Handle behavior for various actions
371         String action = intent.getAction();
372         if (action.equalsIgnoreCase(CROP_ACTION)) {
373             Bundle extras = intent.getExtras();
374             if (extras != null) {
375                 mCropExtras = new CropExtras(extras.getInt(CropExtras.KEY_OUTPUT_X, 0),
376                         extras.getInt(CropExtras.KEY_OUTPUT_Y, 0),
377                         extras.getBoolean(CropExtras.KEY_SCALE, true) &&
378                                 extras.getBoolean(CropExtras.KEY_SCALE_UP_IF_NEEDED, false),
379                         extras.getInt(CropExtras.KEY_ASPECT_X, 0),
380                         extras.getInt(CropExtras.KEY_ASPECT_Y, 0),
381                         extras.getBoolean(CropExtras.KEY_SET_AS_WALLPAPER, false),
382                         extras.getBoolean(CropExtras.KEY_RETURN_DATA, false),
383                         (Uri) extras.getParcelable(MediaStore.EXTRA_OUTPUT),
384                         extras.getString(CropExtras.KEY_OUTPUT_FORMAT),
385                         extras.getBoolean(CropExtras.KEY_SHOW_WHEN_LOCKED, false),
386                         extras.getFloat(CropExtras.KEY_SPOTLIGHT_X),
387                         extras.getFloat(CropExtras.KEY_SPOTLIGHT_Y));
388
389                 if (mCropExtras.getShowWhenLocked()) {
390                     getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
391                 }
392                 mImageShow.getImagePreset().mGeoData.setCropExtras(mCropExtras);
393
394                 mImageCrop.setExtras(mCropExtras);
395                 String s = getString(R.string.Fixed);
396                 mImageCrop.setAspectString(s);
397                 mImageCrop.setCropActionFlag(true);
398                 mPanelController.setFixedAspect(mCropExtras.getAspectX() > 0
399                         && mCropExtras.getAspectY() > 0);
400             }
401             mPanelController.showComponent(findViewById(R.id.cropButton));
402         } else if (action.equalsIgnoreCase(TINY_PLANET_ACTION)) {
403             mPanelController.showComponent(findViewById(R.id.tinyplanetButton));
404         }
405     }
406
407     private void startLoadBitmap(Uri uri) {
408         final View filters = findViewById(R.id.filtersPanel);
409         final View loading = findViewById(R.id.loading);
410         loading.setVisibility(View.VISIBLE);
411         filters.setVisibility(View.INVISIBLE);
412         View tinyPlanetView = findViewById(R.id.tinyplanetButton);
413         if (tinyPlanetView != null) {
414             tinyPlanetView.setVisibility(View.GONE);
415         }
416         mLoadBitmapTask = new LoadBitmapTask(tinyPlanetView);
417         mLoadBitmapTask.execute(uri);
418     }
419
420     private class LoadBitmapTask extends AsyncTask<Uri, Boolean, Boolean> {
421         View mTinyPlanetButton;
422         int mBitmapSize;
423
424         public LoadBitmapTask(View button) {
425             mTinyPlanetButton = button;
426             mBitmapSize = getScreenImageSize();
427         }
428
429         @Override
430         protected Boolean doInBackground(Uri... params) {
431             if (!mImageLoader.loadBitmap(params[0], mBitmapSize)) {
432                 return false;
433             }
434             publishProgress(mImageLoader.queryLightCycle360());
435             return true;
436         }
437
438         @Override
439         protected void onProgressUpdate(Boolean... values) {
440             super.onProgressUpdate(values);
441             if (isCancelled()) {
442                 return;
443             }
444             final View filters = findViewById(R.id.filtersPanel);
445             final View loading = findViewById(R.id.loading);
446             loading.setVisibility(View.GONE);
447             filters.setVisibility(View.VISIBLE);
448             if (values[0]) {
449                 mTinyPlanetButton.setVisibility(View.VISIBLE);
450             }
451         }
452
453         @Override
454         protected void onPostExecute(Boolean result) {
455             if (isCancelled()) {
456                 return;
457             }
458             if (!result) {
459                 cannotLoadImage();
460             }
461
462             mLoadBitmapTask = null;
463             super.onPostExecute(result);
464         }
465
466     }
467
468     @Override
469     protected void onDestroy() {
470         if (mLoadBitmapTask != null) {
471             mLoadBitmapTask.cancel(false);
472         }
473         super.onDestroy();
474     }
475
476     private int translateMainPanel(View viewPanel) {
477         int accessoryPanelWidth = viewPanel.getWidth();
478         int mainViewWidth = findViewById(R.id.mainView).getWidth();
479         int mainPanelWidth = mImageShow.getDisplayedImageBounds().width();
480         if (mainPanelWidth == 0) {
481             mainPanelWidth = mainViewWidth;
482         }
483         int filtersPanelWidth = findViewById(R.id.filtersPanel).getWidth();
484         if (mainPanelWidth < filtersPanelWidth) {
485             mainPanelWidth = filtersPanelWidth;
486         }
487         int leftOver = mainViewWidth - mainPanelWidth - accessoryPanelWidth;
488         if (leftOver < 0) {
489             return -accessoryPanelWidth;
490         }
491         return 0;
492     }
493
494     private int getScreenImageSize() {
495         DisplayMetrics metrics = new DisplayMetrics();
496         Display display = getWindowManager().getDefaultDisplay();
497         Point size = new Point();
498         display.getSize(size);
499         display.getMetrics(metrics);
500         int msize = Math.min(size.x, size.y);
501         return (133 * msize) / metrics.densityDpi;
502     }
503
504     private void showSavingProgress(String albumName) {
505         ProgressDialog progress;
506         if (mSavingProgressDialog != null) {
507             progress = mSavingProgressDialog.get();
508             if (progress != null) {
509                 progress.show();
510                 return;
511             }
512         }
513         // TODO: Allow cancellation of the saving process
514         String progressText;
515         if (albumName == null) {
516             progressText = getString(R.string.saving_image);
517         } else {
518             progressText = getString(R.string.filtershow_saving_image, albumName);
519         }
520         progress = ProgressDialog.show(this, "", progressText, true, false);
521         mSavingProgressDialog = new WeakReference<ProgressDialog>(progress);
522     }
523
524     private void hideSavingProgress() {
525         if (mSavingProgressDialog != null) {
526             ProgressDialog progress = mSavingProgressDialog.get();
527             if (progress != null)
528                 progress.dismiss();
529         }
530     }
531
532     public void completeSaveImage(Uri saveUri) {
533         if (mSharingImage && mSharedOutputFile != null) {
534             // Image saved, we unblock the content provider
535             Uri uri = Uri.withAppendedPath(SharedImageProvider.CONTENT_URI,
536                     Uri.encode(mSharedOutputFile.getAbsolutePath()));
537             ContentValues values = new ContentValues();
538             values.put(SharedImageProvider.PREPARE, false);
539             getContentResolver().insert(uri, values);
540         }
541         setResult(RESULT_OK, new Intent().setData(saveUri));
542         hideSavingProgress();
543         finish();
544     }
545
546     @Override
547     public boolean onShareTargetSelected(ShareActionProvider arg0, Intent arg1) {
548         // First, let's tell the SharedImageProvider that it will need to wait
549         // for the image
550         Uri uri = Uri.withAppendedPath(SharedImageProvider.CONTENT_URI,
551                 Uri.encode(mSharedOutputFile.getAbsolutePath()));
552         ContentValues values = new ContentValues();
553         values.put(SharedImageProvider.PREPARE, true);
554         getContentResolver().insert(uri, values);
555         mSharingImage = true;
556
557         // Process and save the image in the background.
558         showSavingProgress(null);
559         mImageShow.saveImage(this, mSharedOutputFile);
560         return true;
561     }
562
563     private Intent getDefaultShareIntent() {
564         Intent intent = new Intent(Intent.ACTION_SEND);
565         intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
566         intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
567         intent.setType(SharedImageProvider.MIME_TYPE);
568         mSharedOutputFile = SaveCopyTask.getNewFile(this, mImageLoader.getUri());
569         Uri uri = Uri.withAppendedPath(SharedImageProvider.CONTENT_URI,
570                 Uri.encode(mSharedOutputFile.getAbsolutePath()));
571         intent.putExtra(Intent.EXTRA_STREAM, uri);
572         return intent;
573     }
574
575     @Override
576     public boolean onCreateOptionsMenu(Menu menu) {
577         getMenuInflater().inflate(R.menu.filtershow_activity_menu, menu);
578         MenuItem showHistory = menu.findItem(R.id.operationsButton);
579         if (mShowingHistoryPanel) {
580             showHistory.setTitle(R.string.hide_history_panel);
581         } else {
582             showHistory.setTitle(R.string.show_history_panel);
583         }
584         MenuItem showState = menu.findItem(R.id.showImageStateButton);
585         if (mShowingImageStatePanel) {
586             showState.setTitle(R.string.hide_imagestate_panel);
587         } else {
588             showState.setTitle(R.string.show_imagestate_panel);
589         }
590         mShareActionProvider = (ShareActionProvider) menu.findItem(R.id.menu_share)
591                 .getActionProvider();
592         mShareActionProvider.setShareIntent(getDefaultShareIntent());
593         mShareActionProvider.setOnShareTargetSelectedListener(this);
594
595         MenuItem undoItem = menu.findItem(R.id.undoButton);
596         MenuItem redoItem = menu.findItem(R.id.redoButton);
597         MenuItem resetItem = menu.findItem(R.id.resetHistoryButton);
598         mImageShow.getHistory().setMenuItems(undoItem, redoItem, resetItem);
599         return true;
600     }
601
602     @Override
603     public void onPause() {
604         super.onPause();
605         if (mShareActionProvider != null) {
606             mShareActionProvider.setOnShareTargetSelectedListener(null);
607         }
608     }
609
610     @Override
611     public void onResume() {
612         super.onResume();
613         if (mShareActionProvider != null) {
614             mShareActionProvider.setOnShareTargetSelectedListener(this);
615         }
616     }
617
618     @Override
619     public boolean onOptionsItemSelected(MenuItem item) {
620         switch (item.getItemId()) {
621             case R.id.undoButton: {
622                 HistoryAdapter adapter = mImageShow.getHistory();
623                 int position = adapter.undo();
624                 mImageShow.onItemClick(position);
625                 mImageShow.showToast("Undo");
626                 invalidateViews();
627                 return true;
628             }
629             case R.id.redoButton: {
630                 HistoryAdapter adapter = mImageShow.getHistory();
631                 int position = adapter.redo();
632                 mImageShow.onItemClick(position);
633                 mImageShow.showToast("Redo");
634                 invalidateViews();
635                 return true;
636             }
637             case R.id.resetHistoryButton: {
638                 resetHistory();
639                 return true;
640             }
641             case R.id.showImageStateButton: {
642                 toggleImageStatePanel();
643                 return true;
644             }
645             case R.id.operationsButton: {
646                 toggleHistoryPanel();
647                 return true;
648             }
649             case android.R.id.home: {
650                 saveImage();
651                 return true;
652             }
653         }
654         return false;
655     }
656
657     public void enableSave(boolean enable) {
658         if (mSaveButton != null)
659             mSaveButton.setEnabled(enable);
660     }
661
662     private void fillListImages(LinearLayout listFilters) {
663         // TODO: use listview
664         // TODO: load the filters straight from the filesystem
665
666         ImageFilterFx[] fxArray = new ImageFilterFx[18];
667         int p = 0;
668
669         int[] drawid = {
670                 R.drawable.filtershow_fx_0005_punch,
671                 R.drawable.filtershow_fx_0000_vintage,
672                 R.drawable.filtershow_fx_0004_bw_contrast,
673                 R.drawable.filtershow_fx_0002_bleach,
674                 R.drawable.filtershow_fx_0001_instant,
675                 R.drawable.filtershow_fx_0007_washout,
676                 R.drawable.filtershow_fx_0003_blue_crush,
677                 R.drawable.filtershow_fx_0008_washout_color,
678                 R.drawable.filtershow_fx_0006_x_process
679         };
680
681         int[] fxNameid = {
682                 R.string.ffx_punch,
683                 R.string.ffx_vintage,
684                 R.string.ffx_bw_contrast,
685                 R.string.ffx_bleach,
686                 R.string.ffx_instant,
687                 R.string.ffx_washout,
688                 R.string.ffx_blue_crush,
689                 R.string.ffx_washout_color,
690                 R.string.ffx_x_process
691         };
692
693         ImagePreset preset = new ImagePreset(getString(R.string.history_original)); // empty
694         preset.setImageLoader(mImageLoader);
695         mNullFxFilter = new ImageSmallFilter(this);
696
697         mNullFxFilter.setSelected(true);
698         mCurrentImageSmallFilter = mNullFxFilter;
699
700         mNullFxFilter.setImageFilter(new ImageFilterFx(null, getString(R.string.none)));
701
702         mNullFxFilter.setController(this);
703         mNullFxFilter.setImageLoader(mImageLoader);
704         listFilters.addView(mNullFxFilter);
705         ImageSmallFilter previousFilter = mNullFxFilter;
706
707         BitmapFactory.Options o = new BitmapFactory.Options();
708         o.inScaled = false;
709
710         for (int i = 0; i < drawid.length; i++) {
711             Bitmap b = BitmapFactory.decodeResource(getResources(), drawid[i], o);
712             fxArray[p++] = new ImageFilterFx(b, getString(fxNameid[i]));
713         }
714         ImageSmallFilter filter;
715         for (int i = 0; i < p; i++) {
716             filter = new ImageSmallFilter(this);
717             filter.setImageFilter(fxArray[i]);
718             filter.setController(this);
719             filter.setNulfilter(mNullFxFilter);
720             filter.setImageLoader(mImageLoader);
721             listFilters.addView(filter);
722             previousFilter = filter;
723         }
724
725         // Default preset (original)
726         mImageShow.setImagePreset(preset);
727     }
728
729     private void fillListBorders(LinearLayout listBorders) {
730         // TODO: use listview
731         // TODO: load the borders straight from the filesystem
732         int p = 0;
733         ImageFilter[] borders = new ImageFilter[12];
734         borders[p++] = new ImageFilterBorder(null);
735
736         Drawable npd1 = getResources().getDrawable(R.drawable.filtershow_border_4x5);
737         borders[p++] = new ImageFilterBorder(npd1);
738         Drawable npd2 = getResources().getDrawable(R.drawable.filtershow_border_brush);
739         borders[p++] = new ImageFilterBorder(npd2);
740         Drawable npd3 = getResources().getDrawable(R.drawable.filtershow_border_grunge);
741         borders[p++] = new ImageFilterBorder(npd3);
742         Drawable npd4 = getResources().getDrawable(R.drawable.filtershow_border_sumi_e);
743         borders[p++] = new ImageFilterBorder(npd4);
744         Drawable npd5 = getResources().getDrawable(R.drawable.filtershow_border_tape);
745         borders[p++] = new ImageFilterBorder(npd5);
746         borders[p++] = new ImageFilterParametricBorder(Color.BLACK, mImageBorderSize, 0);
747         borders[p++] = new ImageFilterParametricBorder(Color.BLACK, mImageBorderSize,
748                 mImageBorderSize);
749         borders[p++] = new ImageFilterParametricBorder(Color.WHITE, mImageBorderSize, 0);
750         borders[p++] = new ImageFilterParametricBorder(Color.WHITE, mImageBorderSize,
751                 mImageBorderSize);
752         int creamColor = Color.argb(255, 237, 237, 227);
753         borders[p++] = new ImageFilterParametricBorder(creamColor, mImageBorderSize, 0);
754         borders[p++] = new ImageFilterParametricBorder(creamColor, mImageBorderSize,
755                 mImageBorderSize);
756
757         ImageSmallFilter previousFilter = null;
758         for (int i = 0; i < p; i++) {
759             ImageSmallBorder filter = new ImageSmallBorder(this);
760             if (i == 0) { // save the first to reset it
761                 mNullBorderFilter = filter;
762             } else {
763                 filter.setNulfilter(mNullBorderFilter);
764             }
765             borders[i].setName(getString(R.string.borders));
766             filter.setImageFilter(borders[i]);
767             filter.setController(this);
768             filter.setBorder(true);
769             filter.setImageLoader(mImageLoader);
770             filter.setShowTitle(false);
771             listBorders.addView(filter);
772             previousFilter = filter;
773         }
774     }
775
776     // //////////////////////////////////////////////////////////////////////////////
777     // Some utility functions
778     // TODO: finish the cleanup.
779
780     public void showOriginalViews(boolean value) {
781         for (ImageShow views : mImageViews) {
782             views.showOriginal(value);
783         }
784     }
785
786     public void invalidateViews() {
787         for (ImageShow views : mImageViews) {
788             views.invalidate();
789             views.updateImage();
790         }
791     }
792
793     public void hideListViews() {
794         for (View view : mListViews) {
795             view.setVisibility(View.GONE);
796         }
797     }
798
799     public void hideImageViews() {
800         mImageShow.setShowControls(false); // reset
801         for (View view : mImageViews) {
802             view.setVisibility(View.GONE);
803         }
804     }
805
806     public void unselectBottomPanelButtons() {
807         for (ImageButton button : mBottomPanelButtons) {
808             button.setSelected(false);
809         }
810     }
811
812     public void unselectPanelButtons(Vector<ImageButton> buttons) {
813         for (ImageButton button : buttons) {
814             button.setSelected(false);
815         }
816     }
817
818     // //////////////////////////////////////////////////////////////////////////////
819     // imageState panel...
820
821     public boolean isShowingHistoryPanel() {
822         return mShowingHistoryPanel;
823     }
824
825     private void toggleImageStatePanel() {
826         final View view = findViewById(R.id.mainPanel);
827         final View viewList = findViewById(R.id.imageStatePanel);
828
829         if (mShowingHistoryPanel) {
830             findViewById(R.id.historyPanel).setVisibility(View.INVISIBLE);
831             mShowingHistoryPanel = false;
832         }
833
834         int translate = translateMainPanel(viewList);
835         if (!mShowingImageStatePanel) {
836             mShowingImageStatePanel = true;
837             view.animate().setDuration(200).x(translate)
838                     .withLayer().withEndAction(new Runnable() {
839                         @Override
840                         public void run() {
841                             viewList.setAlpha(0);
842                             viewList.setVisibility(View.VISIBLE);
843                             viewList.animate().setDuration(100)
844                                     .alpha(1.0f).start();
845                         }
846                     }).start();
847         } else {
848             mShowingImageStatePanel = false;
849             viewList.setVisibility(View.INVISIBLE);
850             view.animate().setDuration(200).x(0).withLayer()
851                     .start();
852         }
853         invalidateOptionsMenu();
854     }
855
856     @Override
857     public void onConfigurationChanged(Configuration newConfig)
858     {
859         super.onConfigurationChanged(newConfig);
860         if (mShowingHistoryPanel) {
861             toggleHistoryPanel();
862         }
863     }
864
865     // //////////////////////////////////////////////////////////////////////////////
866     // history panel...
867
868     public void toggleHistoryPanel() {
869         final View view = findViewById(R.id.mainPanel);
870         final View viewList = findViewById(R.id.historyPanel);
871
872         if (mShowingImageStatePanel) {
873             findViewById(R.id.imageStatePanel).setVisibility(View.INVISIBLE);
874             mShowingImageStatePanel = false;
875         }
876
877         int translate = translateMainPanel(viewList);
878         if (!mShowingHistoryPanel) {
879             mShowingHistoryPanel = true;
880             view.animate().setDuration(200).x(translate)
881                     .withLayer().withEndAction(new Runnable() {
882                         @Override
883                         public void run() {
884                             viewList.setAlpha(0);
885                             viewList.setVisibility(View.VISIBLE);
886                             viewList.animate().setDuration(100)
887                                     .alpha(1.0f).start();
888                         }
889                     }).start();
890         } else {
891             mShowingHistoryPanel = false;
892             viewList.setVisibility(View.INVISIBLE);
893             view.animate().setDuration(200).x(0).withLayer()
894                     .start();
895         }
896         invalidateOptionsMenu();
897     }
898
899     private void resetHistory() {
900         mNullFxFilter.onClick(mNullFxFilter);
901         mNullBorderFilter.onClick(mNullBorderFilter);
902
903         HistoryAdapter adapter = mImageShow.getHistory();
904         adapter.reset();
905         ImagePreset original = new ImagePreset(adapter.getItem(0));
906         mImageShow.setImagePreset(original);
907         mPanelController.resetParameters();
908         invalidateViews();
909     }
910
911     // reset button in the history panel.
912     private OnClickListener createOnClickResetOperationsButton() {
913         return new View.OnClickListener() {
914             @Override
915             public void onClick(View v) {
916
917                 resetHistory();
918             }
919         };
920     }
921
922     @Override
923     public void onBackPressed() {
924         if (mPanelController.onBackPressed()) {
925             saveImage();
926         }
927     }
928
929     public void cannotLoadImage() {
930         CharSequence text = getString(R.string.cannot_load_image);
931         Toast toast = Toast.makeText(this, text, Toast.LENGTH_SHORT);
932         toast.show();
933         finish();
934     }
935
936     // //////////////////////////////////////////////////////////////////////////////
937
938     public float getPixelsFromDip(float value) {
939         Resources r = getResources();
940         return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, value,
941                 r.getDisplayMetrics());
942     }
943
944     public void useImagePreset(ImageSmallFilter imageSmallFilter, ImagePreset preset) {
945         if (preset == null) {
946             return;
947         }
948
949         if (mCurrentImageSmallFilter != null) {
950             mCurrentImageSmallFilter.setSelected(false);
951         }
952         mCurrentImageSmallFilter = imageSmallFilter;
953         mCurrentImageSmallFilter.setSelected(true);
954
955         ImagePreset copy = new ImagePreset(preset);
956         mImageShow.setImagePreset(copy);
957         if (preset.isFx()) {
958             // if it's an FX we rest the curve adjustment too
959             mImageCurves.resetCurve();
960         }
961         invalidateViews();
962     }
963
964     public void useImageFilter(ImageSmallFilter imageSmallFilter, ImageFilter imageFilter,
965             boolean setBorder) {
966         if (imageFilter == null) {
967             return;
968         }
969
970         if (mCurrentImageSmallFilter != null) {
971             mCurrentImageSmallFilter.setSelected(false);
972         }
973         mCurrentImageSmallFilter = imageSmallFilter;
974         mCurrentImageSmallFilter.setSelected(true);
975
976         ImagePreset oldPreset = mImageShow.getImagePreset();
977         ImagePreset copy = new ImagePreset(oldPreset);
978         // TODO: use a numerical constant instead.
979
980         copy.add(imageFilter);
981
982         mImageShow.setImagePreset(copy);
983         invalidateViews();
984     }
985
986     @Override
987     public void onItemClick(AdapterView<?> parent, View view, int position,
988             long id) {
989         mImageShow.onItemClick(position);
990         invalidateViews();
991     }
992
993     public void pickImage() {
994         Intent intent = new Intent();
995         intent.setType("image/*");
996         intent.setAction(Intent.ACTION_GET_CONTENT);
997         startActivityForResult(Intent.createChooser(intent, getString(R.string.select_image)),
998                 SELECT_PICTURE);
999     }
1000
1001     @Override
1002     public void onActivityResult(int requestCode, int resultCode, Intent data) {
1003         Log.v(LOGTAG, "onActivityResult");
1004         if (resultCode == RESULT_OK) {
1005             if (requestCode == SELECT_PICTURE) {
1006                 Uri selectedImageUri = data.getData();
1007                 startLoadBitmap(selectedImageUri);
1008             }
1009         }
1010     }
1011
1012     private boolean mSaveToExtraUri = false;
1013     private boolean mSaveAsWallpaper = false;
1014     private boolean mReturnAsExtra = false;
1015     private boolean outputted = false;
1016
1017     public void saveImage() {
1018         // boolean outputted = false;
1019         if (mCropExtras != null) {
1020             if (mCropExtras.getExtraOutput() != null) {
1021                 mSaveToExtraUri = true;
1022                 outputted = true;
1023             }
1024             if (mCropExtras.getSetAsWallpaper()) {
1025                 mSaveAsWallpaper = true;
1026                 outputted = true;
1027             }
1028             if (mCropExtras.getReturnData()) {
1029
1030                 mReturnAsExtra = true;
1031                 outputted = true;
1032             }
1033
1034             if (outputted) {
1035                 mImageShow.getImagePreset().mGeoData.setUseCropExtrasFlag(true);
1036                 showSavingProgress(null);
1037                 mImageShow.returnFilteredResult(this);
1038             }
1039         }
1040         if (!outputted) {
1041             if (mImageShow.hasModifications()) {
1042                 // Get the name of the album, to which the image will be saved
1043                 File saveDir = SaveCopyTask.getFinalSaveDirectory(this, mImageLoader.getUri());
1044                 int bucketId = GalleryUtils.getBucketId(saveDir.getPath());
1045                 String albumName = LocalAlbum.getLocalizedName(getResources(), bucketId, null);
1046                 showSavingProgress(albumName);
1047                 mImageShow.saveImage(this, null);
1048             } else {
1049                 done();
1050             }
1051         }
1052     }
1053
1054     public void onFilteredResult(Bitmap filtered) {
1055         Intent intent = new Intent();
1056         intent.putExtra(CropExtras.KEY_CROPPED_RECT, mImageShow.getImageCropBounds());
1057         if (mSaveToExtraUri) {
1058             mImageShow.saveToUri(filtered, mCropExtras.getExtraOutput(),
1059                     mCropExtras.getOutputFormat(), this);
1060         }
1061         if (mSaveAsWallpaper) {
1062             try {
1063                 WallpaperManager.getInstance(this).setBitmap(filtered);
1064             } catch (IOException e) {
1065                 Log.w(LOGTAG, "fail to set wall paper", e);
1066             }
1067         }
1068         if (mReturnAsExtra) {
1069             if (filtered != null) {
1070                 int bmapSize = filtered.getRowBytes() * filtered.getHeight();
1071                 /*
1072                  * Max size of Binder transaction buffer is 1Mb, so constrain
1073                  * Bitmap to be somewhat less than this, otherwise we get
1074                  * TransactionTooLargeExceptions.
1075                  */
1076                 if (bmapSize > MAX_BMAP_IN_INTENT) {
1077                     Log.w(LOGTAG, "Bitmap too large to be returned via intent");
1078                 } else {
1079                     intent.putExtra(CropExtras.KEY_DATA, filtered);
1080                 }
1081             }
1082         }
1083         setResult(RESULT_OK, intent);
1084         if (!mSaveToExtraUri) {
1085             done();
1086         }
1087     }
1088
1089     public void done() {
1090         if (outputted) {
1091             hideSavingProgress();
1092         }
1093         finish();
1094     }
1095
1096     static {
1097         System.loadLibrary("jni_filtershow_filters");
1098     }
1099
1100 }