2 * Copyright (C) 2012 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.gallery3d.filtershow;
19 import android.app.ActionBar;
20 import android.app.AlertDialog;
21 import android.app.ProgressDialog;
22 import android.content.ContentValues;
23 import android.content.DialogInterface;
24 import android.content.Intent;
25 import android.content.pm.ActivityInfo;
26 import android.content.res.Configuration;
27 import android.content.res.Resources;
28 import android.graphics.Bitmap;
29 import android.graphics.Point;
30 import android.graphics.drawable.Drawable;
31 import android.net.Uri;
32 import android.os.AsyncTask;
33 import android.os.Bundle;
34 import android.os.Handler;
35 import android.support.v4.app.Fragment;
36 import android.support.v4.app.FragmentActivity;
37 import android.support.v4.app.FragmentTransaction;
38 import android.util.DisplayMetrics;
39 import android.util.TypedValue;
40 import android.util.Log;
41 import android.view.Display;
42 import android.view.Menu;
43 import android.view.MenuItem;
44 import android.view.View;
45 import android.view.View.OnClickListener;
46 import android.view.ViewPropertyAnimator;
47 import android.view.WindowManager;
48 import android.widget.AdapterView;
49 import android.widget.AdapterView.OnItemClickListener;
50 import android.widget.FrameLayout;
51 import android.widget.ShareActionProvider;
52 import android.widget.ShareActionProvider.OnShareTargetSelectedListener;
53 import android.widget.Toast;
55 import com.android.gallery3d.R;
56 import com.android.gallery3d.data.LocalAlbum;
57 import com.android.gallery3d.filtershow.cache.CachingPipeline;
58 import com.android.gallery3d.filtershow.cache.FilteringPipeline;
59 import com.android.gallery3d.filtershow.cache.ImageLoader;
60 import com.android.gallery3d.filtershow.category.Action;
61 import com.android.gallery3d.filtershow.category.CategoryAdapter;
62 import com.android.gallery3d.filtershow.category.CategoryView;
63 import com.android.gallery3d.filtershow.category.MainPanel;
64 import com.android.gallery3d.filtershow.editors.BasicEditor;
65 import com.android.gallery3d.filtershow.editors.Editor;
66 import com.android.gallery3d.filtershow.editors.EditorCrop;
67 import com.android.gallery3d.filtershow.editors.EditorDraw;
68 import com.android.gallery3d.filtershow.editors.EditorFlip;
69 import com.android.gallery3d.filtershow.editors.EditorInfo;
70 import com.android.gallery3d.filtershow.editors.EditorManager;
71 import com.android.gallery3d.filtershow.editors.EditorPanel;
72 import com.android.gallery3d.filtershow.editors.EditorRedEye;
73 import com.android.gallery3d.filtershow.editors.EditorRotate;
74 import com.android.gallery3d.filtershow.editors.EditorStraighten;
75 import com.android.gallery3d.filtershow.editors.EditorTinyPlanet;
76 import com.android.gallery3d.filtershow.editors.ImageOnlyEditor;
77 import com.android.gallery3d.filtershow.filters.FilterFxRepresentation;
78 import com.android.gallery3d.filtershow.filters.FilterImageBorderRepresentation;
79 import com.android.gallery3d.filtershow.filters.FilterRepresentation;
80 import com.android.gallery3d.filtershow.filters.FiltersManager;
81 import com.android.gallery3d.filtershow.filters.ImageFilter;
82 import com.android.gallery3d.filtershow.imageshow.GeometryMetadata;
83 import com.android.gallery3d.filtershow.imageshow.ImageCrop;
84 import com.android.gallery3d.filtershow.imageshow.ImageShow;
85 import com.android.gallery3d.filtershow.imageshow.MasterImage;
86 import com.android.gallery3d.filtershow.presets.ImagePreset;
87 import com.android.gallery3d.filtershow.provider.SharedImageProvider;
88 import com.android.gallery3d.filtershow.state.StateAdapter;
89 import com.android.gallery3d.filtershow.tools.SaveCopyTask;
90 import com.android.gallery3d.filtershow.tools.XmpPresets;
91 import com.android.gallery3d.filtershow.tools.XmpPresets.XMresults;
92 import com.android.gallery3d.filtershow.ui.FramedTextButton;
93 import com.android.gallery3d.filtershow.ui.Spline;
94 import com.android.gallery3d.util.GalleryUtils;
95 import com.android.gallery3d.util.UsageStatistics;
96 import com.android.photos.data.GalleryBitmapPool;
99 import java.lang.ref.WeakReference;
100 import java.util.Vector;
102 public class FilterShowActivity extends FragmentActivity implements OnItemClickListener,
103 OnShareTargetSelectedListener {
105 private String mAction = "";
106 MasterImage mMasterImage = null;
108 private static final long LIMIT_SUPPORTS_HIGHRES = 134217728; // 128Mb
110 public static final String TINY_PLANET_ACTION = "com.android.camera.action.TINY_PLANET";
111 public static final String LAUNCH_FULLSCREEN = "launch-fullscreen";
112 private ImageLoader mImageLoader = null;
113 private ImageShow mImageShow = null;
115 private View mSaveButton = null;
117 private EditorPlaceHolder mEditorPlaceHolder = new EditorPlaceHolder(this);
119 private static final int SELECT_PICTURE = 1;
120 private static final String LOGTAG = "FilterShowActivity";
121 protected static final boolean ANIMATE_PANELS = true;
123 private boolean mShowingTinyPlanet = false;
124 private boolean mShowingImageStatePanel = false;
126 private final Vector<ImageShow> mImageViews = new Vector<ImageShow>();
128 private ShareActionProvider mShareActionProvider;
129 private File mSharedOutputFile = null;
131 private boolean mSharingImage = false;
133 private WeakReference<ProgressDialog> mSavingProgressDialog;
135 private LoadBitmapTask mLoadBitmapTask;
136 private boolean mLoading = true;
138 private Uri mOriginalImageUri = null;
139 private ImagePreset mOriginalPreset = null;
141 private CategoryAdapter mCategoryLooksAdapter = null;
142 private CategoryAdapter mCategoryBordersAdapter = null;
143 private CategoryAdapter mCategoryGeometryAdapter = null;
144 private CategoryAdapter mCategoryFiltersAdapter = null;
145 private int mCurrentPanel = MainPanel.LOOKS;
148 public void onCreate(Bundle savedInstanceState) {
149 super.onCreate(savedInstanceState);
151 boolean onlyUsePortrait = getResources().getBoolean(R.bool.only_use_portrait);
152 if (onlyUsePortrait) {
153 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
155 MasterImage.setMaster(mMasterImage);
157 clearGalleryBitmapPool();
159 CachingPipeline.createRenderscriptContext(this);
171 UsageStatistics.onContentViewChanged(UsageStatistics.COMPONENT_EDITOR, "Main");
172 UsageStatistics.onEvent(UsageStatistics.COMPONENT_EDITOR,
173 UsageStatistics.CATEGORY_LIFECYCLE, UsageStatistics.LIFECYCLE_START);
176 public boolean isShowingImageStatePanel() {
177 return mShowingImageStatePanel;
180 public void loadMainPanel() {
181 if (findViewById(R.id.main_panel_container) == null) {
184 MainPanel panel = new MainPanel();
185 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
186 transaction.replace(R.id.main_panel_container, panel, MainPanel.FRAGMENT_TAG);
187 transaction.commit();
190 public void loadEditorPanel(FilterRepresentation representation,
191 final Editor currentEditor) {
192 if (representation.getEditorId() == ImageOnlyEditor.ID) {
193 currentEditor.reflectCurrentFilter();
196 final int currentId = currentEditor.getID();
197 Runnable showEditor = new Runnable() {
200 EditorPanel panel = new EditorPanel();
201 panel.setEditor(currentId);
202 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
203 transaction.remove(getSupportFragmentManager().findFragmentByTag(MainPanel.FRAGMENT_TAG));
204 transaction.replace(R.id.main_panel_container, panel, MainPanel.FRAGMENT_TAG);
205 transaction.commit();
208 Fragment main = getSupportFragmentManager().findFragmentByTag(MainPanel.FRAGMENT_TAG);
209 boolean doAnimation = false;
210 if (mShowingImageStatePanel
211 && getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
214 if (doAnimation && main != null && main instanceof MainPanel) {
215 MainPanel mainPanel = (MainPanel) main;
216 View container = mainPanel.getView().findViewById(R.id.category_panel_container);
217 View bottom = mainPanel.getView().findViewById(R.id.bottom_panel);
218 int panelHeight = container.getHeight() + bottom.getHeight();
219 ViewPropertyAnimator anim = mainPanel.getView().animate();
220 anim.translationY(panelHeight).start();
221 final Handler handler = new Handler();
222 handler.postDelayed(showEditor, anim.getDuration());
228 private void loadXML() {
229 setContentView(R.layout.filtershow_activity);
231 ActionBar actionBar = getActionBar();
232 actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
233 actionBar.setCustomView(R.layout.filtershow_actionbar);
235 mSaveButton = actionBar.getCustomView();
236 mSaveButton.setOnClickListener(new OnClickListener() {
238 public void onClick(View view) {
243 mImageShow = (ImageShow) findViewById(R.id.imageShow);
244 mImageViews.add(mImageShow);
248 mEditorPlaceHolder.hide();
250 mImageShow.setImageLoader(mImageLoader);
260 public void setupStatePanel() {
261 mImageLoader.setAdapter(mMasterImage.getHistory());
264 private void fillFilters() {
265 Vector<FilterRepresentation> filtersRepresentations = new Vector<FilterRepresentation>();
266 FiltersManager filtersManager = FiltersManager.getManager();
267 filtersManager.addEffects(filtersRepresentations);
269 mCategoryFiltersAdapter = new CategoryAdapter(this);
270 for (FilterRepresentation representation : filtersRepresentations) {
271 if (representation.getTextId() != 0) {
272 representation.setName(getString(representation.getTextId()));
274 mCategoryFiltersAdapter.add(new Action(this, representation));
278 private void fillGeometry() {
279 Vector<FilterRepresentation> filtersRepresentations = new Vector<FilterRepresentation>();
280 FiltersManager filtersManager = FiltersManager.getManager();
282 GeometryMetadata geo = new GeometryMetadata();
283 int[] editorsId = geo.getEditorIds();
284 for (int i = 0; i < editorsId.length; i++) {
285 int editorId = editorsId[i];
286 GeometryMetadata geometry = new GeometryMetadata(geo);
287 geometry.setEditorId(editorId);
288 EditorInfo editorInfo = (EditorInfo) mEditorPlaceHolder.getEditor(editorId);
289 geometry.setTextId(editorInfo.getTextId());
290 geometry.setOverlayId(editorInfo.getOverlayId());
291 geometry.setOverlayOnly(editorInfo.getOverlayOnly());
292 if (geometry.getTextId() != 0) {
293 geometry.setName(getString(geometry.getTextId()));
295 filtersRepresentations.add(geometry);
298 filtersManager.addTools(filtersRepresentations);
300 mCategoryGeometryAdapter = new CategoryAdapter(this);
301 for (FilterRepresentation representation : filtersRepresentations) {
302 mCategoryGeometryAdapter.add(new Action(this, representation));
306 private void processIntent() {
307 Intent intent = getIntent();
308 if (intent.getBooleanExtra(LAUNCH_FULLSCREEN, false)) {
309 getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
312 mAction = intent.getAction();
313 Uri srcUri = intent.getData();
314 if (mOriginalImageUri != null) {
315 srcUri = mOriginalImageUri;
317 if (srcUri != null) {
318 startLoadBitmap(srcUri);
324 private void setupEditors() {
325 mEditorPlaceHolder.setContainer((FrameLayout) findViewById(R.id.editorContainer));
326 EditorManager.addEditors(mEditorPlaceHolder);
327 mEditorPlaceHolder.setOldViews(mImageViews);
328 mEditorPlaceHolder.setImageLoader(mImageLoader);
331 private void fillEditors() {
332 mEditorPlaceHolder.addEditor(new EditorDraw());
333 mEditorPlaceHolder.addEditor(new BasicEditor());
334 mEditorPlaceHolder.addEditor(new ImageOnlyEditor());
335 mEditorPlaceHolder.addEditor(new EditorTinyPlanet());
336 mEditorPlaceHolder.addEditor(new EditorRedEye());
337 mEditorPlaceHolder.addEditor(new EditorCrop());
338 mEditorPlaceHolder.addEditor(new EditorFlip());
339 mEditorPlaceHolder.addEditor(new EditorRotate());
340 mEditorPlaceHolder.addEditor(new EditorStraighten());
343 private void setDefaultValues() {
344 ImageFilter.setActivityForMemoryToasts(this);
346 Resources res = getResources();
347 FiltersManager.setResources(res);
349 CategoryView.setMargin((int) getPixelsFromDip(8));
350 CategoryView.setTextSize((int) getPixelsFromDip(16));
352 // TODO: get those values from XML.
353 FramedTextButton.setTextSize((int) getPixelsFromDip(14));
354 FramedTextButton.setTrianglePadding((int) getPixelsFromDip(4));
355 FramedTextButton.setTriangleSize((int) getPixelsFromDip(10));
357 Drawable curveHandle = res.getDrawable(R.drawable.camera_crop);
358 int curveHandleSize = (int) res.getDimension(R.dimen.crop_indicator_size);
359 Spline.setCurveHandle(curveHandle, curveHandleSize);
360 Spline.setCurveWidth((int) getPixelsFromDip(3));
362 ImageCrop.setAspectTextSize((int) getPixelsFromDip(18));
363 ImageCrop.setTouchTolerance((int) getPixelsFromDip(25));
364 ImageCrop.setMinCropSize((int) getPixelsFromDip(55));
367 private void startLoadBitmap(Uri uri) {
369 final View loading = findViewById(R.id.loading);
370 final View imageShow = findViewById(R.id.imageShow);
371 imageShow.setVisibility(View.INVISIBLE);
372 loading.setVisibility(View.VISIBLE);
373 mShowingTinyPlanet = false;
374 mLoadBitmapTask = new LoadBitmapTask();
375 mLoadBitmapTask.execute(uri);
378 private void fillBorders() {
379 Vector<FilterRepresentation> borders = new Vector<FilterRepresentation>();
381 // The "no border" implementation
382 borders.add(new FilterImageBorderRepresentation(0));
384 // Google-build borders
385 FiltersManager.getManager().addBorders(this, borders);
387 for (int i = 0; i < borders.size(); i++) {
388 FilterRepresentation filter = borders.elementAt(i);
389 filter.setName(getString(R.string.borders));
391 filter.setName(getString(R.string.none));
395 mCategoryBordersAdapter = new CategoryAdapter(this);
396 for (FilterRepresentation representation : borders) {
397 if (representation.getTextId() != 0) {
398 representation.setName(getString(representation.getTextId()));
400 mCategoryBordersAdapter.add(new Action(this, representation, Action.FULL_VIEW));
404 public CategoryAdapter getCategoryLooksAdapter() {
405 return mCategoryLooksAdapter;
408 public CategoryAdapter getCategoryBordersAdapter() {
409 return mCategoryBordersAdapter;
412 public CategoryAdapter getCategoryGeometryAdapter() {
413 return mCategoryGeometryAdapter;
416 public CategoryAdapter getCategoryFiltersAdapter() {
417 return mCategoryFiltersAdapter;
420 public void removeFilterRepresentation(FilterRepresentation filterRepresentation) {
421 if (filterRepresentation == null) {
424 ImagePreset oldPreset = MasterImage.getImage().getPreset();
425 ImagePreset copy = new ImagePreset(oldPreset);
426 copy.removeFilter(filterRepresentation);
427 MasterImage.getImage().setPreset(copy, true);
428 if (MasterImage.getImage().getCurrentFilterRepresentation() == filterRepresentation) {
429 FilterRepresentation lastRepresentation = copy.getLastRepresentation();
430 MasterImage.getImage().setCurrentFilterRepresentation(lastRepresentation);
434 public void useFilterRepresentation(FilterRepresentation filterRepresentation) {
435 if (filterRepresentation == null) {
438 if (MasterImage.getImage().getCurrentFilterRepresentation() == filterRepresentation) {
441 ImagePreset oldPreset = MasterImage.getImage().getPreset();
442 ImagePreset copy = new ImagePreset(oldPreset);
443 FilterRepresentation representation = copy.getRepresentation(filterRepresentation);
444 if (representation == null) {
445 copy.addFilter(filterRepresentation);
447 if (filterRepresentation.allowsMultipleInstances()) {
448 representation.updateTempParametersFrom(filterRepresentation);
449 copy.setHistoryName(filterRepresentation.getName());
450 representation.synchronizeRepresentation();
452 filterRepresentation = representation;
454 MasterImage.getImage().setPreset(copy, true);
455 MasterImage.getImage().setCurrentFilterRepresentation(filterRepresentation);
458 public void showRepresentation(FilterRepresentation representation) {
459 if (representation == null) {
462 useFilterRepresentation(representation);
464 // show representation
465 Editor mCurrentEditor = mEditorPlaceHolder.showEditor(representation.getEditorId());
466 loadEditorPanel(representation, mCurrentEditor);
469 public Editor getEditor(int editorID) {
470 return mEditorPlaceHolder.getEditor(editorID);
473 public void setCurrentPanel(int currentPanel) {
474 mCurrentPanel = currentPanel;
477 public int getCurrentPanel() {
478 return mCurrentPanel;
481 private class LoadBitmapTask extends AsyncTask<Uri, Boolean, Boolean> {
484 public LoadBitmapTask() {
485 mBitmapSize = getScreenImageSize();
489 protected Boolean doInBackground(Uri... params) {
490 if (!mImageLoader.loadBitmap(params[0], mBitmapSize)) {
493 publishProgress(mImageLoader.queryLightCycle360());
498 protected void onProgressUpdate(Boolean... values) {
499 super.onProgressUpdate(values);
504 mShowingTinyPlanet = true;
509 protected void onPostExecute(Boolean result) {
510 MasterImage.setMaster(mMasterImage);
519 if (null == CachingPipeline.getRenderScriptContext()){
520 Log.v(LOGTAG,"RenderScript context destroyed during load");
523 final View loading = findViewById(R.id.loading);
524 loading.setVisibility(View.GONE);
525 final View imageShow = findViewById(R.id.imageShow);
526 imageShow.setVisibility(View.VISIBLE);
528 Bitmap largeBitmap = mImageLoader.getOriginalBitmapLarge();
529 FilteringPipeline pipeline = FilteringPipeline.getPipeline();
530 pipeline.setOriginal(largeBitmap);
531 float previewScale = (float) largeBitmap.getWidth() / (float) mImageLoader.getOriginalBounds().width();
532 pipeline.setPreviewScaleFactor(previewScale);
533 Bitmap highresBitmap = mImageLoader.getOriginalBitmapHighres();
534 if (highresBitmap != null) {
535 float highResPreviewScale = (float) highresBitmap.getWidth() / (float) mImageLoader.getOriginalBounds().width();
536 pipeline.setHighResPreviewScaleFactor(highResPreviewScale);
538 if (!mShowingTinyPlanet) {
539 mCategoryFiltersAdapter.removeTinyPlanet();
541 pipeline.turnOnPipeline(true);
542 MasterImage.getImage().setOriginalGeometry(largeBitmap);
543 mCategoryLooksAdapter.imageLoaded();
544 mCategoryBordersAdapter.imageLoaded();
545 mCategoryGeometryAdapter.imageLoaded();
546 mCategoryFiltersAdapter.imageLoaded();
547 mLoadBitmapTask = null;
549 if (mOriginalPreset != null) {
550 MasterImage.getImage().setPreset(mOriginalPreset, true);
551 mOriginalPreset = null;
554 if (mAction == TINY_PLANET_ACTION) {
555 showRepresentation(mCategoryFiltersAdapter.getTinyPlanet());
558 super.onPostExecute(result);
563 private void clearGalleryBitmapPool() {
564 (new AsyncTask<Void, Void, Void>() {
566 protected Void doInBackground(Void... params) {
567 // Free memory held in Gallery's Bitmap pool. May be O(n) for n bitmaps.
568 GalleryBitmapPool.getInstance().clear();
575 protected void onDestroy() {
576 if (mLoadBitmapTask != null) {
577 mLoadBitmapTask.cancel(false);
579 // TODO: refactor, don't use so many singletons.
580 FilteringPipeline.getPipeline().turnOnPipeline(false);
582 FilteringPipeline.reset();
583 ImageFilter.resetStatics();
584 FiltersManager.getPreviewManager().freeRSFilterScripts();
585 FiltersManager.getManager().freeRSFilterScripts();
586 FiltersManager.getHighresManager().freeRSFilterScripts();
587 FiltersManager.reset();
588 CachingPipeline.destroyRenderScriptContext();
592 private int getScreenImageSize() {
593 DisplayMetrics metrics = new DisplayMetrics();
594 Display display = getWindowManager().getDefaultDisplay();
595 Point size = new Point();
596 display.getSize(size);
597 display.getMetrics(metrics);
598 int msize = Math.min(size.x, size.y);
599 return (133 * msize) / metrics.densityDpi;
602 private void showSavingProgress(String albumName) {
603 ProgressDialog progress;
604 if (mSavingProgressDialog != null) {
605 progress = mSavingProgressDialog.get();
606 if (progress != null) {
611 // TODO: Allow cancellation of the saving process
613 if (albumName == null) {
614 progressText = getString(R.string.saving_image);
616 progressText = getString(R.string.filtershow_saving_image, albumName);
618 progress = ProgressDialog.show(this, "", progressText, true, false);
619 mSavingProgressDialog = new WeakReference<ProgressDialog>(progress);
622 private void hideSavingProgress() {
623 if (mSavingProgressDialog != null) {
624 ProgressDialog progress = mSavingProgressDialog.get();
625 if (progress != null)
630 public void completeSaveImage(Uri saveUri) {
631 if (mSharingImage && mSharedOutputFile != null) {
632 // Image saved, we unblock the content provider
633 Uri uri = Uri.withAppendedPath(SharedImageProvider.CONTENT_URI,
634 Uri.encode(mSharedOutputFile.getAbsolutePath()));
635 ContentValues values = new ContentValues();
636 values.put(SharedImageProvider.PREPARE, false);
637 getContentResolver().insert(uri, values);
639 setResult(RESULT_OK, new Intent().setData(saveUri));
640 hideSavingProgress();
645 public boolean onShareTargetSelected(ShareActionProvider arg0, Intent arg1) {
646 // First, let's tell the SharedImageProvider that it will need to wait
648 Uri uri = Uri.withAppendedPath(SharedImageProvider.CONTENT_URI,
649 Uri.encode(mSharedOutputFile.getAbsolutePath()));
650 ContentValues values = new ContentValues();
651 values.put(SharedImageProvider.PREPARE, true);
652 getContentResolver().insert(uri, values);
653 mSharingImage = true;
655 // Process and save the image in the background.
656 showSavingProgress(null);
657 mImageShow.saveImage(this, mSharedOutputFile);
661 private Intent getDefaultShareIntent() {
662 Intent intent = new Intent(Intent.ACTION_SEND);
663 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
664 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
665 intent.setType(SharedImageProvider.MIME_TYPE);
666 mSharedOutputFile = SaveCopyTask.getNewFile(this, mImageLoader.getUri());
667 Uri uri = Uri.withAppendedPath(SharedImageProvider.CONTENT_URI,
668 Uri.encode(mSharedOutputFile.getAbsolutePath()));
669 intent.putExtra(Intent.EXTRA_STREAM, uri);
674 public boolean onCreateOptionsMenu(Menu menu) {
675 getMenuInflater().inflate(R.menu.filtershow_activity_menu, menu);
676 MenuItem showState = menu.findItem(R.id.showImageStateButton);
677 if (mShowingImageStatePanel) {
678 showState.setTitle(R.string.hide_imagestate_panel);
680 showState.setTitle(R.string.show_imagestate_panel);
682 mShareActionProvider = (ShareActionProvider) menu.findItem(R.id.menu_share)
683 .getActionProvider();
684 mShareActionProvider.setShareIntent(getDefaultShareIntent());
685 mShareActionProvider.setOnShareTargetSelectedListener(this);
687 MenuItem undoItem = menu.findItem(R.id.undoButton);
688 MenuItem redoItem = menu.findItem(R.id.redoButton);
689 MenuItem resetItem = menu.findItem(R.id.resetHistoryButton);
690 mMasterImage.getHistory().setMenuItems(undoItem, redoItem, resetItem);
695 public void onPause() {
698 if (mShareActionProvider != null) {
699 mShareActionProvider.setOnShareTargetSelectedListener(null);
704 public void onResume() {
707 if (mShareActionProvider != null) {
708 mShareActionProvider.setOnShareTargetSelectedListener(this);
712 private void rsResume() {
713 ImageFilter.setActivityForMemoryToasts(this);
714 MasterImage.setMaster(mMasterImage);
715 if (CachingPipeline.getRenderScriptContext() == null) {
716 CachingPipeline.createRenderscriptContext(this);
718 FiltersManager.setResources(getResources());
720 Bitmap largeBitmap = mImageLoader.getOriginalBitmapLarge();
721 FilteringPipeline pipeline = FilteringPipeline.getPipeline();
722 pipeline.setOriginal(largeBitmap);
723 float previewScale = (float) largeBitmap.getWidth() /
724 (float) mImageLoader.getOriginalBounds().width();
725 pipeline.setPreviewScaleFactor(previewScale);
726 Bitmap highresBitmap = mImageLoader.getOriginalBitmapHighres();
727 if (highresBitmap != null) {
728 float highResPreviewScale = (float) highresBitmap.getWidth() /
729 (float) mImageLoader.getOriginalBounds().width();
730 pipeline.setHighResPreviewScaleFactor(highResPreviewScale);
732 pipeline.turnOnPipeline(true);
733 MasterImage.getImage().setOriginalGeometry(largeBitmap);
737 private void rsPause() {
738 FilteringPipeline.getPipeline().turnOnPipeline(false);
739 FilteringPipeline.reset();
740 ImageFilter.resetStatics();
741 FiltersManager.getPreviewManager().freeRSFilterScripts();
742 FiltersManager.getManager().freeRSFilterScripts();
743 FiltersManager.getHighresManager().freeRSFilterScripts();
744 FiltersManager.reset();
745 CachingPipeline.destroyRenderScriptContext();
749 public boolean onOptionsItemSelected(MenuItem item) {
750 switch (item.getItemId()) {
751 case R.id.undoButton: {
752 HistoryAdapter adapter = mMasterImage.getHistory();
753 int position = adapter.undo();
754 mMasterImage.onHistoryItemClick(position);
757 UsageStatistics.onEvent(UsageStatistics.COMPONENT_EDITOR,
758 UsageStatistics.CATEGORY_BUTTON_PRESS, "Undo");
761 case R.id.redoButton: {
762 HistoryAdapter adapter = mMasterImage.getHistory();
763 int position = adapter.redo();
764 mMasterImage.onHistoryItemClick(position);
766 UsageStatistics.onEvent(UsageStatistics.COMPONENT_EDITOR,
767 UsageStatistics.CATEGORY_BUTTON_PRESS, "Redo");
770 case R.id.resetHistoryButton: {
772 UsageStatistics.onEvent(UsageStatistics.COMPONENT_EDITOR,
773 UsageStatistics.CATEGORY_BUTTON_PRESS, "ResetHistory");
776 case R.id.showImageStateButton: {
777 toggleImageStatePanel();
778 UsageStatistics.onEvent(UsageStatistics.COMPONENT_EDITOR,
779 UsageStatistics.CATEGORY_BUTTON_PRESS,
780 mShowingImageStatePanel ? "ShowPanel" : "HidePanel");
783 case android.R.id.home: {
791 public void enableSave(boolean enable) {
792 if (mSaveButton != null)
793 mSaveButton.setEnabled(enable);
796 private void fillFx() {
797 FilterFxRepresentation nullFx =
798 new FilterFxRepresentation(getString(R.string.none), 0, R.string.none);
799 Vector<FilterRepresentation> filtersRepresentations = new Vector<FilterRepresentation>();
800 FiltersManager.getManager().addLooks(this, filtersRepresentations);
802 mCategoryLooksAdapter = new CategoryAdapter(this);
803 int verticalItemHeight = (int) getResources().getDimension(R.dimen.action_item_height);
804 mCategoryLooksAdapter.setItemHeight(verticalItemHeight);
805 mCategoryLooksAdapter.add(new Action(this, nullFx, Action.FULL_VIEW));
806 for (FilterRepresentation representation : filtersRepresentations) {
807 mCategoryLooksAdapter.add(new Action(this, representation, Action.FULL_VIEW));
811 public void setDefaultPreset() {
812 // Default preset (original)
813 ImagePreset preset = new ImagePreset(getString(R.string.history_original)); // empty
814 preset.setImageLoader(mImageLoader);
816 mMasterImage.setPreset(preset, true);
819 // //////////////////////////////////////////////////////////////////////////////
820 // Some utility functions
821 // TODO: finish the cleanup.
823 public void invalidateViews() {
824 for (ImageShow views : mImageViews) {
830 public void hideImageViews() {
831 for (View view : mImageViews) {
832 view.setVisibility(View.GONE);
834 mEditorPlaceHolder.hide();
837 // //////////////////////////////////////////////////////////////////////////////
838 // imageState panel...
840 public void toggleImageStatePanel() {
841 invalidateOptionsMenu();
842 mShowingImageStatePanel = !mShowingImageStatePanel;
843 Fragment panel = getSupportFragmentManager().findFragmentByTag(MainPanel.FRAGMENT_TAG);
845 if (panel instanceof EditorPanel) {
846 EditorPanel editorPanel = (EditorPanel) panel;
847 editorPanel.showImageStatePanel(mShowingImageStatePanel);
848 } else if (panel instanceof MainPanel) {
849 MainPanel mainPanel = (MainPanel) panel;
850 mainPanel.showImageStatePanel(mShowingImageStatePanel);
856 public void onConfigurationChanged(Configuration newConfig)
858 super.onConfigurationChanged(newConfig);
863 // mLoadBitmapTask==null implies you have looked at the intent
864 if (!mShowingTinyPlanet && (mLoadBitmapTask == null)) {
865 mCategoryFiltersAdapter.removeTinyPlanet();
867 final View loading = findViewById(R.id.loading);
868 loading.setVisibility(View.GONE);
871 public void setupMasterImage() {
872 mImageLoader = new ImageLoader(this, getApplicationContext());
874 HistoryAdapter mHistoryAdapter = new HistoryAdapter(
875 this, R.layout.filtershow_history_operation_row,
878 StateAdapter mImageStateAdapter = new StateAdapter(this, 0);
880 mMasterImage = MasterImage.getImage();
881 mMasterImage.setHistoryAdapter(mHistoryAdapter);
882 mMasterImage.setStateAdapter(mImageStateAdapter);
883 mMasterImage.setActivity(this);
884 mMasterImage.setImageLoader(mImageLoader);
886 if (Runtime.getRuntime().maxMemory() > LIMIT_SUPPORTS_HIGHRES) {
887 mMasterImage.setSupportsHighRes(true);
889 mMasterImage.setSupportsHighRes(false);
893 void resetHistory() {
894 HistoryAdapter adapter = mMasterImage.getHistory();
896 ImagePreset original = new ImagePreset(adapter.getItem(0));
897 mMasterImage.setPreset(original, true);
902 public void showDefaultImageView() {
903 mEditorPlaceHolder.hide();
904 mImageShow.setVisibility(View.VISIBLE);
905 MasterImage.getImage().setCurrentFilter(null);
906 MasterImage.getImage().setCurrentFilterRepresentation(null);
909 public void backToMain() {
910 Fragment currentPanel = getSupportFragmentManager().findFragmentByTag(MainPanel.FRAGMENT_TAG);
911 if (currentPanel instanceof MainPanel) {
915 showDefaultImageView();
919 public void onBackPressed() {
920 Fragment currentPanel = getSupportFragmentManager().findFragmentByTag(MainPanel.FRAGMENT_TAG);
921 if (currentPanel instanceof MainPanel) {
922 if (!mImageShow.hasModifications()) {
925 AlertDialog.Builder builder = new AlertDialog.Builder(this);
926 builder.setMessage(R.string.unsaved).setTitle(R.string.save_before_exit);
927 builder.setPositiveButton(R.string.save_and_exit, new DialogInterface.OnClickListener() {
928 public void onClick(DialogInterface dialog, int id) {
932 builder.setNegativeButton(R.string.exit, new DialogInterface.OnClickListener() {
933 public void onClick(DialogInterface dialog, int id) {
944 public void cannotLoadImage() {
945 Toast.makeText(this, R.string.cannot_load_image, Toast.LENGTH_SHORT).show();
949 // //////////////////////////////////////////////////////////////////////////////
951 public float getPixelsFromDip(float value) {
952 Resources r = getResources();
953 return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, value,
954 r.getDisplayMetrics());
958 public void onItemClick(AdapterView<?> parent, View view, int position,
960 mMasterImage.onHistoryItemClick(position);
964 public void pickImage() {
965 Intent intent = new Intent();
966 intent.setType("image/*");
967 intent.setAction(Intent.ACTION_GET_CONTENT);
968 startActivityForResult(Intent.createChooser(intent, getString(R.string.select_image)),
973 public void onActivityResult(int requestCode, int resultCode, Intent data) {
974 if (resultCode == RESULT_OK) {
975 if (requestCode == SELECT_PICTURE) {
976 Uri selectedImageUri = data.getData();
977 startLoadBitmap(selectedImageUri);
983 public void saveImage() {
984 if (mImageShow.hasModifications()) {
985 // Get the name of the album, to which the image will be saved
986 File saveDir = SaveCopyTask.getFinalSaveDirectory(this, mImageLoader.getUri());
987 int bucketId = GalleryUtils.getBucketId(saveDir.getPath());
988 String albumName = LocalAlbum.getLocalizedName(getResources(), bucketId, null);
989 showSavingProgress(albumName);
990 mImageShow.saveImage(this, null);
998 hideSavingProgress();
999 if (mLoadBitmapTask != null) {
1000 mLoadBitmapTask.cancel(false);
1006 System.loadLibrary("jni_filtershow_filters");
1009 private void extractXMPData() {
1010 XMresults res = XmpPresets.extractXMPData(
1011 getBaseContext(), mMasterImage, getIntent().getData());
1015 mOriginalImageUri = res.originalimage;
1016 mOriginalPreset = res.preset;