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