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