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