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.ComponentName;
23 import android.content.ContentValues;
24 import android.content.Context;
25 import android.content.DialogInterface;
26 import android.content.Intent;
27 import android.content.ServiceConnection;
28 import android.content.pm.ActivityInfo;
29 import android.content.res.Configuration;
30 import android.content.res.Resources;
31 import android.graphics.Bitmap;
32 import android.graphics.Color;
33 import android.graphics.Matrix;
34 import android.graphics.Point;
35 import android.graphics.Rect;
36 import android.graphics.RectF;
37 import android.graphics.drawable.ColorDrawable;
38 import android.graphics.drawable.Drawable;
39 import android.net.Uri;
40 import android.os.AsyncTask;
41 import android.os.Bundle;
42 import android.os.CancellationSignal;
43 import android.os.Handler;
44 import android.os.IBinder;
45 import android.support.v4.app.DialogFragment;
46 import android.support.v4.app.Fragment;
47 import android.support.v4.app.FragmentActivity;
48 import android.support.v4.app.FragmentTransaction;
49 import android.support.v4.print.PrintHelper;
50 import android.util.DisplayMetrics;
51 import android.util.Log;
52 import android.util.TypedValue;
53 import android.view.Menu;
54 import android.view.MenuItem;
55 import android.view.MotionEvent;
56 import android.view.View;
57 import android.view.View.OnClickListener;
58 import android.view.ViewPropertyAnimator;
59 import android.view.WindowManager;
60 import android.widget.AdapterView;
61 import android.widget.AdapterView.OnItemClickListener;
62 import android.widget.FrameLayout;
63 import android.widget.PopupMenu;
64 import android.widget.ShareActionProvider;
65 import android.widget.ShareActionProvider.OnShareTargetSelectedListener;
66 import android.widget.Spinner;
67 import android.widget.Toast;
69 import com.android.gallery3d.R;
70 import com.android.gallery3d.app.PhotoPage;
71 import com.android.gallery3d.data.LocalAlbum;
72 import com.android.gallery3d.filtershow.cache.ImageLoader;
73 import com.android.gallery3d.filtershow.category.Action;
74 import com.android.gallery3d.filtershow.category.CategoryAdapter;
75 import com.android.gallery3d.filtershow.category.CategorySelected;
76 import com.android.gallery3d.filtershow.category.CategoryView;
77 import com.android.gallery3d.filtershow.category.MainPanel;
78 import com.android.gallery3d.filtershow.category.SwipableView;
79 import com.android.gallery3d.filtershow.data.UserPresetsManager;
80 import com.android.gallery3d.filtershow.editors.BasicEditor;
81 import com.android.gallery3d.filtershow.editors.Editor;
82 import com.android.gallery3d.filtershow.editors.EditorChanSat;
83 import com.android.gallery3d.filtershow.editors.EditorColorBorder;
84 import com.android.gallery3d.filtershow.editors.EditorCrop;
85 import com.android.gallery3d.filtershow.editors.EditorDraw;
86 import com.android.gallery3d.filtershow.editors.EditorGrad;
87 import com.android.gallery3d.filtershow.editors.EditorManager;
88 import com.android.gallery3d.filtershow.editors.EditorMirror;
89 import com.android.gallery3d.filtershow.editors.EditorPanel;
90 import com.android.gallery3d.filtershow.editors.EditorRedEye;
91 import com.android.gallery3d.filtershow.editors.EditorRotate;
92 import com.android.gallery3d.filtershow.editors.EditorStraighten;
93 import com.android.gallery3d.filtershow.editors.EditorTinyPlanet;
94 import com.android.gallery3d.filtershow.editors.ImageOnlyEditor;
95 import com.android.gallery3d.filtershow.filters.FilterDrawRepresentation;
96 import com.android.gallery3d.filtershow.filters.FilterMirrorRepresentation;
97 import com.android.gallery3d.filtershow.filters.FilterRepresentation;
98 import com.android.gallery3d.filtershow.filters.FilterRotateRepresentation;
99 import com.android.gallery3d.filtershow.filters.FilterStraightenRepresentation;
100 import com.android.gallery3d.filtershow.filters.FilterUserPresetRepresentation;
101 import com.android.gallery3d.filtershow.filters.FiltersManager;
102 import com.android.gallery3d.filtershow.filters.ImageFilter;
103 import com.android.gallery3d.filtershow.history.HistoryItem;
104 import com.android.gallery3d.filtershow.history.HistoryManager;
105 import com.android.gallery3d.filtershow.imageshow.ImageShow;
106 import com.android.gallery3d.filtershow.imageshow.MasterImage;
107 import com.android.gallery3d.filtershow.imageshow.Spline;
108 import com.android.gallery3d.filtershow.info.InfoPanel;
109 import com.android.gallery3d.filtershow.pipeline.CachingPipeline;
110 import com.android.gallery3d.filtershow.pipeline.ImagePreset;
111 import com.android.gallery3d.filtershow.pipeline.ProcessingService;
112 import com.android.gallery3d.filtershow.presets.PresetManagementDialog;
113 import com.android.gallery3d.filtershow.presets.UserPresetsAdapter;
114 import com.android.gallery3d.filtershow.provider.SharedImageProvider;
115 import com.android.gallery3d.filtershow.state.StateAdapter;
116 import com.android.gallery3d.filtershow.tools.SaveImage;
117 import com.android.gallery3d.filtershow.tools.XmpPresets;
118 import com.android.gallery3d.filtershow.tools.XmpPresets.XMresults;
119 import com.android.gallery3d.filtershow.ui.ExportDialog;
120 import com.android.gallery3d.filtershow.ui.FramedTextButton;
121 import com.android.gallery3d.util.GalleryUtils;
122 import com.android.photos.data.GalleryBitmapPool;
125 import java.io.FileDescriptor;
126 import java.io.FileOutputStream;
127 import java.lang.ref.WeakReference;
128 import java.util.ArrayList;
129 import java.util.Vector;
131 public class FilterShowActivity extends FragmentActivity implements OnItemClickListener,
132 OnShareTargetSelectedListener, DialogInterface.OnShowListener,
133 DialogInterface.OnDismissListener, PopupMenu.OnDismissListener{
135 private String mAction = "";
136 MasterImage mMasterImage = null;
138 private static final long LIMIT_SUPPORTS_HIGHRES = 134217728; // 128Mb
140 public static final String TINY_PLANET_ACTION = "com.android.camera.action.TINY_PLANET";
141 public static final String LAUNCH_FULLSCREEN = "launch-fullscreen";
142 public static final boolean RESET_TO_LOADED = false;
143 private ImageShow mImageShow = null;
145 private View mSaveButton = null;
147 private EditorPlaceHolder mEditorPlaceHolder = new EditorPlaceHolder(this);
148 private Editor mCurrentEditor = null;
150 private static final int SELECT_PICTURE = 1;
151 private static final String LOGTAG = "FilterShowActivity";
153 private boolean mShowingTinyPlanet = false;
154 private boolean mShowingImageStatePanel = false;
155 private boolean mShowingVersionsPanel = false;
157 private final Vector<ImageShow> mImageViews = new Vector<ImageShow>();
159 private ShareActionProvider mShareActionProvider;
160 private File mSharedOutputFile = null;
162 private boolean mSharingImage = false;
164 private WeakReference<ProgressDialog> mSavingProgressDialog;
166 private LoadBitmapTask mLoadBitmapTask;
168 private Uri mOriginalImageUri = null;
169 private ImagePreset mOriginalPreset = null;
171 private Uri mSelectedImageUri = null;
173 private ArrayList<Action> mActions = new ArrayList<Action>();
174 private UserPresetsManager mUserPresetsManager = null;
175 private UserPresetsAdapter mUserPresetsAdapter = null;
176 private CategoryAdapter mCategoryLooksAdapter = null;
177 private CategoryAdapter mCategoryBordersAdapter = null;
178 private CategoryAdapter mCategoryGeometryAdapter = null;
179 private CategoryAdapter mCategoryFiltersAdapter = null;
180 private CategoryAdapter mCategoryVersionsAdapter = null;
181 private int mCurrentPanel = MainPanel.LOOKS;
182 private Vector<FilterUserPresetRepresentation> mVersions =
183 new Vector<FilterUserPresetRepresentation>();
184 private int mVersionsCounter = 0;
186 private boolean mHandlingSwipeButton = false;
187 private View mHandledSwipeView = null;
188 private float mHandledSwipeViewLastDelta = 0;
189 private float mSwipeStartX = 0;
190 private float mSwipeStartY = 0;
192 private ProcessingService mBoundService;
193 private boolean mIsBound = false;
195 private DialogInterface mCurrentDialog = null;
196 private PopupMenu mCurrentMenu = null;
197 private boolean mLoadingVisible = true;
199 public ProcessingService getProcessingService() {
200 return mBoundService;
203 public boolean isSimpleEditAction() {
204 return !PhotoPage.ACTION_NEXTGEN_EDIT.equalsIgnoreCase(mAction);
207 private ServiceConnection mConnection = new ServiceConnection() {
209 public void onServiceConnected(ComponentName className, IBinder service) {
211 * This is called when the connection with the service has been
212 * established, giving us the service object we can use to
213 * interact with the service. Because we have bound to a explicit
214 * service that we know is running in our own process, we can
215 * cast its IBinder to a concrete class and directly access it.
217 mBoundService = ((ProcessingService.LocalBinder)service).getService();
218 mBoundService.setFiltershowActivity(FilterShowActivity.this);
219 mBoundService.onStart();
223 public void onServiceDisconnected(ComponentName className) {
225 * This is called when the connection with the service has been
226 * unexpectedly disconnected -- that is, its process crashed.
227 * Because it is running in our same process, we should never
230 mBoundService = null;
234 void doBindService() {
236 * Establish a connection with the service. We use an explicit
237 * class name because we want a specific service implementation that
238 * we know will be running in our own process (and thus won't be
239 * supporting component replacement by other applications).
241 bindService(new Intent(FilterShowActivity.this, ProcessingService.class),
242 mConnection, Context.BIND_AUTO_CREATE);
246 void doUnbindService() {
248 // Detach our existing connection.
249 unbindService(mConnection);
254 public void updateUIAfterServiceStarted() {
255 MasterImage.setMaster(mMasterImage);
256 ImageFilter.setActivityForMemoryToasts(this);
257 mUserPresetsManager = new UserPresetsManager(this);
258 mUserPresetsAdapter = new UserPresetsAdapter(this);
264 getWindow().setBackgroundDrawable(new ColorDrawable(0));
274 public void onCreate(Bundle savedInstanceState) {
275 super.onCreate(savedInstanceState);
277 boolean onlyUsePortrait = getResources().getBoolean(R.bool.only_use_portrait);
278 if (onlyUsePortrait) {
279 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
282 clearGalleryBitmapPool();
284 getWindow().setBackgroundDrawable(new ColorDrawable(Color.GRAY));
285 setContentView(R.layout.filtershow_splashscreen);
288 public boolean isShowingImageStatePanel() {
289 return mShowingImageStatePanel;
292 public void loadMainPanel() {
293 if (findViewById(R.id.main_panel_container) == null) {
296 MainPanel panel = new MainPanel();
297 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
298 transaction.replace(R.id.main_panel_container, panel, MainPanel.FRAGMENT_TAG);
299 transaction.commitAllowingStateLoss();
302 public void loadEditorPanel(FilterRepresentation representation,
303 final Editor currentEditor) {
304 if (representation.getEditorId() == ImageOnlyEditor.ID) {
305 currentEditor.reflectCurrentFilter();
308 final int currentId = currentEditor.getID();
309 Runnable showEditor = new Runnable() {
312 EditorPanel panel = new EditorPanel();
313 panel.setEditor(currentId);
314 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
315 transaction.remove(getSupportFragmentManager().findFragmentByTag(MainPanel.FRAGMENT_TAG));
316 transaction.replace(R.id.main_panel_container, panel, MainPanel.FRAGMENT_TAG);
317 transaction.commit();
320 Fragment main = getSupportFragmentManager().findFragmentByTag(MainPanel.FRAGMENT_TAG);
321 boolean doAnimation = false;
322 if (mShowingImageStatePanel
323 && getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
326 if (doAnimation && main != null && main instanceof MainPanel) {
327 MainPanel mainPanel = (MainPanel) main;
328 View container = mainPanel.getView().findViewById(R.id.category_panel_container);
329 View bottom = mainPanel.getView().findViewById(R.id.bottom_panel);
330 int panelHeight = container.getHeight() + bottom.getHeight();
331 ViewPropertyAnimator anim = mainPanel.getView().animate();
332 anim.translationY(panelHeight).start();
333 final Handler handler = new Handler();
334 handler.postDelayed(showEditor, anim.getDuration());
340 public void toggleInformationPanel() {
341 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
342 transaction.setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left);
344 InfoPanel panel = new InfoPanel();
345 panel.show(transaction, InfoPanel.FRAGMENT_TAG);
348 private void loadXML() {
349 setContentView(R.layout.filtershow_activity);
351 ActionBar actionBar = getActionBar();
352 actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
353 actionBar.setCustomView(R.layout.filtershow_actionbar);
354 actionBar.setBackgroundDrawable(new ColorDrawable(
355 getResources().getColor(R.color.background_screen)));
357 mSaveButton = actionBar.getCustomView();
358 mSaveButton.setOnClickListener(new OnClickListener() {
360 public void onClick(View view) {
365 mImageShow = (ImageShow) findViewById(R.id.imageShow);
366 mImageViews.add(mImageShow);
370 mEditorPlaceHolder.hide();
376 public void fillCategories() {
385 public void setupStatePanel() {
386 MasterImage.getImage().setHistoryManager(mMasterImage.getHistory());
389 private void fillVersions() {
390 if (mCategoryVersionsAdapter != null) {
391 mCategoryVersionsAdapter.clear();
393 mCategoryVersionsAdapter = new CategoryAdapter(this);
394 mCategoryVersionsAdapter.setShowAddButton(true);
397 public void registerAction(Action action) {
398 if (mActions.contains(action)) {
401 mActions.add(action);
404 private void loadActions() {
405 for (int i = 0; i < mActions.size(); i++) {
406 Action action = mActions.get(i);
407 action.setImageFrame(new Rect(0, 0, 96, 96), 0);
411 public void updateVersions() {
412 mCategoryVersionsAdapter.clear();
413 FilterUserPresetRepresentation originalRep = new FilterUserPresetRepresentation(
414 getString(R.string.filtershow_version_original), new ImagePreset(), -1);
415 mCategoryVersionsAdapter.add(
416 new Action(this, originalRep, Action.FULL_VIEW));
417 ImagePreset current = new ImagePreset(MasterImage.getImage().getPreset());
418 FilterUserPresetRepresentation currentRep = new FilterUserPresetRepresentation(
419 getString(R.string.filtershow_version_current), current, -1);
420 mCategoryVersionsAdapter.add(
421 new Action(this, currentRep, Action.FULL_VIEW));
422 if (mVersions.size() > 0) {
423 mCategoryVersionsAdapter.add(new Action(this, Action.SPACER));
425 for (FilterUserPresetRepresentation rep : mVersions) {
426 mCategoryVersionsAdapter.add(
427 new Action(this, rep, Action.FULL_VIEW, true));
429 mCategoryVersionsAdapter.notifyDataSetInvalidated();
432 public void addCurrentVersion() {
433 ImagePreset current = new ImagePreset(MasterImage.getImage().getPreset());
435 FilterUserPresetRepresentation rep = new FilterUserPresetRepresentation(
436 "" + mVersionsCounter, current, -1);
441 public void removeVersion(Action action) {
442 mVersions.remove(action.getRepresentation());
446 public void removeLook(Action action) {
447 FilterUserPresetRepresentation rep =
448 (FilterUserPresetRepresentation) action.getRepresentation();
452 mUserPresetsManager.delete(rep.getId());
453 updateUserPresetsFromManager();
456 private void fillEffects() {
457 FiltersManager filtersManager = FiltersManager.getManager();
458 ArrayList<FilterRepresentation> filtersRepresentations = filtersManager.getEffects();
459 if (mCategoryFiltersAdapter != null) {
460 mCategoryFiltersAdapter.clear();
462 mCategoryFiltersAdapter = new CategoryAdapter(this);
463 for (FilterRepresentation representation : filtersRepresentations) {
464 if (representation.getTextId() != 0) {
465 representation.setName(getString(representation.getTextId()));
467 mCategoryFiltersAdapter.add(new Action(this, representation));
471 private void fillTools() {
472 FiltersManager filtersManager = FiltersManager.getManager();
473 ArrayList<FilterRepresentation> filtersRepresentations = filtersManager.getTools();
474 if (mCategoryGeometryAdapter != null) {
475 mCategoryGeometryAdapter.clear();
477 mCategoryGeometryAdapter = new CategoryAdapter(this);
478 boolean found = false;
479 for (FilterRepresentation representation : filtersRepresentations) {
480 mCategoryGeometryAdapter.add(new Action(this, representation));
481 if (representation instanceof FilterDrawRepresentation) {
486 FilterRepresentation representation = new FilterDrawRepresentation();
487 Action action = new Action(this, representation);
488 action.setIsDoubleAction(true);
489 mCategoryGeometryAdapter.add(action);
493 private void processIntent() {
494 Intent intent = getIntent();
495 if (intent.getBooleanExtra(LAUNCH_FULLSCREEN, false)) {
496 getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
499 mAction = intent.getAction();
500 mSelectedImageUri = intent.getData();
501 Uri loadUri = mSelectedImageUri;
502 if (mOriginalImageUri != null) {
503 loadUri = mOriginalImageUri;
505 if (loadUri != null) {
506 startLoadBitmap(loadUri);
512 private void setupEditors() {
513 mEditorPlaceHolder.setContainer((FrameLayout) findViewById(R.id.editorContainer));
514 EditorManager.addEditors(mEditorPlaceHolder);
515 mEditorPlaceHolder.setOldViews(mImageViews);
518 private void fillEditors() {
519 mEditorPlaceHolder.addEditor(new EditorChanSat());
520 mEditorPlaceHolder.addEditor(new EditorGrad());
521 mEditorPlaceHolder.addEditor(new EditorDraw());
522 mEditorPlaceHolder.addEditor(new EditorColorBorder());
523 mEditorPlaceHolder.addEditor(new BasicEditor());
524 mEditorPlaceHolder.addEditor(new ImageOnlyEditor());
525 mEditorPlaceHolder.addEditor(new EditorTinyPlanet());
526 mEditorPlaceHolder.addEditor(new EditorRedEye());
527 mEditorPlaceHolder.addEditor(new EditorCrop());
528 mEditorPlaceHolder.addEditor(new EditorMirror());
529 mEditorPlaceHolder.addEditor(new EditorRotate());
530 mEditorPlaceHolder.addEditor(new EditorStraighten());
533 private void setDefaultValues() {
534 Resources res = getResources();
536 // TODO: get those values from XML.
537 FramedTextButton.setTextSize((int) getPixelsFromDip(14));
538 FramedTextButton.setTrianglePadding((int) getPixelsFromDip(4));
539 FramedTextButton.setTriangleSize((int) getPixelsFromDip(10));
541 Drawable curveHandle = res.getDrawable(R.drawable.camera_crop);
542 int curveHandleSize = (int) res.getDimension(R.dimen.crop_indicator_size);
543 Spline.setCurveHandle(curveHandle, curveHandleSize);
544 Spline.setCurveWidth((int) getPixelsFromDip(3));
546 mOriginalImageUri = null;
549 private void startLoadBitmap(Uri uri) {
550 final View imageShow = findViewById(R.id.imageShow);
551 imageShow.setVisibility(View.INVISIBLE);
552 startLoadingIndicator();
553 mShowingTinyPlanet = false;
554 mLoadBitmapTask = new LoadBitmapTask();
555 mLoadBitmapTask.execute(uri);
558 private void fillBorders() {
559 FiltersManager filtersManager = FiltersManager.getManager();
560 ArrayList<FilterRepresentation> borders = filtersManager.getBorders();
562 for (int i = 0; i < borders.size(); i++) {
563 FilterRepresentation filter = borders.get(i);
564 filter.setName(getString(R.string.borders));
566 filter.setName(getString(R.string.none));
570 if (mCategoryBordersAdapter != null) {
571 mCategoryBordersAdapter.clear();
573 mCategoryBordersAdapter = new CategoryAdapter(this);
574 for (FilterRepresentation representation : borders) {
575 if (representation.getTextId() != 0) {
576 representation.setName(getString(representation.getTextId()));
578 mCategoryBordersAdapter.add(new Action(this, representation, Action.FULL_VIEW));
582 public UserPresetsAdapter getUserPresetsAdapter() {
583 return mUserPresetsAdapter;
586 public CategoryAdapter getCategoryLooksAdapter() {
587 return mCategoryLooksAdapter;
590 public CategoryAdapter getCategoryBordersAdapter() {
591 return mCategoryBordersAdapter;
594 public CategoryAdapter getCategoryGeometryAdapter() {
595 return mCategoryGeometryAdapter;
598 public CategoryAdapter getCategoryFiltersAdapter() {
599 return mCategoryFiltersAdapter;
602 public CategoryAdapter getCategoryVersionsAdapter() {
603 return mCategoryVersionsAdapter;
606 public void removeFilterRepresentation(FilterRepresentation filterRepresentation) {
607 if (filterRepresentation == null) {
610 ImagePreset oldPreset = MasterImage.getImage().getPreset();
611 ImagePreset copy = new ImagePreset(oldPreset);
612 copy.removeFilter(filterRepresentation);
613 MasterImage.getImage().setPreset(copy, copy.getLastRepresentation(), true);
614 if (MasterImage.getImage().getCurrentFilterRepresentation() == filterRepresentation) {
615 FilterRepresentation lastRepresentation = copy.getLastRepresentation();
616 MasterImage.getImage().setCurrentFilterRepresentation(lastRepresentation);
620 public void useFilterRepresentation(FilterRepresentation filterRepresentation) {
621 if (filterRepresentation == null) {
624 if (!(filterRepresentation instanceof FilterRotateRepresentation)
625 && !(filterRepresentation instanceof FilterMirrorRepresentation)
626 && MasterImage.getImage().getCurrentFilterRepresentation() == filterRepresentation) {
629 if (filterRepresentation instanceof FilterUserPresetRepresentation
630 || filterRepresentation instanceof FilterRotateRepresentation
631 || filterRepresentation instanceof FilterMirrorRepresentation) {
632 MasterImage.getImage().onNewLook(filterRepresentation);
634 ImagePreset oldPreset = MasterImage.getImage().getPreset();
635 ImagePreset copy = new ImagePreset(oldPreset);
636 FilterRepresentation representation = copy.getRepresentation(filterRepresentation);
637 if (representation == null) {
638 filterRepresentation = filterRepresentation.copy();
639 copy.addFilter(filterRepresentation);
641 if (filterRepresentation.allowsSingleInstanceOnly()) {
642 // Don't just update the filter representation. Centralize the
643 // logic in the addFilter(), such that we can keep "None" as
645 if (!representation.equals(filterRepresentation)) {
646 // Only do this if the filter isn't the same
647 // (state panel clicks can lead us here)
648 copy.removeFilter(representation);
649 copy.addFilter(filterRepresentation);
653 MasterImage.getImage().setPreset(copy, filterRepresentation, true);
654 MasterImage.getImage().setCurrentFilterRepresentation(filterRepresentation);
657 public void showRepresentation(FilterRepresentation representation) {
658 if (representation == null) {
662 if (representation instanceof FilterRotateRepresentation) {
663 FilterRotateRepresentation r = (FilterRotateRepresentation) representation;
666 if (representation instanceof FilterMirrorRepresentation) {
667 FilterMirrorRepresentation r = (FilterMirrorRepresentation) representation;
670 if (representation.isBooleanFilter()) {
671 ImagePreset preset = MasterImage.getImage().getPreset();
672 if (preset.getRepresentation(representation) != null) {
674 ImagePreset copy = new ImagePreset(preset);
675 copy.removeFilter(representation);
676 FilterRepresentation filterRepresentation = representation.copy();
677 MasterImage.getImage().setPreset(copy, filterRepresentation, true);
678 MasterImage.getImage().setCurrentFilterRepresentation(null);
682 useFilterRepresentation(representation);
684 // show representation
685 if (mCurrentEditor != null) {
686 mCurrentEditor.detach();
688 mCurrentEditor = mEditorPlaceHolder.showEditor(representation.getEditorId());
689 loadEditorPanel(representation, mCurrentEditor);
692 public Editor getEditor(int editorID) {
693 return mEditorPlaceHolder.getEditor(editorID);
696 public void setCurrentPanel(int currentPanel) {
697 mCurrentPanel = currentPanel;
700 public int getCurrentPanel() {
701 return mCurrentPanel;
704 public void updateCategories() {
705 if (mMasterImage == null) {
708 ImagePreset preset = mMasterImage.getPreset();
709 mCategoryLooksAdapter.reflectImagePreset(preset);
710 mCategoryBordersAdapter.reflectImagePreset(preset);
713 public View getMainStatePanelContainer(int id) {
714 return findViewById(id);
717 public void onShowMenu(PopupMenu menu) {
719 menu.setOnDismissListener(this);
723 public void onDismiss(PopupMenu popupMenu){
724 if (mCurrentMenu == null) {
727 mCurrentMenu.setOnDismissListener(null);
732 public void onShow(DialogInterface dialog) {
733 mCurrentDialog = dialog;
737 public void onDismiss(DialogInterface dialogInterface) {
738 mCurrentDialog = null;
741 private class LoadHighresBitmapTask extends AsyncTask<Void, Void, Boolean> {
743 protected Boolean doInBackground(Void... params) {
744 MasterImage master = MasterImage.getImage();
745 Rect originalBounds = master.getOriginalBounds();
746 if (master.supportsHighRes()) {
747 int highresPreviewSize = master.getOriginalBitmapLarge().getWidth() * 2;
748 if (highresPreviewSize > originalBounds.width()) {
749 highresPreviewSize = originalBounds.width();
751 Rect bounds = new Rect();
752 Bitmap originalHires = ImageLoader.loadOrientedConstrainedBitmap(master.getUri(),
753 master.getActivity(), highresPreviewSize,
754 master.getOrientation(), bounds);
755 master.setOriginalBounds(bounds);
756 master.setOriginalBitmapHighres(originalHires);
757 mBoundService.setOriginalBitmapHighres(originalHires);
758 master.warnListeners();
764 protected void onPostExecute(Boolean result) {
765 Bitmap highresBitmap = MasterImage.getImage().getOriginalBitmapHighres();
766 if (highresBitmap != null) {
767 float highResPreviewScale = (float) highresBitmap.getWidth()
768 / (float) MasterImage.getImage().getOriginalBounds().width();
769 mBoundService.setHighresPreviewScaleFactor(highResPreviewScale);
771 MasterImage.getImage().warnListeners();
775 public boolean isLoadingVisible() {
776 return mLoadingVisible;
779 public void startLoadingIndicator() {
780 final View loading = findViewById(R.id.loading);
781 mLoadingVisible = true;
782 loading.setVisibility(View.VISIBLE);
785 public void stopLoadingIndicator() {
786 final View loading = findViewById(R.id.loading);
787 loading.setVisibility(View.GONE);
788 mLoadingVisible = false;
791 private class LoadBitmapTask extends AsyncTask<Uri, Boolean, Boolean> {
794 public LoadBitmapTask() {
795 mBitmapSize = getScreenImageSize();
799 protected Boolean doInBackground(Uri... params) {
800 if (!MasterImage.getImage().loadBitmap(params[0], mBitmapSize)) {
803 publishProgress(ImageLoader.queryLightCycle360(MasterImage.getImage().getActivity()));
808 protected void onProgressUpdate(Boolean... values) {
809 super.onProgressUpdate(values);
814 mShowingTinyPlanet = true;
819 protected void onPostExecute(Boolean result) {
820 MasterImage.setMaster(mMasterImage);
826 if (mOriginalImageUri != null
827 && !mOriginalImageUri.equals(mSelectedImageUri)) {
828 mOriginalImageUri = mSelectedImageUri;
829 mOriginalPreset = null;
830 Toast.makeText(FilterShowActivity.this,
831 R.string.cannot_edit_original, Toast.LENGTH_SHORT).show();
832 startLoadBitmap(mOriginalImageUri);
839 if (null == CachingPipeline.getRenderScriptContext()){
840 Log.v(LOGTAG,"RenderScript context destroyed during load");
843 final View imageShow = findViewById(R.id.imageShow);
844 imageShow.setVisibility(View.VISIBLE);
847 Bitmap largeBitmap = MasterImage.getImage().getOriginalBitmapLarge();
848 mBoundService.setOriginalBitmap(largeBitmap);
850 float previewScale = (float) largeBitmap.getWidth()
851 / (float) MasterImage.getImage().getOriginalBounds().width();
852 mBoundService.setPreviewScaleFactor(previewScale);
853 if (!mShowingTinyPlanet) {
854 mCategoryFiltersAdapter.removeTinyPlanet();
856 mCategoryLooksAdapter.imageLoaded();
857 mCategoryBordersAdapter.imageLoaded();
858 mCategoryGeometryAdapter.imageLoaded();
859 mCategoryFiltersAdapter.imageLoaded();
860 mLoadBitmapTask = null;
862 MasterImage.getImage().warnListeners();
865 if (mOriginalPreset != null) {
866 MasterImage.getImage().setLoadedPreset(mOriginalPreset);
867 MasterImage.getImage().setPreset(mOriginalPreset,
868 mOriginalPreset.getLastRepresentation(), true);
869 mOriginalPreset = null;
874 MasterImage.getImage().resetGeometryImages(true);
876 if (mAction == TINY_PLANET_ACTION) {
877 showRepresentation(mCategoryFiltersAdapter.getTinyPlanet());
879 LoadHighresBitmapTask highresLoad = new LoadHighresBitmapTask();
880 highresLoad.execute();
881 MasterImage.getImage().warnListeners();
882 super.onPostExecute(result);
887 private void clearGalleryBitmapPool() {
888 (new AsyncTask<Void, Void, Void>() {
890 protected Void doInBackground(Void... params) {
891 // Free memory held in Gallery's Bitmap pool. May be O(n) for n bitmaps.
892 GalleryBitmapPool.getInstance().clear();
899 protected void onDestroy() {
900 if (mLoadBitmapTask != null) {
901 mLoadBitmapTask.cancel(false);
903 mUserPresetsManager.close();
908 // TODO: find a more robust way of handling image size selection
909 // for high screen densities.
910 private int getScreenImageSize() {
911 DisplayMetrics outMetrics = new DisplayMetrics();
912 getWindowManager().getDefaultDisplay().getMetrics(outMetrics);
913 return Math.max(outMetrics.heightPixels, outMetrics.widthPixels);
916 private void showSavingProgress(String albumName) {
917 ProgressDialog progress;
918 if (mSavingProgressDialog != null) {
919 progress = mSavingProgressDialog.get();
920 if (progress != null) {
925 // TODO: Allow cancellation of the saving process
927 if (albumName == null) {
928 progressText = getString(R.string.saving_image);
930 progressText = getString(R.string.filtershow_saving_image, albumName);
932 progress = ProgressDialog.show(this, "", progressText, true, false);
933 mSavingProgressDialog = new WeakReference<ProgressDialog>(progress);
936 private void hideSavingProgress() {
937 if (mSavingProgressDialog != null) {
938 ProgressDialog progress = mSavingProgressDialog.get();
939 if (progress != null)
944 public void completeSaveImage(Uri saveUri) {
945 if (mSharingImage && mSharedOutputFile != null) {
946 // Image saved, we unblock the content provider
947 Uri uri = Uri.withAppendedPath(SharedImageProvider.CONTENT_URI,
948 Uri.encode(mSharedOutputFile.getAbsolutePath()));
949 ContentValues values = new ContentValues();
950 values.put(SharedImageProvider.PREPARE, false);
951 getContentResolver().insert(uri, values);
953 setResult(RESULT_OK, new Intent().setData(saveUri));
954 hideSavingProgress();
959 public boolean onShareTargetSelected(ShareActionProvider arg0, Intent arg1) {
960 // First, let's tell the SharedImageProvider that it will need to wait
962 Uri uri = Uri.withAppendedPath(SharedImageProvider.CONTENT_URI,
963 Uri.encode(mSharedOutputFile.getAbsolutePath()));
964 ContentValues values = new ContentValues();
965 values.put(SharedImageProvider.PREPARE, true);
966 getContentResolver().insert(uri, values);
967 mSharingImage = true;
969 // Process and save the image in the background.
970 showSavingProgress(null);
971 mImageShow.saveImage(this, mSharedOutputFile);
975 private Intent getDefaultShareIntent() {
976 Intent intent = new Intent(Intent.ACTION_SEND);
977 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
978 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
979 intent.setType(SharedImageProvider.MIME_TYPE);
980 mSharedOutputFile = SaveImage.getNewFile(this, MasterImage.getImage().getUri());
981 Uri uri = Uri.withAppendedPath(SharedImageProvider.CONTENT_URI,
982 Uri.encode(mSharedOutputFile.getAbsolutePath()));
983 intent.putExtra(Intent.EXTRA_STREAM, uri);
988 public boolean onCreateOptionsMenu(Menu menu) {
989 getMenuInflater().inflate(R.menu.filtershow_activity_menu, menu);
990 MenuItem showState = menu.findItem(R.id.showImageStateButton);
991 if (mShowingImageStatePanel) {
992 showState.setTitle(R.string.hide_imagestate_panel);
994 showState.setTitle(R.string.show_imagestate_panel);
996 mShareActionProvider = (ShareActionProvider) menu.findItem(R.id.menu_share)
997 .getActionProvider();
998 mShareActionProvider.setShareIntent(getDefaultShareIntent());
999 mShareActionProvider.setOnShareTargetSelectedListener(this);
1005 private void setupMenu(){
1006 if (mMenu == null || mMasterImage == null) {
1009 MenuItem undoItem = mMenu.findItem(R.id.undoButton);
1010 MenuItem redoItem = mMenu.findItem(R.id.redoButton);
1011 MenuItem resetItem = mMenu.findItem(R.id.resetHistoryButton);
1012 MenuItem printItem = mMenu.findItem(R.id.printButton);
1013 if (!PrintHelper.systemSupportsPrint()) {
1014 printItem.setVisible(false);
1016 mMasterImage.getHistory().setMenuItems(undoItem, redoItem, resetItem);
1020 public void onPause() {
1022 if (mShareActionProvider != null) {
1023 mShareActionProvider.setOnShareTargetSelectedListener(null);
1028 public void onResume() {
1030 if (mShareActionProvider != null) {
1031 mShareActionProvider.setOnShareTargetSelectedListener(this);
1036 public boolean onOptionsItemSelected(MenuItem item) {
1037 switch (item.getItemId()) {
1038 case R.id.undoButton: {
1039 HistoryManager adapter = mMasterImage.getHistory();
1040 int position = adapter.undo();
1041 mMasterImage.onHistoryItemClick(position);
1046 case R.id.redoButton: {
1047 HistoryManager adapter = mMasterImage.getHistory();
1048 int position = adapter.redo();
1049 mMasterImage.onHistoryItemClick(position);
1053 case R.id.resetHistoryButton: {
1057 case R.id.showImageStateButton: {
1058 toggleImageStatePanel();
1061 case R.id.exportFlattenButton: {
1062 showExportOptionsDialog();
1065 case android.R.id.home: {
1069 case R.id.manageUserPresets: {
1070 manageUserPresets();
1073 case R.id.showInfoPanel: {
1074 toggleInformationPanel();
1077 case R.id.printButton: {
1085 public void print() {
1086 Bitmap bitmap = MasterImage.getImage().getHighresImage();
1087 PrintHelper printer = new PrintHelper(this);
1088 printer.printBitmap("ImagePrint", bitmap);
1091 public void addNewPreset() {
1092 DialogFragment dialog = new PresetManagementDialog();
1093 dialog.show(getSupportFragmentManager(), "NoticeDialogFragment");
1096 private void manageUserPresets() {
1097 DialogFragment dialog = new PresetManagementDialog();
1098 dialog.show(getSupportFragmentManager(), "NoticeDialogFragment");
1101 private void showExportOptionsDialog() {
1102 DialogFragment dialog = new ExportDialog();
1103 dialog.show(getSupportFragmentManager(), "ExportDialogFragment");
1106 public void updateUserPresetsFromAdapter(UserPresetsAdapter adapter) {
1107 ArrayList<FilterUserPresetRepresentation> representations =
1108 adapter.getDeletedRepresentations();
1109 for (FilterUserPresetRepresentation representation : representations) {
1110 deletePreset(representation.getId());
1112 ArrayList<FilterUserPresetRepresentation> changedRepresentations =
1113 adapter.getChangedRepresentations();
1114 for (FilterUserPresetRepresentation representation : changedRepresentations) {
1115 updatePreset(representation);
1117 adapter.clearDeletedRepresentations();
1118 adapter.clearChangedRepresentations();
1122 public void loadUserPresets() {
1123 mUserPresetsManager.load();
1124 updateUserPresetsFromManager();
1127 public void updateUserPresetsFromManager() {
1128 ArrayList<FilterUserPresetRepresentation> presets = mUserPresetsManager.getRepresentations();
1129 if (presets == null) {
1132 if (mCategoryLooksAdapter != null) {
1135 if (presets.size() > 0) {
1136 mCategoryLooksAdapter.add(new Action(this, Action.SPACER));
1138 mUserPresetsAdapter.clear();
1139 for (int i = 0; i < presets.size(); i++) {
1140 FilterUserPresetRepresentation representation = presets.get(i);
1141 mCategoryLooksAdapter.add(
1142 new Action(this, representation, Action.FULL_VIEW, true));
1143 mUserPresetsAdapter.add(new Action(this, representation, Action.FULL_VIEW));
1145 if (presets.size() > 0) {
1146 mCategoryLooksAdapter.add(new Action(this, Action.ADD_ACTION));
1148 mCategoryLooksAdapter.notifyDataSetChanged();
1149 mCategoryLooksAdapter.notifyDataSetInvalidated();
1152 public void saveCurrentImagePreset(String name) {
1153 mUserPresetsManager.save(MasterImage.getImage().getPreset(), name);
1156 private void deletePreset(int id) {
1157 mUserPresetsManager.delete(id);
1160 private void updatePreset(FilterUserPresetRepresentation representation) {
1161 mUserPresetsManager.update(representation);
1164 public void enableSave(boolean enable) {
1165 if (mSaveButton != null) {
1166 mSaveButton.setEnabled(enable);
1170 private void fillLooks() {
1171 FiltersManager filtersManager = FiltersManager.getManager();
1172 ArrayList<FilterRepresentation> filtersRepresentations = filtersManager.getLooks();
1174 if (mCategoryLooksAdapter != null) {
1175 mCategoryLooksAdapter.clear();
1177 mCategoryLooksAdapter = new CategoryAdapter(this);
1178 int verticalItemHeight = (int) getResources().getDimension(R.dimen.action_item_height);
1179 mCategoryLooksAdapter.setItemHeight(verticalItemHeight);
1180 for (FilterRepresentation representation : filtersRepresentations) {
1181 mCategoryLooksAdapter.add(new Action(this, representation, Action.FULL_VIEW));
1183 if (mUserPresetsManager.getRepresentations() == null
1184 || mUserPresetsManager.getRepresentations().size() == 0) {
1185 mCategoryLooksAdapter.add(new Action(this, Action.ADD_ACTION));
1188 Fragment panel = getSupportFragmentManager().findFragmentByTag(MainPanel.FRAGMENT_TAG);
1189 if (panel != null) {
1190 if (panel instanceof MainPanel) {
1191 MainPanel mainPanel = (MainPanel) panel;
1192 mainPanel.loadCategoryLookPanel(true);
1197 public void setDefaultPreset() {
1198 // Default preset (original)
1199 ImagePreset preset = new ImagePreset(); // empty
1200 mMasterImage.setPreset(preset, preset.getLastRepresentation(), true);
1203 // //////////////////////////////////////////////////////////////////////////////
1204 // Some utility functions
1205 // TODO: finish the cleanup.
1207 public void invalidateViews() {
1208 for (ImageShow views : mImageViews) {
1209 views.updateImage();
1213 public void hideImageViews() {
1214 for (View view : mImageViews) {
1215 view.setVisibility(View.GONE);
1217 mEditorPlaceHolder.hide();
1220 // //////////////////////////////////////////////////////////////////////////////
1221 // imageState panel...
1223 public void toggleImageStatePanel() {
1224 invalidateOptionsMenu();
1225 mShowingImageStatePanel = !mShowingImageStatePanel;
1226 Fragment panel = getSupportFragmentManager().findFragmentByTag(MainPanel.FRAGMENT_TAG);
1227 if (panel != null) {
1228 if (panel instanceof EditorPanel) {
1229 EditorPanel editorPanel = (EditorPanel) panel;
1230 editorPanel.showImageStatePanel(mShowingImageStatePanel);
1231 } else if (panel instanceof MainPanel) {
1232 MainPanel mainPanel = (MainPanel) panel;
1233 mainPanel.showImageStatePanel(mShowingImageStatePanel);
1238 public void toggleVersionsPanel() {
1239 mShowingVersionsPanel = !mShowingVersionsPanel;
1240 Fragment panel = getSupportFragmentManager().findFragmentByTag(MainPanel.FRAGMENT_TAG);
1241 if (panel != null && panel instanceof MainPanel) {
1242 MainPanel mainPanel = (MainPanel) panel;
1243 mainPanel.loadCategoryVersionsPanel();
1248 public void onConfigurationChanged(Configuration newConfig)
1250 super.onConfigurationChanged(newConfig);
1253 if (mMasterImage == null) {
1260 if (mCurrentMenu != null) {
1261 mCurrentMenu.dismiss();
1262 mCurrentMenu = null;
1264 if (mCurrentDialog != null) {
1265 mCurrentDialog.dismiss();
1266 mCurrentDialog = null;
1268 // mLoadBitmapTask==null implies you have looked at the intent
1269 if (!mShowingTinyPlanet && (mLoadBitmapTask == null)) {
1270 mCategoryFiltersAdapter.removeTinyPlanet();
1272 stopLoadingIndicator();
1275 public void setupMasterImage() {
1277 HistoryManager historyManager = new HistoryManager();
1278 StateAdapter imageStateAdapter = new StateAdapter(this, 0);
1279 MasterImage.reset();
1280 mMasterImage = MasterImage.getImage();
1281 mMasterImage.setHistoryManager(historyManager);
1282 mMasterImage.setStateAdapter(imageStateAdapter);
1283 mMasterImage.setActivity(this);
1285 if (Runtime.getRuntime().maxMemory() > LIMIT_SUPPORTS_HIGHRES) {
1286 mMasterImage.setSupportsHighRes(true);
1288 mMasterImage.setSupportsHighRes(false);
1292 void resetHistory() {
1293 HistoryManager adapter = mMasterImage.getHistory();
1295 HistoryItem historyItem = adapter.getItem(0);
1296 ImagePreset original = null;
1297 if (RESET_TO_LOADED) {
1298 original = new ImagePreset(historyItem.getImagePreset());
1300 original = new ImagePreset();
1302 FilterRepresentation rep = null;
1303 if (historyItem != null) {
1304 rep = historyItem.getFilterRepresentation();
1306 mMasterImage.setPreset(original, rep, true);
1311 public void showDefaultImageView() {
1312 mEditorPlaceHolder.hide();
1313 mImageShow.setVisibility(View.VISIBLE);
1314 MasterImage.getImage().setCurrentFilter(null);
1315 MasterImage.getImage().setCurrentFilterRepresentation(null);
1318 public void backToMain() {
1319 Fragment currentPanel = getSupportFragmentManager().findFragmentByTag(MainPanel.FRAGMENT_TAG);
1320 if (currentPanel instanceof MainPanel) {
1324 showDefaultImageView();
1328 public void onBackPressed() {
1329 Fragment currentPanel = getSupportFragmentManager().findFragmentByTag(MainPanel.FRAGMENT_TAG);
1330 if (currentPanel instanceof MainPanel) {
1331 if (!mImageShow.hasModifications()) {
1334 AlertDialog.Builder builder = new AlertDialog.Builder(this);
1335 builder.setMessage(R.string.unsaved).setTitle(R.string.save_before_exit);
1336 builder.setPositiveButton(R.string.save_and_exit, new DialogInterface.OnClickListener() {
1338 public void onClick(DialogInterface dialog, int id) {
1342 builder.setNegativeButton(R.string.exit, new DialogInterface.OnClickListener() {
1344 public void onClick(DialogInterface dialog, int id) {
1355 public void cannotLoadImage() {
1356 Toast.makeText(this, R.string.cannot_load_image, Toast.LENGTH_SHORT).show();
1360 // //////////////////////////////////////////////////////////////////////////////
1362 public float getPixelsFromDip(float value) {
1363 Resources r = getResources();
1364 return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, value,
1365 r.getDisplayMetrics());
1369 public void onItemClick(AdapterView<?> parent, View view, int position,
1371 mMasterImage.onHistoryItemClick(position);
1375 public void pickImage() {
1376 Intent intent = new Intent();
1377 intent.setType("image/*");
1378 intent.setAction(Intent.ACTION_GET_CONTENT);
1379 startActivityForResult(Intent.createChooser(intent, getString(R.string.select_image)),
1384 public void onActivityResult(int requestCode, int resultCode, Intent data) {
1385 if (resultCode == RESULT_OK) {
1386 if (requestCode == SELECT_PICTURE) {
1387 Uri selectedImageUri = data.getData();
1388 startLoadBitmap(selectedImageUri);
1394 public void saveImage() {
1395 if (mImageShow.hasModifications()) {
1396 // Get the name of the album, to which the image will be saved
1397 File saveDir = SaveImage.getFinalSaveDirectory(this, mSelectedImageUri);
1398 int bucketId = GalleryUtils.getBucketId(saveDir.getPath());
1399 String albumName = LocalAlbum.getLocalizedName(getResources(), bucketId, null);
1400 showSavingProgress(albumName);
1401 mImageShow.saveImage(this, null);
1408 public void done() {
1409 hideSavingProgress();
1410 if (mLoadBitmapTask != null) {
1411 mLoadBitmapTask.cancel(false);
1416 private void extractXMPData() {
1417 XMresults res = XmpPresets.extractXMPData(
1418 getBaseContext(), mMasterImage, getIntent().getData());
1422 mOriginalImageUri = res.originalimage;
1423 mOriginalPreset = res.preset;
1426 public Uri getSelectedImageUri() {
1427 return mSelectedImageUri;
1430 public void setHandlesSwipeForView(View view, float startX, float startY) {
1432 mHandlingSwipeButton = true;
1434 mHandlingSwipeButton = false;
1436 mHandledSwipeView = view;
1437 int[] location = new int[2];
1438 view.getLocationInWindow(location);
1439 mSwipeStartX = location[0] + startX;
1440 mSwipeStartY = location[1] + startY;
1443 public boolean dispatchTouchEvent (MotionEvent ev) {
1444 if (mHandlingSwipeButton) {
1445 int direction = CategoryView.HORIZONTAL;
1446 if (mHandledSwipeView instanceof CategoryView) {
1447 direction = ((CategoryView) mHandledSwipeView).getOrientation();
1449 if (ev.getActionMasked() == MotionEvent.ACTION_MOVE) {
1450 float delta = ev.getY() - mSwipeStartY;
1451 float distance = mHandledSwipeView.getHeight();
1452 if (direction == CategoryView.VERTICAL) {
1453 delta = ev.getX() - mSwipeStartX;
1454 mHandledSwipeView.setTranslationX(delta);
1455 distance = mHandledSwipeView.getWidth();
1457 mHandledSwipeView.setTranslationY(delta);
1459 delta = Math.abs(delta);
1460 float transparency = Math.min(1, delta / distance);
1461 mHandledSwipeView.setAlpha(1.f - transparency);
1462 mHandledSwipeViewLastDelta = delta;
1464 if (ev.getActionMasked() == MotionEvent.ACTION_CANCEL
1465 || ev.getActionMasked() == MotionEvent.ACTION_UP) {
1466 mHandledSwipeView.setTranslationX(0);
1467 mHandledSwipeView.setTranslationY(0);
1468 mHandledSwipeView.setAlpha(1.f);
1469 mHandlingSwipeButton = false;
1470 float distance = mHandledSwipeView.getHeight();
1471 if (direction == CategoryView.VERTICAL) {
1472 distance = mHandledSwipeView.getWidth();
1474 if (mHandledSwipeViewLastDelta > distance) {
1475 ((SwipableView) mHandledSwipeView).delete();
1480 return super.dispatchTouchEvent(ev);
1483 public Point mHintTouchPoint = new Point();
1485 public Point hintTouchPoint(View view) {
1486 int location[] = new int[2];
1487 view.getLocationOnScreen(location);
1488 int x = mHintTouchPoint.x - location[0];
1489 int y = mHintTouchPoint.y - location[1];
1490 return new Point(x, y);
1493 public void startTouchAnimation(View target, float x, float y) {
1494 final CategorySelected hint =
1495 (CategorySelected) findViewById(R.id.categorySelectedIndicator);
1496 int location[] = new int[2];
1497 target.getLocationOnScreen(location);
1498 mHintTouchPoint.x = (int) (location[0] + x);
1499 mHintTouchPoint.y = (int) (location[1] + y);
1500 int locationHint[] = new int[2];
1501 ((View)hint.getParent()).getLocationOnScreen(locationHint);
1502 int dx = (int) (x - (hint.getWidth())/2);
1503 int dy = (int) (y - (hint.getHeight())/2);
1504 hint.setTranslationX(location[0] - locationHint[0] + dx);
1505 hint.setTranslationY(location[1] - locationHint[1] + dy);
1506 hint.setVisibility(View.VISIBLE);
1507 hint.animate().scaleX(2).scaleY(2).alpha(0).withEndAction(new Runnable() {
1510 hint.setVisibility(View.INVISIBLE);