FilterShowActivity.java revision 92e2341248e99c691f38820503984bc5e2f18811
1
2package com.android.gallery3d.filtershow;
3
4import android.annotation.TargetApi;
5import android.app.ActionBar;
6import android.app.Activity;
7import android.content.ContentValues;
8import android.content.Intent;
9import android.content.res.Resources;
10import android.graphics.drawable.Drawable;
11import android.net.Uri;
12import android.os.Bundle;
13import android.util.Log;
14import android.util.TypedValue;
15import android.view.Gravity;
16import android.view.Menu;
17import android.view.MenuItem;
18import android.view.MotionEvent;
19import android.view.View;
20import android.view.View.OnClickListener;
21import android.view.View.OnTouchListener;
22import android.widget.AdapterView;
23import android.widget.AdapterView.OnItemClickListener;
24import android.widget.ImageButton;
25import android.widget.LinearLayout;
26import android.widget.ListView;
27import android.widget.SeekBar;
28import android.widget.ShareActionProvider;
29import android.widget.ShareActionProvider.OnShareTargetSelectedListener;
30import android.widget.Toast;
31
32import com.android.gallery3d.R;
33import com.android.gallery3d.filtershow.cache.ImageLoader;
34import com.android.gallery3d.filtershow.filters.ImageFilter;
35import com.android.gallery3d.filtershow.filters.ImageFilterBorder;
36import com.android.gallery3d.filtershow.filters.ImageFilterRS;
37import com.android.gallery3d.filtershow.imageshow.ImageBorder;
38import com.android.gallery3d.filtershow.imageshow.ImageShow;
39import com.android.gallery3d.filtershow.imageshow.ImageSmallFilter;
40import com.android.gallery3d.filtershow.imageshow.ImageStraighten;
41import com.android.gallery3d.filtershow.imageshow.ImageZoom;
42import com.android.gallery3d.filtershow.presets.ImagePreset;
43import com.android.gallery3d.filtershow.presets.ImagePresetBW;
44import com.android.gallery3d.filtershow.presets.ImagePresetBWBlue;
45import com.android.gallery3d.filtershow.presets.ImagePresetBWGreen;
46import com.android.gallery3d.filtershow.presets.ImagePresetBWRed;
47import com.android.gallery3d.filtershow.presets.ImagePresetOld;
48import com.android.gallery3d.filtershow.presets.ImagePresetSaturated;
49import com.android.gallery3d.filtershow.presets.ImagePresetXProcessing;
50import com.android.gallery3d.filtershow.provider.SharedImageProvider;
51import com.android.gallery3d.filtershow.tools.SaveCopyTask;
52import com.android.gallery3d.filtershow.ui.ImageCurves;
53
54import java.io.File;
55import java.util.Vector;
56
57@TargetApi(16)
58public class FilterShowActivity extends Activity implements OnItemClickListener,
59        OnShareTargetSelectedListener {
60
61    private final PanelController mPanelController = new PanelController();
62    private ImageLoader mImageLoader = null;
63    private ImageShow mImageShow = null;
64    private ImageCurves mImageCurves = null;
65    private ImageBorder mImageBorders = null;
66    private ImageStraighten mImageStraighten = null;
67    private ImageZoom mImageZoom = null;
68
69    private View mListFx = null;
70    private View mListBorders = null;
71    private View mListGeometry = null;
72    private View mListColors = null;
73    private View mListFilterButtons = null;
74
75    private ImageButton mFxButton = null;
76    private ImageButton mBorderButton = null;
77    private ImageButton mGeometryButton = null;
78    private ImageButton mColorsButton = null;
79
80    private static final int SELECT_PICTURE = 1;
81    private static final String LOGTAG = "FilterShowActivity";
82    protected static final boolean ANIMATE_PANELS = true;
83
84    private boolean mShowingHistoryPanel = false;
85    private boolean mShowingImageStatePanel = false;
86
87    private final Vector<ImageShow> mImageViews = new Vector<ImageShow>();
88    private final Vector<View> mListViews = new Vector<View>();
89    private final Vector<ImageButton> mBottomPanelButtons = new Vector<ImageButton>();
90
91    private ShareActionProvider mShareActionProvider;
92    private File mSharedOutputFile = null;
93
94    private boolean mSharingImage = false;
95
96    @Override
97    public void onCreate(Bundle savedInstanceState) {
98        super.onCreate(savedInstanceState);
99
100        ImageFilterRS.setRenderScriptContext(this);
101
102        setContentView(R.layout.filtershow_activity);
103        ActionBar actionBar = getActionBar();
104        actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
105        actionBar.setCustomView(R.layout.filtershow_actionbar);
106
107        actionBar.getCustomView().setOnClickListener(new OnClickListener() {
108            @Override
109            public void onClick(View view) {
110                saveImage();
111            }
112        });
113
114        mImageLoader = new ImageLoader(getApplicationContext());
115
116        LinearLayout listFilters = (LinearLayout) findViewById(R.id.listFilters);
117        LinearLayout listBorders = (LinearLayout) findViewById(R.id.listBorders);
118
119        mImageShow = (ImageShow) findViewById(R.id.imageShow);
120        mImageCurves = (ImageCurves) findViewById(R.id.imageCurves);
121        mImageBorders = (ImageBorder) findViewById(R.id.imageBorder);
122        mImageStraighten = (ImageStraighten) findViewById(R.id.imageStraighten);
123        mImageZoom = (ImageZoom) findViewById(R.id.imageZoom);
124
125        mImageViews.add(mImageShow);
126        mImageViews.add(mImageCurves);
127        mImageViews.add(mImageBorders);
128        mImageViews.add(mImageStraighten);
129        mImageViews.add(mImageZoom);
130
131        mListFx = findViewById(R.id.fxList);
132        mListBorders = findViewById(R.id.bordersList);
133        mListGeometry = findViewById(R.id.geometryList);
134        mListFilterButtons = findViewById(R.id.filterButtonsList);
135        mListColors = findViewById(R.id.colorsFxList);
136        mListViews.add(mListFx);
137        mListViews.add(mListBorders);
138        mListViews.add(mListGeometry);
139        mListViews.add(mListFilterButtons);
140        mListViews.add(mListColors);
141
142        mFxButton = (ImageButton) findViewById(R.id.fxButton);
143        mBorderButton = (ImageButton) findViewById(R.id.borderButton);
144        mGeometryButton = (ImageButton) findViewById(R.id.geometryButton);
145        mColorsButton = (ImageButton) findViewById(R.id.colorsButton);
146
147        mImageShow.setImageLoader(mImageLoader);
148        mImageCurves.setImageLoader(mImageLoader);
149        mImageCurves.setMaster(mImageShow);
150        mImageBorders.setImageLoader(mImageLoader);
151        mImageBorders.setMaster(mImageShow);
152        mImageStraighten.setImageLoader(mImageLoader);
153        mImageStraighten.setMaster(mImageShow);
154        mImageZoom.setImageLoader(mImageLoader);
155        mImageZoom.setMaster(mImageShow);
156
157        mPanelController.addImageView(findViewById(R.id.imageShow));
158        mPanelController.addImageView(findViewById(R.id.imageCurves));
159        mPanelController.addImageView(findViewById(R.id.imageBorder));
160        mPanelController.addImageView(findViewById(R.id.imageStraighten));
161        mPanelController.addImageView(findViewById(R.id.imageZoom));
162
163        mPanelController.addPanel(mFxButton, mListFx, 0);
164        mPanelController.addPanel(mBorderButton, mListBorders, 1);
165
166        mPanelController.addPanel(mGeometryButton, mListGeometry, 2);
167        mPanelController.addComponent(mGeometryButton, findViewById(R.id.straightenButton));
168        mPanelController.addComponent(mGeometryButton, findViewById(R.id.cropButton));
169        mPanelController.addComponent(mGeometryButton, findViewById(R.id.rotateButton));
170        mPanelController.addComponent(mGeometryButton, findViewById(R.id.flipButton));
171
172        mPanelController.addPanel(mColorsButton, mListColors, 3);
173        mPanelController.addComponent(mColorsButton, findViewById(R.id.vignetteButton));
174        mPanelController.addComponent(mColorsButton, findViewById(R.id.curvesButtonRGB));
175        mPanelController.addComponent(mColorsButton, findViewById(R.id.sharpenButton));
176        mPanelController.addComponent(mColorsButton, findViewById(R.id.vibranceButton));
177        mPanelController.addComponent(mColorsButton, findViewById(R.id.contrastButton));
178        mPanelController.addComponent(mColorsButton, findViewById(R.id.saturationButton));
179        mPanelController.addComponent(mColorsButton, findViewById(R.id.tintButton));
180        mPanelController.addComponent(mColorsButton, findViewById(R.id.exposureButton));
181        mPanelController.addComponent(mColorsButton, findViewById(R.id.shadowRecoveryButton));
182
183        mPanelController.addView(findViewById(R.id.resetEffect));
184        mPanelController.addView(findViewById(R.id.applyEffect));
185
186        findViewById(R.id.compareWithOriginalImage).setOnTouchListener(createOnTouchShowOriginalButton());
187
188        findViewById(R.id.resetOperationsButton).setOnClickListener(
189                createOnClickResetOperationsButton());
190
191        ListView operationsList = (ListView) findViewById(R.id.operationsList);
192        operationsList.setAdapter(mImageShow.getHistoryAdapter());
193        operationsList.setOnItemClickListener(this);
194        ListView imageStateList = (ListView) findViewById(R.id.imageStateList);
195        imageStateList.setAdapter(mImageShow.getImageStateAdapter());
196        mImageLoader.setAdapter((HistoryAdapter) mImageShow.getHistoryAdapter());
197
198        fillListImages(listFilters);
199        fillListBorders(listBorders);
200
201        SeekBar seekBar = (SeekBar) findViewById(R.id.filterSeekBar);
202        seekBar.setMax(200);
203        mImageShow.setSeekBar(seekBar);
204        mPanelController.setRowPanel(findViewById(R.id.secondRowPanel));
205        mPanelController.setUtilityPanel(findViewById(R.id.filterButtonsList),
206                findViewById(R.id.compareWithOriginalImage),
207                findViewById(R.id.applyEffect));
208        mPanelController.setMasterImage(mImageShow);
209        mPanelController.setCurrentPanel(mFxButton);
210
211        Intent intent = getIntent();
212        String data = intent.getDataString();
213        if (data != null) {
214            Uri uri = Uri.parse(data);
215            mImageLoader.loadBitmap(uri);
216        } else {
217            pickImage();
218        }
219    }
220
221    public void completeSaveImage(Uri saveUri) {
222        if (mSharingImage && mSharedOutputFile != null) {
223            // Image saved, we unblock the content provider
224            Uri uri = Uri.withAppendedPath(SharedImageProvider.CONTENT_URI,
225                    Uri.encode(mSharedOutputFile.getAbsolutePath()));
226            ContentValues values = new ContentValues();
227            values.put(SharedImageProvider.PREPARE, false);
228            getContentResolver().insert(uri, values);
229        }
230        setResult(RESULT_OK, new Intent().setData(saveUri));
231        finish();
232    }
233
234    @Override
235    public boolean onShareTargetSelected(ShareActionProvider arg0, Intent arg1) {
236        // First, let's tell the SharedImageProvider that it will need to wait
237        // for the image
238        Uri uri = Uri.withAppendedPath(SharedImageProvider.CONTENT_URI,
239                Uri.encode(mSharedOutputFile.getAbsolutePath()));
240        ContentValues values = new ContentValues();
241        values.put(SharedImageProvider.PREPARE, true);
242        getContentResolver().insert(uri, values);
243        mSharingImage = true;
244
245        // Process and save the image in the background.
246        mImageShow.saveImage(this, mSharedOutputFile);
247        return true;
248    }
249
250    private Intent getDefaultShareIntent() {
251        Intent intent = new Intent(Intent.ACTION_SEND);
252        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
253        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
254        intent.setType(SharedImageProvider.MIME_TYPE);
255        mSharedOutputFile = SaveCopyTask.getNewFile(this, mImageLoader.getUri());
256        Uri uri = Uri.withAppendedPath(SharedImageProvider.CONTENT_URI,
257                Uri.encode(mSharedOutputFile.getAbsolutePath()));
258        intent.putExtra(Intent.EXTRA_STREAM, uri);
259        return intent;
260    }
261
262    @Override
263    public boolean onCreateOptionsMenu(Menu menu) {
264        getMenuInflater().inflate(R.menu.filtershow_activity_menu, menu);
265        MenuItem showHistory = menu.findItem(R.id.operationsButton);
266        if (mShowingHistoryPanel) {
267            showHistory.setTitle(R.string.hide_history_panel);
268        } else {
269            showHistory.setTitle(R.string.show_history_panel);
270        }
271        MenuItem showState = menu.findItem(R.id.showImageStateButton);
272        if (mShowingImageStatePanel) {
273            showState.setTitle(R.string.hide_imagestate_panel);
274        } else {
275            showState.setTitle(R.string.show_imagestate_panel);
276        }
277        mShareActionProvider = (ShareActionProvider) menu.findItem(R.id.menu_share)
278                .getActionProvider();
279        mShareActionProvider.setShareIntent(getDefaultShareIntent());
280        mShareActionProvider.setOnShareTargetSelectedListener(this);
281        return true;
282    }
283
284    @Override
285    public boolean onOptionsItemSelected(MenuItem item) {
286        switch (item.getItemId()) {
287            case R.id.undoButton: {
288                HistoryAdapter adapter = (HistoryAdapter) mImageShow
289                        .getHistoryAdapter();
290                int position = adapter.undo();
291                mImageShow.onItemClick(position);
292                mImageShow.showToast("Undo");
293                invalidateViews();
294                return true;
295            }
296            case R.id.redoButton: {
297                HistoryAdapter adapter = (HistoryAdapter) mImageShow
298                        .getHistoryAdapter();
299                int position = adapter.redo();
300                mImageShow.onItemClick(position);
301                mImageShow.showToast("Redo");
302                invalidateViews();
303                return true;
304            }
305            case R.id.resetHistoryButton: {
306                resetHistory();
307                return true;
308            }
309            case R.id.showImageStateButton: {
310                toggleImageStatePanel();
311                return true;
312            }
313            case R.id.operationsButton: {
314                toggleHistoryPanel();
315                return true;
316            }
317            case android.R.id.home: {
318                saveImage();
319                return true;
320            }
321        }
322        return false;
323    }
324
325    private void fillListImages(LinearLayout listFilters) {
326        // TODO: use listview
327        // TODO: load the filters straight from the filesystem
328        ImagePreset[] preset = new ImagePreset[9];
329        int p = 0;
330        preset[p++] = new ImagePreset();
331        preset[p++] = new ImagePresetSaturated();
332        preset[p++] = new ImagePresetOld();
333        preset[p++] = new ImagePresetXProcessing();
334        preset[p++] = new ImagePresetBW();
335        preset[p++] = new ImagePresetBWRed();
336        preset[p++] = new ImagePresetBWGreen();
337        preset[p++] = new ImagePresetBWBlue();
338
339        for (int i = 0; i < p; i++) {
340            ImageSmallFilter filter = new ImageSmallFilter(getBaseContext());
341            preset[i].setIsFx(true);
342            filter.setImagePreset(preset[i]);
343            filter.setController(this);
344            filter.setImageLoader(mImageLoader);
345            listFilters.addView(filter);
346        }
347
348        // Default preset (original)
349        mImageShow.setImagePreset(preset[0]);
350    }
351
352    private void fillListBorders(LinearLayout listBorders) {
353        // TODO: use listview
354        // TODO: load the borders straight from the filesystem
355        int p = 0;
356        ImageFilter[] borders = new ImageFilter[8];
357        borders[p++] = new ImageFilterBorder(null);
358
359        Drawable npd3 = getResources().getDrawable(R.drawable.filtershow_border_film3);
360        borders[p++] = new ImageFilterBorder(npd3);
361        Drawable npd = getResources().getDrawable(
362                R.drawable.filtershow_border_scratch3);
363        borders[p++] = new ImageFilterBorder(npd);
364        Drawable npd2 = getResources().getDrawable(R.drawable.filtershow_border_black);
365        borders[p++] = new ImageFilterBorder(npd2);
366        Drawable npd6 = getResources().getDrawable(
367                R.drawable.filtershow_border_rounded_black);
368        borders[p++] = new ImageFilterBorder(npd6);
369        Drawable npd4 = getResources().getDrawable(R.drawable.filtershow_border_white);
370        borders[p++] = new ImageFilterBorder(npd4);
371        Drawable npd5 = getResources().getDrawable(
372                R.drawable.filtershow_border_rounded_white);
373        borders[p++] = new ImageFilterBorder(npd5);
374
375        for (int i = 0; i < p; i++) {
376            ImageSmallFilter filter = new ImageSmallFilter(getBaseContext());
377            filter.setImageFilter(borders[i]);
378            filter.setController(this);
379            filter.setImageLoader(mImageLoader);
380            filter.setShowTitle(false);
381            listBorders.addView(filter);
382        }
383    }
384
385    // //////////////////////////////////////////////////////////////////////////////
386    // Some utility functions
387    // TODO: finish the cleanup.
388
389    public void showOriginalViews(boolean value) {
390        for (ImageShow views : mImageViews) {
391            views.showOriginal(value);
392        }
393    }
394
395    public void invalidateViews() {
396        for (ImageShow views : mImageViews) {
397            views.invalidate();
398        }
399    }
400
401    public void hideListViews() {
402        for (View view : mListViews) {
403            view.setVisibility(View.GONE);
404        }
405    }
406
407    public void hideImageViews() {
408        mImageShow.setShowControls(false); // reset
409        for (View view : mImageViews) {
410            view.setVisibility(View.GONE);
411        }
412    }
413
414    public void unselectBottomPanelButtons() {
415        for (ImageButton button : mBottomPanelButtons) {
416            button.setSelected(false);
417        }
418    }
419
420    public void unselectPanelButtons(Vector<ImageButton> buttons) {
421        for (ImageButton button : buttons) {
422            button.setSelected(false);
423        }
424    }
425
426    // //////////////////////////////////////////////////////////////////////////////
427    // Click handlers for the top row buttons
428
429    private OnTouchListener createOnTouchShowOriginalButton() {
430        return new View.OnTouchListener() {
431            @Override
432            public boolean onTouch(View v, MotionEvent event) {
433                boolean show = false;
434                if ((event.getActionMasked() != MotionEvent.ACTION_UP)
435                        || (event.getActionMasked() == MotionEvent.ACTION_CANCEL)) {
436                    show = true;
437                }
438                showOriginalViews(show);
439                return true;
440            }
441        };
442    }
443
444    // //////////////////////////////////////////////////////////////////////////////
445    // imageState panel...
446
447    private void toggleImageStatePanel() {
448        final View view = findViewById(R.id.mainPanel);
449        final View viewList = findViewById(R.id.imageStatePanel);
450
451        if (mShowingHistoryPanel) {
452            findViewById(R.id.historyPanel).setVisibility(View.INVISIBLE);
453            mShowingHistoryPanel = false;
454        }
455
456        if (!mShowingImageStatePanel) {
457            mShowingImageStatePanel = true;
458            view.animate().setDuration(200).x(-viewList.getWidth())
459                    .withLayer().withEndAction(new Runnable() {
460                        @Override
461                        public void run() {
462                            viewList.setAlpha(0);
463                            viewList.setVisibility(View.VISIBLE);
464                            viewList.animate().setDuration(100)
465                                    .alpha(1.0f).start();
466                        }
467                    }).start();
468        } else {
469            mShowingImageStatePanel = false;
470            viewList.setVisibility(View.INVISIBLE);
471            view.animate().setDuration(200).x(0).withLayer()
472                    .start();
473        }
474        invalidateOptionsMenu();
475    }
476
477    // //////////////////////////////////////////////////////////////////////////////
478    // history panel...
479
480    private void toggleHistoryPanel() {
481        final View view = findViewById(R.id.mainPanel);
482        final View viewList = findViewById(R.id.historyPanel);
483
484        if (mShowingImageStatePanel) {
485            findViewById(R.id.imageStatePanel).setVisibility(View.INVISIBLE);
486            mShowingImageStatePanel = false;
487        }
488
489        if (!mShowingHistoryPanel) {
490            mShowingHistoryPanel = true;
491            view.animate().setDuration(200).x(-viewList.getWidth())
492                    .withLayer().withEndAction(new Runnable() {
493                        @Override
494                        public void run() {
495                            viewList.setAlpha(0);
496                            viewList.setVisibility(View.VISIBLE);
497                            viewList.animate().setDuration(100)
498                                    .alpha(1.0f).start();
499                        }
500                    }).start();
501        } else {
502            mShowingHistoryPanel = false;
503            viewList.setVisibility(View.INVISIBLE);
504            view.animate().setDuration(200).x(0).withLayer()
505                    .start();
506        }
507        invalidateOptionsMenu();
508    }
509
510    private void resetHistory() {
511        HistoryAdapter adapter = (HistoryAdapter) mImageShow
512                .getHistoryAdapter();
513        adapter.reset();
514        ImagePreset original = new ImagePreset(adapter.getItem(0));
515        mImageShow.setImagePreset(original);
516        invalidateViews();
517    }
518
519    // reset button in the history panel.
520    private OnClickListener createOnClickResetOperationsButton() {
521        return new View.OnClickListener() {
522            @Override
523            public void onClick(View v) {
524                resetHistory();
525            }
526        };
527    }
528
529    // //////////////////////////////////////////////////////////////////////////////
530
531    public float getPixelsFromDip(float value) {
532        Resources r = getResources();
533        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, value,
534                r.getDisplayMetrics());
535    }
536
537    public void useImagePreset(ImagePreset preset) {
538        if (preset == null) {
539            return;
540        }
541        ImagePreset copy = new ImagePreset(preset);
542        mImageShow.setImagePreset(copy);
543        if (preset.isFx()) {
544            // if it's an FX we rest the curve adjustment too
545            mImageCurves.resetCurve();
546        }
547        invalidateViews();
548    }
549
550    public void useImageFilter(ImageFilter imageFilter) {
551        if (imageFilter == null) {
552            return;
553        }
554        ImagePreset oldPreset = mImageShow.getImagePreset();
555        ImagePreset copy = new ImagePreset(oldPreset);
556        // TODO: use a numerical constant instead.
557        if (imageFilter.getName().equalsIgnoreCase("Border")) {
558            copy.remove("Border");
559            copy.setHistoryName("Border");
560        }
561        copy.add(imageFilter);
562        mImageShow.setImagePreset(copy);
563        invalidateViews();
564    }
565
566    @Override
567    public void onItemClick(AdapterView<?> parent, View view, int position,
568            long id) {
569        mImageShow.onItemClick(position);
570        invalidateViews();
571    }
572
573    public void pickImage() {
574        Intent intent = new Intent();
575        intent.setType("image/*");
576        intent.setAction(Intent.ACTION_GET_CONTENT);
577        startActivityForResult(Intent.createChooser(intent, getString(R.string.select_image)),
578                SELECT_PICTURE);
579    }
580
581    @Override
582    public void onActivityResult(int requestCode, int resultCode, Intent data) {
583        Log.v(LOGTAG, "onActivityResult");
584        if (resultCode == RESULT_OK) {
585            if (requestCode == SELECT_PICTURE) {
586                Uri selectedImageUri = data.getData();
587                mImageLoader.loadBitmap(selectedImageUri);
588            }
589        }
590    }
591
592    public void saveImage() {
593        Toast toast = Toast.makeText(getBaseContext(), getString(R.string.saving_image),
594                Toast.LENGTH_SHORT);
595        toast.setGravity(Gravity.CENTER, 0, 0);
596        toast.show();
597
598        mImageShow.saveImage(this, null);
599    }
600
601    static {
602        System.loadLibrary("jni_filtershow_filters");
603    }
604
605}
606