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