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 Uri mSelectedImageUri = null;
143 private CategoryAdapter mCategoryLooksAdapter = null;
144 private CategoryAdapter mCategoryBordersAdapter = null;
145 private CategoryAdapter mCategoryGeometryAdapter = null;
146 private CategoryAdapter mCategoryFiltersAdapter = null;
147 private int mCurrentPanel = MainPanel.LOOKS;
150 public void onCreate(Bundle savedInstanceState) {
151 super.onCreate(savedInstanceState);
153 boolean onlyUsePortrait = getResources().getBoolean(R.bool.only_use_portrait);
154 if (onlyUsePortrait) {
155 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
157 MasterImage.setMaster(mMasterImage);
159 clearGalleryBitmapPool();
161 CachingPipeline.createRenderscriptContext(this);
173 UsageStatistics.onContentViewChanged(UsageStatistics.COMPONENT_EDITOR, "Main");
174 UsageStatistics.onEvent(UsageStatistics.COMPONENT_EDITOR,
175 UsageStatistics.CATEGORY_LIFECYCLE, UsageStatistics.LIFECYCLE_START);
178 public boolean isShowingImageStatePanel() {
179 return mShowingImageStatePanel;
182 public void loadMainPanel() {
183 if (findViewById(R.id.main_panel_container) == null) {
186 MainPanel panel = new MainPanel();
187 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
188 transaction.replace(R.id.main_panel_container, panel, MainPanel.FRAGMENT_TAG);
189 transaction.commit();
192 public void loadEditorPanel(FilterRepresentation representation,
193 final Editor currentEditor) {
194 if (representation.getEditorId() == ImageOnlyEditor.ID) {
195 currentEditor.reflectCurrentFilter();
198 final int currentId = currentEditor.getID();
199 Runnable showEditor = new Runnable() {
202 EditorPanel panel = new EditorPanel();
203 panel.setEditor(currentId);
204 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
205 transaction.remove(getSupportFragmentManager().findFragmentByTag(MainPanel.FRAGMENT_TAG));
206 transaction.replace(R.id.main_panel_container, panel, MainPanel.FRAGMENT_TAG);
207 transaction.commit();
210 Fragment main = getSupportFragmentManager().findFragmentByTag(MainPanel.FRAGMENT_TAG);
211 boolean doAnimation = false;
212 if (mShowingImageStatePanel
213 && getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
216 if (doAnimation && main != null && main instanceof MainPanel) {
217 MainPanel mainPanel = (MainPanel) main;
218 View container = mainPanel.getView().findViewById(R.id.category_panel_container);
219 View bottom = mainPanel.getView().findViewById(R.id.bottom_panel);
220 int panelHeight = container.getHeight() + bottom.getHeight();
221 ViewPropertyAnimator anim = mainPanel.getView().animate();
222 anim.translationY(panelHeight).start();
223 final Handler handler = new Handler();
224 handler.postDelayed(showEditor, anim.getDuration());
230 private void loadXML() {
231 setContentView(R.layout.filtershow_activity);
233 ActionBar actionBar = getActionBar();
234 actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
235 actionBar.setCustomView(R.layout.filtershow_actionbar);
237 mSaveButton = actionBar.getCustomView();
238 mSaveButton.setOnClickListener(new OnClickListener() {
240 public void onClick(View view) {
245 mImageShow = (ImageShow) findViewById(R.id.imageShow);
246 mImageViews.add(mImageShow);
250 mEditorPlaceHolder.hide();
252 mImageShow.setImageLoader(mImageLoader);
262 public void setupStatePanel() {
263 mImageLoader.setAdapter(mMasterImage.getHistory());
266 private void fillFilters() {
267 Vector<FilterRepresentation> filtersRepresentations = new Vector<FilterRepresentation>();
268 FiltersManager filtersManager = FiltersManager.getManager();
269 filtersManager.addEffects(filtersRepresentations);
271 mCategoryFiltersAdapter = new CategoryAdapter(this);
272 for (FilterRepresentation representation : filtersRepresentations) {
273 if (representation.getTextId() != 0) {
274 representation.setName(getString(representation.getTextId()));
276 mCategoryFiltersAdapter.add(new Action(this, representation));
280 private void fillGeometry() {
281 Vector<FilterRepresentation> filtersRepresentations = new Vector<FilterRepresentation>();
282 FiltersManager filtersManager = FiltersManager.getManager();
284 GeometryMetadata geo = new GeometryMetadata();
285 int[] editorsId = geo.getEditorIds();
286 for (int i = 0; i < editorsId.length; i++) {
287 int editorId = editorsId[i];
288 GeometryMetadata geometry = new GeometryMetadata(geo);
289 geometry.setEditorId(editorId);
290 EditorInfo editorInfo = (EditorInfo) mEditorPlaceHolder.getEditor(editorId);
291 geometry.setTextId(editorInfo.getTextId());
292 geometry.setOverlayId(editorInfo.getOverlayId());
293 geometry.setOverlayOnly(editorInfo.getOverlayOnly());
294 if (geometry.getTextId() != 0) {
295 geometry.setName(getString(geometry.getTextId()));
297 filtersRepresentations.add(geometry);
300 filtersManager.addTools(filtersRepresentations);
302 mCategoryGeometryAdapter = new CategoryAdapter(this);
303 for (FilterRepresentation representation : filtersRepresentations) {
304 mCategoryGeometryAdapter.add(new Action(this, representation));
308 private void processIntent() {
309 Intent intent = getIntent();
310 if (intent.getBooleanExtra(LAUNCH_FULLSCREEN, false)) {
311 getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
314 mAction = intent.getAction();
315 mSelectedImageUri = intent.getData();
316 Uri loadUri = mSelectedImageUri;
317 if (mOriginalImageUri != null) {
318 loadUri = mOriginalImageUri;
320 if (loadUri != null) {
321 startLoadBitmap(loadUri);
327 private void setupEditors() {
328 mEditorPlaceHolder.setContainer((FrameLayout) findViewById(R.id.editorContainer));
329 EditorManager.addEditors(mEditorPlaceHolder);
330 mEditorPlaceHolder.setOldViews(mImageViews);
331 mEditorPlaceHolder.setImageLoader(mImageLoader);
334 private void fillEditors() {
335 mEditorPlaceHolder.addEditor(new EditorDraw());
336 mEditorPlaceHolder.addEditor(new BasicEditor());
337 mEditorPlaceHolder.addEditor(new ImageOnlyEditor());
338 mEditorPlaceHolder.addEditor(new EditorTinyPlanet());
339 mEditorPlaceHolder.addEditor(new EditorRedEye());
340 mEditorPlaceHolder.addEditor(new EditorCrop());
341 mEditorPlaceHolder.addEditor(new EditorFlip());
342 mEditorPlaceHolder.addEditor(new EditorRotate());
343 mEditorPlaceHolder.addEditor(new EditorStraighten());
346 private void setDefaultValues() {
347 ImageFilter.setActivityForMemoryToasts(this);
349 Resources res = getResources();
350 FiltersManager.setResources(res);
352 CategoryView.setMargin((int) getPixelsFromDip(8));
353 CategoryView.setTextSize((int) getPixelsFromDip(16));
355 // TODO: get those values from XML.
356 FramedTextButton.setTextSize((int) getPixelsFromDip(14));
357 FramedTextButton.setTrianglePadding((int) getPixelsFromDip(4));
358 FramedTextButton.setTriangleSize((int) getPixelsFromDip(10));
360 Drawable curveHandle = res.getDrawable(R.drawable.camera_crop);
361 int curveHandleSize = (int) res.getDimension(R.dimen.crop_indicator_size);
362 Spline.setCurveHandle(curveHandle, curveHandleSize);
363 Spline.setCurveWidth((int) getPixelsFromDip(3));
365 ImageCrop.setAspectTextSize((int) getPixelsFromDip(18));
366 ImageCrop.setTouchTolerance((int) getPixelsFromDip(25));
367 ImageCrop.setMinCropSize((int) getPixelsFromDip(55));
370 private void startLoadBitmap(Uri uri) {
372 final View loading = findViewById(R.id.loading);
373 final View imageShow = findViewById(R.id.imageShow);
374 imageShow.setVisibility(View.INVISIBLE);
375 loading.setVisibility(View.VISIBLE);
376 mShowingTinyPlanet = false;
377 mLoadBitmapTask = new LoadBitmapTask();
378 mLoadBitmapTask.execute(uri);
381 private void fillBorders() {
382 Vector<FilterRepresentation> borders = new Vector<FilterRepresentation>();
384 // The "no border" implementation
385 borders.add(new FilterImageBorderRepresentation(0));
387 // Google-build borders
388 FiltersManager.getManager().addBorders(this, borders);
390 for (int i = 0; i < borders.size(); i++) {
391 FilterRepresentation filter = borders.elementAt(i);
392 filter.setName(getString(R.string.borders));
394 filter.setName(getString(R.string.none));
398 mCategoryBordersAdapter = new CategoryAdapter(this);
399 for (FilterRepresentation representation : borders) {
400 if (representation.getTextId() != 0) {
401 representation.setName(getString(representation.getTextId()));
403 mCategoryBordersAdapter.add(new Action(this, representation, Action.FULL_VIEW));
407 public CategoryAdapter getCategoryLooksAdapter() {
408 return mCategoryLooksAdapter;
411 public CategoryAdapter getCategoryBordersAdapter() {
412 return mCategoryBordersAdapter;
415 public CategoryAdapter getCategoryGeometryAdapter() {
416 return mCategoryGeometryAdapter;
419 public CategoryAdapter getCategoryFiltersAdapter() {
420 return mCategoryFiltersAdapter;
423 public void removeFilterRepresentation(FilterRepresentation filterRepresentation) {
424 if (filterRepresentation == null) {
427 ImagePreset oldPreset = MasterImage.getImage().getPreset();
428 ImagePreset copy = new ImagePreset(oldPreset);
429 copy.removeFilter(filterRepresentation);
430 MasterImage.getImage().setPreset(copy, true);
431 if (MasterImage.getImage().getCurrentFilterRepresentation() == filterRepresentation) {
432 FilterRepresentation lastRepresentation = copy.getLastRepresentation();
433 MasterImage.getImage().setCurrentFilterRepresentation(lastRepresentation);
437 public void useFilterRepresentation(FilterRepresentation filterRepresentation) {
438 if (filterRepresentation == null) {
441 if (MasterImage.getImage().getCurrentFilterRepresentation() == filterRepresentation) {
444 ImagePreset oldPreset = MasterImage.getImage().getPreset();
445 ImagePreset copy = new ImagePreset(oldPreset);
446 FilterRepresentation representation = copy.getRepresentation(filterRepresentation);
447 if (representation == null) {
448 copy.addFilter(filterRepresentation);
450 if (filterRepresentation.allowsSingleInstanceOnly()) {
451 representation.updateTempParametersFrom(filterRepresentation);
452 copy.setHistoryName(filterRepresentation.getName());
453 representation.synchronizeRepresentation();
455 filterRepresentation = representation;
457 MasterImage.getImage().setPreset(copy, true);
458 MasterImage.getImage().setCurrentFilterRepresentation(filterRepresentation);
461 public void showRepresentation(FilterRepresentation representation) {
462 if (representation == null) {
465 useFilterRepresentation(representation);
467 // show representation
468 Editor mCurrentEditor = mEditorPlaceHolder.showEditor(representation.getEditorId());
469 loadEditorPanel(representation, mCurrentEditor);
472 public Editor getEditor(int editorID) {
473 return mEditorPlaceHolder.getEditor(editorID);
476 public void setCurrentPanel(int currentPanel) {
477 mCurrentPanel = currentPanel;
480 public int getCurrentPanel() {
481 return mCurrentPanel;
484 private class LoadBitmapTask extends AsyncTask<Uri, Boolean, Boolean> {
487 public LoadBitmapTask() {
488 mBitmapSize = getScreenImageSize();
492 protected Boolean doInBackground(Uri... params) {
493 if (!mImageLoader.loadBitmap(params[0], mBitmapSize)) {
496 publishProgress(mImageLoader.queryLightCycle360());
501 protected void onProgressUpdate(Boolean... values) {
502 super.onProgressUpdate(values);
507 mShowingTinyPlanet = true;
512 protected void onPostExecute(Boolean result) {
513 MasterImage.setMaster(mMasterImage);
522 if (null == CachingPipeline.getRenderScriptContext()){
523 Log.v(LOGTAG,"RenderScript context destroyed during load");
526 final View loading = findViewById(R.id.loading);
527 loading.setVisibility(View.GONE);
528 final View imageShow = findViewById(R.id.imageShow);
529 imageShow.setVisibility(View.VISIBLE);
531 Bitmap largeBitmap = mImageLoader.getOriginalBitmapLarge();
532 FilteringPipeline pipeline = FilteringPipeline.getPipeline();
533 pipeline.setOriginal(largeBitmap);
534 float previewScale = (float) largeBitmap.getWidth() / (float) mImageLoader.getOriginalBounds().width();
535 pipeline.setPreviewScaleFactor(previewScale);
536 Bitmap highresBitmap = mImageLoader.getOriginalBitmapHighres();
537 if (highresBitmap != null) {
538 float highResPreviewScale = (float) highresBitmap.getWidth() / (float) mImageLoader.getOriginalBounds().width();
539 pipeline.setHighResPreviewScaleFactor(highResPreviewScale);
541 if (!mShowingTinyPlanet) {
542 mCategoryFiltersAdapter.removeTinyPlanet();
544 pipeline.turnOnPipeline(true);
545 MasterImage.getImage().setOriginalGeometry(largeBitmap);
546 mCategoryLooksAdapter.imageLoaded();
547 mCategoryBordersAdapter.imageLoaded();
548 mCategoryGeometryAdapter.imageLoaded();
549 mCategoryFiltersAdapter.imageLoaded();
550 mLoadBitmapTask = null;
552 if (mOriginalPreset != null) {
553 MasterImage.getImage().setPreset(mOriginalPreset, true);
554 mOriginalPreset = null;
557 if (mAction == TINY_PLANET_ACTION) {
558 showRepresentation(mCategoryFiltersAdapter.getTinyPlanet());
561 super.onPostExecute(result);
566 private void clearGalleryBitmapPool() {
567 (new AsyncTask<Void, Void, Void>() {
569 protected Void doInBackground(Void... params) {
570 // Free memory held in Gallery's Bitmap pool. May be O(n) for n bitmaps.
571 GalleryBitmapPool.getInstance().clear();
578 protected void onDestroy() {
579 if (mLoadBitmapTask != null) {
580 mLoadBitmapTask.cancel(false);
582 // TODO: refactor, don't use so many singletons.
583 FilteringPipeline.getPipeline().turnOnPipeline(false);
585 FilteringPipeline.reset();
586 ImageFilter.resetStatics();
587 FiltersManager.getPreviewManager().freeRSFilterScripts();
588 FiltersManager.getManager().freeRSFilterScripts();
589 FiltersManager.getHighresManager().freeRSFilterScripts();
590 FiltersManager.reset();
591 CachingPipeline.destroyRenderScriptContext();
595 private int getScreenImageSize() {
596 DisplayMetrics metrics = new DisplayMetrics();
597 Display display = getWindowManager().getDefaultDisplay();
598 Point size = new Point();
599 display.getSize(size);
600 display.getMetrics(metrics);
601 int msize = Math.min(size.x, size.y);
602 return (133 * msize) / metrics.densityDpi;
605 private void showSavingProgress(String albumName) {
606 ProgressDialog progress;
607 if (mSavingProgressDialog != null) {
608 progress = mSavingProgressDialog.get();
609 if (progress != null) {
614 // TODO: Allow cancellation of the saving process
616 if (albumName == null) {
617 progressText = getString(R.string.saving_image);
619 progressText = getString(R.string.filtershow_saving_image, albumName);
621 progress = ProgressDialog.show(this, "", progressText, true, false);
622 mSavingProgressDialog = new WeakReference<ProgressDialog>(progress);
625 private void hideSavingProgress() {
626 if (mSavingProgressDialog != null) {
627 ProgressDialog progress = mSavingProgressDialog.get();
628 if (progress != null)
633 public void completeSaveImage(Uri saveUri) {
634 if (mSharingImage && mSharedOutputFile != null) {
635 // Image saved, we unblock the content provider
636 Uri uri = Uri.withAppendedPath(SharedImageProvider.CONTENT_URI,
637 Uri.encode(mSharedOutputFile.getAbsolutePath()));
638 ContentValues values = new ContentValues();
639 values.put(SharedImageProvider.PREPARE, false);
640 getContentResolver().insert(uri, values);
642 setResult(RESULT_OK, new Intent().setData(saveUri));
643 hideSavingProgress();
648 public boolean onShareTargetSelected(ShareActionProvider arg0, Intent arg1) {
649 // First, let's tell the SharedImageProvider that it will need to wait
651 Uri uri = Uri.withAppendedPath(SharedImageProvider.CONTENT_URI,
652 Uri.encode(mSharedOutputFile.getAbsolutePath()));
653 ContentValues values = new ContentValues();
654 values.put(SharedImageProvider.PREPARE, true);
655 getContentResolver().insert(uri, values);
656 mSharingImage = true;
658 // Process and save the image in the background.
659 showSavingProgress(null);
660 mImageShow.saveImage(this, mSharedOutputFile);
664 private Intent getDefaultShareIntent() {
665 Intent intent = new Intent(Intent.ACTION_SEND);
666 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
667 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
668 intent.setType(SharedImageProvider.MIME_TYPE);
669 mSharedOutputFile = SaveCopyTask.getNewFile(this, mImageLoader.getUri());
670 Uri uri = Uri.withAppendedPath(SharedImageProvider.CONTENT_URI,
671 Uri.encode(mSharedOutputFile.getAbsolutePath()));
672 intent.putExtra(Intent.EXTRA_STREAM, uri);
677 public boolean onCreateOptionsMenu(Menu menu) {
678 getMenuInflater().inflate(R.menu.filtershow_activity_menu, menu);
679 MenuItem showState = menu.findItem(R.id.showImageStateButton);
680 if (mShowingImageStatePanel) {
681 showState.setTitle(R.string.hide_imagestate_panel);
683 showState.setTitle(R.string.show_imagestate_panel);
685 mShareActionProvider = (ShareActionProvider) menu.findItem(R.id.menu_share)
686 .getActionProvider();
687 mShareActionProvider.setShareIntent(getDefaultShareIntent());
688 mShareActionProvider.setOnShareTargetSelectedListener(this);
690 MenuItem undoItem = menu.findItem(R.id.undoButton);
691 MenuItem redoItem = menu.findItem(R.id.redoButton);
692 MenuItem resetItem = menu.findItem(R.id.resetHistoryButton);
693 mMasterImage.getHistory().setMenuItems(undoItem, redoItem, resetItem);
698 public void onPause() {
701 if (mShareActionProvider != null) {
702 mShareActionProvider.setOnShareTargetSelectedListener(null);
707 public void onResume() {
710 if (mShareActionProvider != null) {
711 mShareActionProvider.setOnShareTargetSelectedListener(this);
715 private void rsResume() {
716 ImageFilter.setActivityForMemoryToasts(this);
717 MasterImage.setMaster(mMasterImage);
718 if (CachingPipeline.getRenderScriptContext() == null) {
719 CachingPipeline.createRenderscriptContext(this);
721 FiltersManager.setResources(getResources());
723 Bitmap largeBitmap = mImageLoader.getOriginalBitmapLarge();
724 FilteringPipeline pipeline = FilteringPipeline.getPipeline();
725 pipeline.setOriginal(largeBitmap);
726 float previewScale = (float) largeBitmap.getWidth() /
727 (float) mImageLoader.getOriginalBounds().width();
728 pipeline.setPreviewScaleFactor(previewScale);
729 Bitmap highresBitmap = mImageLoader.getOriginalBitmapHighres();
730 if (highresBitmap != null) {
731 float highResPreviewScale = (float) highresBitmap.getWidth() /
732 (float) mImageLoader.getOriginalBounds().width();
733 pipeline.setHighResPreviewScaleFactor(highResPreviewScale);
735 pipeline.turnOnPipeline(true);
736 MasterImage.getImage().setOriginalGeometry(largeBitmap);
740 private void rsPause() {
741 FilteringPipeline.getPipeline().turnOnPipeline(false);
742 FilteringPipeline.reset();
743 ImageFilter.resetStatics();
744 FiltersManager.getPreviewManager().freeRSFilterScripts();
745 FiltersManager.getManager().freeRSFilterScripts();
746 FiltersManager.getHighresManager().freeRSFilterScripts();
747 FiltersManager.reset();
748 CachingPipeline.destroyRenderScriptContext();
752 public boolean onOptionsItemSelected(MenuItem item) {
753 switch (item.getItemId()) {
754 case R.id.undoButton: {
755 HistoryAdapter adapter = mMasterImage.getHistory();
756 int position = adapter.undo();
757 mMasterImage.onHistoryItemClick(position);
760 UsageStatistics.onEvent(UsageStatistics.COMPONENT_EDITOR,
761 UsageStatistics.CATEGORY_BUTTON_PRESS, "Undo");
764 case R.id.redoButton: {
765 HistoryAdapter adapter = mMasterImage.getHistory();
766 int position = adapter.redo();
767 mMasterImage.onHistoryItemClick(position);
769 UsageStatistics.onEvent(UsageStatistics.COMPONENT_EDITOR,
770 UsageStatistics.CATEGORY_BUTTON_PRESS, "Redo");
773 case R.id.resetHistoryButton: {
775 UsageStatistics.onEvent(UsageStatistics.COMPONENT_EDITOR,
776 UsageStatistics.CATEGORY_BUTTON_PRESS, "ResetHistory");
779 case R.id.showImageStateButton: {
780 toggleImageStatePanel();
781 UsageStatistics.onEvent(UsageStatistics.COMPONENT_EDITOR,
782 UsageStatistics.CATEGORY_BUTTON_PRESS,
783 mShowingImageStatePanel ? "ShowPanel" : "HidePanel");
786 case android.R.id.home: {
794 public void enableSave(boolean enable) {
795 if (mSaveButton != null)
796 mSaveButton.setEnabled(enable);
799 private void fillFx() {
800 FilterFxRepresentation nullFx =
801 new FilterFxRepresentation(getString(R.string.none), 0, R.string.none);
802 Vector<FilterRepresentation> filtersRepresentations = new Vector<FilterRepresentation>();
803 FiltersManager.getManager().addLooks(this, filtersRepresentations);
805 mCategoryLooksAdapter = new CategoryAdapter(this);
806 int verticalItemHeight = (int) getResources().getDimension(R.dimen.action_item_height);
807 mCategoryLooksAdapter.setItemHeight(verticalItemHeight);
808 mCategoryLooksAdapter.add(new Action(this, nullFx, Action.FULL_VIEW));
809 for (FilterRepresentation representation : filtersRepresentations) {
810 mCategoryLooksAdapter.add(new Action(this, representation, Action.FULL_VIEW));
814 public void setDefaultPreset() {
815 // Default preset (original)
816 ImagePreset preset = new ImagePreset(getString(R.string.history_original)); // empty
817 preset.setImageLoader(mImageLoader);
819 mMasterImage.setPreset(preset, true);
822 // //////////////////////////////////////////////////////////////////////////////
823 // Some utility functions
824 // TODO: finish the cleanup.
826 public void invalidateViews() {
827 for (ImageShow views : mImageViews) {
833 public void hideImageViews() {
834 for (View view : mImageViews) {
835 view.setVisibility(View.GONE);
837 mEditorPlaceHolder.hide();
840 // //////////////////////////////////////////////////////////////////////////////
841 // imageState panel...
843 public void toggleImageStatePanel() {
844 invalidateOptionsMenu();
845 mShowingImageStatePanel = !mShowingImageStatePanel;
846 Fragment panel = getSupportFragmentManager().findFragmentByTag(MainPanel.FRAGMENT_TAG);
848 if (panel instanceof EditorPanel) {
849 EditorPanel editorPanel = (EditorPanel) panel;
850 editorPanel.showImageStatePanel(mShowingImageStatePanel);
851 } else if (panel instanceof MainPanel) {
852 MainPanel mainPanel = (MainPanel) panel;
853 mainPanel.showImageStatePanel(mShowingImageStatePanel);
859 public void onConfigurationChanged(Configuration newConfig)
861 super.onConfigurationChanged(newConfig);
866 // mLoadBitmapTask==null implies you have looked at the intent
867 if (!mShowingTinyPlanet && (mLoadBitmapTask == null)) {
868 mCategoryFiltersAdapter.removeTinyPlanet();
870 final View loading = findViewById(R.id.loading);
871 loading.setVisibility(View.GONE);
874 public void setupMasterImage() {
875 mImageLoader = new ImageLoader(this, getApplicationContext());
877 HistoryAdapter mHistoryAdapter = new HistoryAdapter(
878 this, R.layout.filtershow_history_operation_row,
881 StateAdapter mImageStateAdapter = new StateAdapter(this, 0);
883 mMasterImage = MasterImage.getImage();
884 mMasterImage.setHistoryAdapter(mHistoryAdapter);
885 mMasterImage.setStateAdapter(mImageStateAdapter);
886 mMasterImage.setActivity(this);
887 mMasterImage.setImageLoader(mImageLoader);
889 if (Runtime.getRuntime().maxMemory() > LIMIT_SUPPORTS_HIGHRES) {
890 mMasterImage.setSupportsHighRes(true);
892 mMasterImage.setSupportsHighRes(false);
896 void resetHistory() {
897 HistoryAdapter adapter = mMasterImage.getHistory();
899 ImagePreset original = new ImagePreset(adapter.getItem(0));
900 mMasterImage.setPreset(original, true);
905 public void showDefaultImageView() {
906 mEditorPlaceHolder.hide();
907 mImageShow.setVisibility(View.VISIBLE);
908 MasterImage.getImage().setCurrentFilter(null);
909 MasterImage.getImage().setCurrentFilterRepresentation(null);
912 public void backToMain() {
913 Fragment currentPanel = getSupportFragmentManager().findFragmentByTag(MainPanel.FRAGMENT_TAG);
914 if (currentPanel instanceof MainPanel) {
918 showDefaultImageView();
922 public void onBackPressed() {
923 Fragment currentPanel = getSupportFragmentManager().findFragmentByTag(MainPanel.FRAGMENT_TAG);
924 if (currentPanel instanceof MainPanel) {
925 if (!mImageShow.hasModifications()) {
928 AlertDialog.Builder builder = new AlertDialog.Builder(this);
929 builder.setMessage(R.string.unsaved).setTitle(R.string.save_before_exit);
930 builder.setPositiveButton(R.string.save_and_exit, new DialogInterface.OnClickListener() {
932 public void onClick(DialogInterface dialog, int id) {
936 builder.setNegativeButton(R.string.exit, new DialogInterface.OnClickListener() {
938 public void onClick(DialogInterface dialog, int id) {
949 public void cannotLoadImage() {
950 Toast.makeText(this, R.string.cannot_load_image, Toast.LENGTH_SHORT).show();
954 // //////////////////////////////////////////////////////////////////////////////
956 public float getPixelsFromDip(float value) {
957 Resources r = getResources();
958 return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, value,
959 r.getDisplayMetrics());
963 public void onItemClick(AdapterView<?> parent, View view, int position,
965 mMasterImage.onHistoryItemClick(position);
969 public void pickImage() {
970 Intent intent = new Intent();
971 intent.setType("image/*");
972 intent.setAction(Intent.ACTION_GET_CONTENT);
973 startActivityForResult(Intent.createChooser(intent, getString(R.string.select_image)),
978 public void onActivityResult(int requestCode, int resultCode, Intent data) {
979 if (resultCode == RESULT_OK) {
980 if (requestCode == SELECT_PICTURE) {
981 Uri selectedImageUri = data.getData();
982 startLoadBitmap(selectedImageUri);
988 public void saveImage() {
989 if (mImageShow.hasModifications()) {
990 // Get the name of the album, to which the image will be saved
991 File saveDir = SaveCopyTask.getFinalSaveDirectory(this, mSelectedImageUri);
992 int bucketId = GalleryUtils.getBucketId(saveDir.getPath());
993 String albumName = LocalAlbum.getLocalizedName(getResources(), bucketId, null);
994 showSavingProgress(albumName);
995 mImageShow.saveImage(this, null);
1002 public void done() {
1003 hideSavingProgress();
1004 if (mLoadBitmapTask != null) {
1005 mLoadBitmapTask.cancel(false);
1010 private void extractXMPData() {
1011 XMresults res = XmpPresets.extractXMPData(
1012 getBaseContext(), mMasterImage, getIntent().getData());
1016 mOriginalImageUri = res.originalimage;
1017 mOriginalPreset = res.preset;
1020 public Uri getSelectedImageUri() {
1021 return mSelectedImageUri;
1025 System.loadLibrary("jni_filtershow_filters");