FilterShowActivity.java revision d33fe6fd37d8c506ab0e47139ef0f77746a275b8
1/* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.gallery3d.filtershow; 18 19import android.app.ActionBar; 20import android.app.AlertDialog; 21import android.app.ProgressDialog; 22import android.content.ComponentName; 23import android.content.ContentValues; 24import android.content.Context; 25import android.content.DialogInterface; 26import android.content.Intent; 27import android.content.ServiceConnection; 28import android.content.pm.ActivityInfo; 29import android.content.res.Configuration; 30import android.content.res.Resources; 31import android.graphics.Bitmap; 32import android.graphics.Rect; 33import android.graphics.drawable.Drawable; 34import android.net.Uri; 35import android.os.AsyncTask; 36import android.os.Bundle; 37import android.os.Handler; 38import android.os.IBinder; 39import android.support.v4.app.DialogFragment; 40import android.support.v4.app.Fragment; 41import android.support.v4.app.FragmentActivity; 42import android.support.v4.app.FragmentTransaction; 43import android.util.DisplayMetrics; 44import android.util.Log; 45import android.util.TypedValue; 46import android.view.Menu; 47import android.view.MenuItem; 48import android.view.MotionEvent; 49import android.view.View; 50import android.view.View.OnClickListener; 51import android.view.ViewPropertyAnimator; 52import android.view.WindowManager; 53import android.widget.AdapterView; 54import android.widget.AdapterView.OnItemClickListener; 55import android.widget.FrameLayout; 56import android.widget.ShareActionProvider; 57import android.widget.ShareActionProvider.OnShareTargetSelectedListener; 58import android.widget.Toast; 59 60import com.android.gallery3d.R; 61import com.android.gallery3d.app.PhotoPage; 62import com.android.gallery3d.data.LocalAlbum; 63import com.android.gallery3d.filtershow.cache.ImageLoader; 64import com.android.gallery3d.filtershow.category.Action; 65import com.android.gallery3d.filtershow.category.CategoryAdapter; 66import com.android.gallery3d.filtershow.category.CategoryView; 67import com.android.gallery3d.filtershow.category.MainPanel; 68import com.android.gallery3d.filtershow.category.SwipableView; 69import com.android.gallery3d.filtershow.data.UserPresetsManager; 70import com.android.gallery3d.filtershow.editors.BasicEditor; 71import com.android.gallery3d.filtershow.editors.Editor; 72import com.android.gallery3d.filtershow.editors.EditorChanSat; 73import com.android.gallery3d.filtershow.editors.EditorCrop; 74import com.android.gallery3d.filtershow.editors.EditorDraw; 75import com.android.gallery3d.filtershow.editors.EditorGrad; 76import com.android.gallery3d.filtershow.editors.EditorManager; 77import com.android.gallery3d.filtershow.editors.EditorMirror; 78import com.android.gallery3d.filtershow.editors.EditorPanel; 79import com.android.gallery3d.filtershow.editors.EditorRedEye; 80import com.android.gallery3d.filtershow.editors.EditorRotate; 81import com.android.gallery3d.filtershow.editors.EditorStraighten; 82import com.android.gallery3d.filtershow.editors.EditorTinyPlanet; 83import com.android.gallery3d.filtershow.editors.ImageOnlyEditor; 84import com.android.gallery3d.filtershow.filters.FilterMirrorRepresentation; 85import com.android.gallery3d.filtershow.filters.FilterRepresentation; 86import com.android.gallery3d.filtershow.filters.FilterRotateRepresentation; 87import com.android.gallery3d.filtershow.filters.FilterUserPresetRepresentation; 88import com.android.gallery3d.filtershow.filters.FiltersManager; 89import com.android.gallery3d.filtershow.filters.ImageFilter; 90import com.android.gallery3d.filtershow.history.HistoryItem; 91import com.android.gallery3d.filtershow.history.HistoryManager; 92import com.android.gallery3d.filtershow.imageshow.ImageShow; 93import com.android.gallery3d.filtershow.imageshow.MasterImage; 94import com.android.gallery3d.filtershow.imageshow.Spline; 95import com.android.gallery3d.filtershow.info.InfoPanel; 96import com.android.gallery3d.filtershow.pipeline.CachingPipeline; 97import com.android.gallery3d.filtershow.pipeline.ImagePreset; 98import com.android.gallery3d.filtershow.pipeline.ProcessingService; 99import com.android.gallery3d.filtershow.presets.PresetManagementDialog; 100import com.android.gallery3d.filtershow.presets.UserPresetsAdapter; 101import com.android.gallery3d.filtershow.provider.SharedImageProvider; 102import com.android.gallery3d.filtershow.state.StateAdapter; 103import com.android.gallery3d.filtershow.tools.SaveImage; 104import com.android.gallery3d.filtershow.tools.XmpPresets; 105import com.android.gallery3d.filtershow.tools.XmpPresets.XMresults; 106import com.android.gallery3d.filtershow.ui.ExportDialog; 107import com.android.gallery3d.filtershow.ui.FramedTextButton; 108import com.android.gallery3d.util.GalleryUtils; 109import com.android.gallery3d.util.UsageStatistics; 110import com.android.photos.data.GalleryBitmapPool; 111 112import java.io.File; 113import java.lang.ref.WeakReference; 114import java.util.ArrayList; 115import java.util.Vector; 116 117public class FilterShowActivity extends FragmentActivity implements OnItemClickListener, 118 OnShareTargetSelectedListener { 119 120 private String mAction = ""; 121 MasterImage mMasterImage = null; 122 123 private static final long LIMIT_SUPPORTS_HIGHRES = 134217728; // 128Mb 124 125 public static final String TINY_PLANET_ACTION = "com.android.camera.action.TINY_PLANET"; 126 public static final String LAUNCH_FULLSCREEN = "launch-fullscreen"; 127 private ImageShow mImageShow = null; 128 129 private View mSaveButton = null; 130 131 private EditorPlaceHolder mEditorPlaceHolder = new EditorPlaceHolder(this); 132 133 private static final int SELECT_PICTURE = 1; 134 private static final String LOGTAG = "FilterShowActivity"; 135 136 private boolean mShowingTinyPlanet = false; 137 private boolean mShowingImageStatePanel = false; 138 private boolean mShowingVersionsPanel = false; 139 private boolean mShowingInformationPanel = false; 140 141 private final Vector<ImageShow> mImageViews = new Vector<ImageShow>(); 142 143 private ShareActionProvider mShareActionProvider; 144 private File mSharedOutputFile = null; 145 146 private boolean mSharingImage = false; 147 148 private WeakReference<ProgressDialog> mSavingProgressDialog; 149 150 private LoadBitmapTask mLoadBitmapTask; 151 152 private Uri mOriginalImageUri = null; 153 private ImagePreset mOriginalPreset = null; 154 155 private Uri mSelectedImageUri = null; 156 157 private UserPresetsManager mUserPresetsManager = null; 158 private UserPresetsAdapter mUserPresetsAdapter = null; 159 private CategoryAdapter mCategoryLooksAdapter = null; 160 private CategoryAdapter mCategoryBordersAdapter = null; 161 private CategoryAdapter mCategoryGeometryAdapter = null; 162 private CategoryAdapter mCategoryFiltersAdapter = null; 163 private CategoryAdapter mCategoryVersionsAdapter = null; 164 private int mCurrentPanel = MainPanel.LOOKS; 165 private Vector<FilterUserPresetRepresentation> mVersions = 166 new Vector<FilterUserPresetRepresentation>(); 167 private int mVersionsCounter = 0; 168 169 private boolean mHandlingSwipeButton = false; 170 private View mHandledSwipeView = null; 171 private float mHandledSwipeViewLastDelta = 0; 172 private float mSwipeStartX = 0; 173 private float mSwipeStartY = 0; 174 175 private ProcessingService mBoundService; 176 private boolean mIsBound = false; 177 178 public ProcessingService getProcessingService() { 179 return mBoundService; 180 } 181 182 public boolean isSimpleEditAction() { 183 return !PhotoPage.ACTION_NEXTGEN_EDIT.equalsIgnoreCase(mAction); 184 } 185 186 private ServiceConnection mConnection = new ServiceConnection() { 187 @Override 188 public void onServiceConnected(ComponentName className, IBinder service) { 189 /* 190 * This is called when the connection with the service has been 191 * established, giving us the service object we can use to 192 * interact with the service. Because we have bound to a explicit 193 * service that we know is running in our own process, we can 194 * cast its IBinder to a concrete class and directly access it. 195 */ 196 mBoundService = ((ProcessingService.LocalBinder)service).getService(); 197 mBoundService.setFiltershowActivity(FilterShowActivity.this); 198 mBoundService.onStart(); 199 } 200 201 @Override 202 public void onServiceDisconnected(ComponentName className) { 203 /* 204 * This is called when the connection with the service has been 205 * unexpectedly disconnected -- that is, its process crashed. 206 * Because it is running in our same process, we should never 207 * see this happen. 208 */ 209 mBoundService = null; 210 } 211 }; 212 213 void doBindService() { 214 /* 215 * Establish a connection with the service. We use an explicit 216 * class name because we want a specific service implementation that 217 * we know will be running in our own process (and thus won't be 218 * supporting component replacement by other applications). 219 */ 220 bindService(new Intent(FilterShowActivity.this, ProcessingService.class), 221 mConnection, Context.BIND_AUTO_CREATE); 222 mIsBound = true; 223 } 224 225 void doUnbindService() { 226 if (mIsBound) { 227 // Detach our existing connection. 228 unbindService(mConnection); 229 mIsBound = false; 230 } 231 } 232 233 private void setupPipeline() { 234 doBindService(); 235 ImageFilter.setActivityForMemoryToasts(this); 236 mUserPresetsManager = new UserPresetsManager(this); 237 mUserPresetsAdapter = new UserPresetsAdapter(this); 238 } 239 240 public void updateUIAfterServiceStarted() { 241 fillCategories(); 242 loadMainPanel(); 243 setDefaultPreset(); 244 extractXMPData(); 245 processIntent(); 246 } 247 248 @Override 249 public void onCreate(Bundle savedInstanceState) { 250 super.onCreate(savedInstanceState); 251 252 boolean onlyUsePortrait = getResources().getBoolean(R.bool.only_use_portrait); 253 if (onlyUsePortrait) { 254 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); 255 } 256 MasterImage.setMaster(mMasterImage); 257 258 clearGalleryBitmapPool(); 259 setupPipeline(); 260 261 setupMasterImage(); 262 setDefaultValues(); 263 fillEditors(); 264 265 loadXML(); 266 UsageStatistics.onContentViewChanged(UsageStatistics.COMPONENT_EDITOR, "Main"); 267 UsageStatistics.onEvent(UsageStatistics.COMPONENT_EDITOR, 268 UsageStatistics.CATEGORY_LIFECYCLE, UsageStatistics.LIFECYCLE_START); 269 } 270 271 public boolean isShowingImageStatePanel() { 272 return mShowingImageStatePanel; 273 } 274 275 public void loadMainPanel() { 276 if (findViewById(R.id.main_panel_container) == null) { 277 return; 278 } 279 MainPanel panel = new MainPanel(); 280 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); 281 transaction.replace(R.id.main_panel_container, panel, MainPanel.FRAGMENT_TAG); 282 transaction.commit(); 283 } 284 285 public void loadEditorPanel(FilterRepresentation representation, 286 final Editor currentEditor) { 287 if (representation.getEditorId() == ImageOnlyEditor.ID) { 288 currentEditor.reflectCurrentFilter(); 289 return; 290 } 291 final int currentId = currentEditor.getID(); 292 Runnable showEditor = new Runnable() { 293 @Override 294 public void run() { 295 EditorPanel panel = new EditorPanel(); 296 panel.setEditor(currentId); 297 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); 298 transaction.remove(getSupportFragmentManager().findFragmentByTag(MainPanel.FRAGMENT_TAG)); 299 transaction.replace(R.id.main_panel_container, panel, MainPanel.FRAGMENT_TAG); 300 transaction.commit(); 301 } 302 }; 303 Fragment main = getSupportFragmentManager().findFragmentByTag(MainPanel.FRAGMENT_TAG); 304 boolean doAnimation = false; 305 if (mShowingImageStatePanel 306 && getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { 307 doAnimation = true; 308 } 309 if (doAnimation && main != null && main instanceof MainPanel) { 310 MainPanel mainPanel = (MainPanel) main; 311 View container = mainPanel.getView().findViewById(R.id.category_panel_container); 312 View bottom = mainPanel.getView().findViewById(R.id.bottom_panel); 313 int panelHeight = container.getHeight() + bottom.getHeight(); 314 ViewPropertyAnimator anim = mainPanel.getView().animate(); 315 anim.translationY(panelHeight).start(); 316 final Handler handler = new Handler(); 317 handler.postDelayed(showEditor, anim.getDuration()); 318 } else { 319 showEditor.run(); 320 } 321 } 322 323 public void hideInformationPanel() { 324 FrameLayout infoLayout = (FrameLayout) findViewById(R.id.central_panel_container); 325 infoLayout.setVisibility(View.GONE); 326 Fragment fragment = getSupportFragmentManager().findFragmentByTag(InfoPanel.FRAGMENT_TAG); 327 if (fragment != null) { 328 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); 329 transaction.remove(fragment); 330 transaction.commit(); 331 } 332 mShowingInformationPanel = false; 333 } 334 335 public void toggleInformationPanel() { 336 mShowingInformationPanel = !mShowingInformationPanel; 337 if (!mShowingInformationPanel) { 338 hideInformationPanel(); 339 showDefaultImageView(); 340 return; 341 } 342 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); 343 transaction.setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left); 344 FrameLayout infoLayout = (FrameLayout) findViewById(R.id.central_panel_container); 345 infoLayout.setVisibility(View.VISIBLE); 346 mEditorPlaceHolder.hide(); 347 mImageShow.setVisibility(View.GONE); 348 349 InfoPanel panel = new InfoPanel(); 350 transaction.replace(R.id.central_panel_container, panel, InfoPanel.FRAGMENT_TAG); 351 transaction.commit(); 352 } 353 354 private void loadXML() { 355 setContentView(R.layout.filtershow_activity); 356 357 ActionBar actionBar = getActionBar(); 358 actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM); 359 actionBar.setCustomView(R.layout.filtershow_actionbar); 360 361 mSaveButton = actionBar.getCustomView(); 362 mSaveButton.setOnClickListener(new OnClickListener() { 363 @Override 364 public void onClick(View view) { 365 saveImage(); 366 } 367 }); 368 369 mImageShow = (ImageShow) findViewById(R.id.imageShow); 370 mImageViews.add(mImageShow); 371 372 setupEditors(); 373 374 mEditorPlaceHolder.hide(); 375 mImageShow.bindAsImageLoadListener(); 376 377 setupStatePanel(); 378 } 379 380 public void fillCategories() { 381 fillLooks(); 382 loadUserPresets(); 383 fillBorders(); 384 fillTools(); 385 fillEffects(); 386 fillVersions(); 387 } 388 389 public void setupStatePanel() { 390 MasterImage.getImage().setHistoryManager(mMasterImage.getHistory()); 391 } 392 393 private void fillVersions() { 394 mCategoryVersionsAdapter = new CategoryAdapter(this); 395 mCategoryVersionsAdapter.setShowAddButton(true); 396 } 397 398 public void updateVersions() { 399 mCategoryVersionsAdapter.clear(); 400 FilterUserPresetRepresentation originalRep = new FilterUserPresetRepresentation( 401 getString(R.string.filtershow_version_original), new ImagePreset(), -1); 402 mCategoryVersionsAdapter.add( 403 new Action(this, originalRep, Action.FULL_VIEW)); 404 ImagePreset current = new ImagePreset(MasterImage.getImage().getPreset()); 405 FilterUserPresetRepresentation currentRep = new FilterUserPresetRepresentation( 406 getString(R.string.filtershow_version_current), current, -1); 407 mCategoryVersionsAdapter.add( 408 new Action(this, currentRep, Action.FULL_VIEW)); 409 if (mVersions.size() > 0) { 410 mCategoryVersionsAdapter.add(new Action(this, Action.SPACER)); 411 } 412 for (FilterUserPresetRepresentation rep : mVersions) { 413 mCategoryVersionsAdapter.add( 414 new Action(this, rep, Action.FULL_VIEW, true)); 415 } 416 mCategoryVersionsAdapter.notifyDataSetInvalidated(); 417 } 418 419 public void addCurrentVersion() { 420 ImagePreset current = new ImagePreset(MasterImage.getImage().getPreset()); 421 mVersionsCounter++; 422 FilterUserPresetRepresentation rep = new FilterUserPresetRepresentation( 423 "" + mVersionsCounter, current, -1); 424 mVersions.add(rep); 425 updateVersions(); 426 } 427 428 public void removeVersion(Action action) { 429 mVersions.remove(action.getRepresentation()); 430 updateVersions(); 431 } 432 433 public void removeLook(Action action) { 434 FilterUserPresetRepresentation rep = 435 (FilterUserPresetRepresentation) action.getRepresentation(); 436 if (rep == null) { 437 return; 438 } 439 mUserPresetsManager.delete(rep.getId()); 440 updateUserPresetsFromManager(); 441 } 442 443 private void fillEffects() { 444 FiltersManager filtersManager = FiltersManager.getManager(); 445 ArrayList<FilterRepresentation> filtersRepresentations = filtersManager.getEffects(); 446 mCategoryFiltersAdapter = new CategoryAdapter(this); 447 for (FilterRepresentation representation : filtersRepresentations) { 448 if (representation.getTextId() != 0) { 449 representation.setName(getString(representation.getTextId())); 450 } 451 mCategoryFiltersAdapter.add(new Action(this, representation)); 452 } 453 } 454 455 private void fillTools() { 456 FiltersManager filtersManager = FiltersManager.getManager(); 457 ArrayList<FilterRepresentation> filtersRepresentations = filtersManager.getTools(); 458 mCategoryGeometryAdapter = new CategoryAdapter(this); 459 for (FilterRepresentation representation : filtersRepresentations) { 460 mCategoryGeometryAdapter.add(new Action(this, representation)); 461 } 462 } 463 464 private void processIntent() { 465 Intent intent = getIntent(); 466 if (intent.getBooleanExtra(LAUNCH_FULLSCREEN, false)) { 467 getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); 468 } 469 470 mAction = intent.getAction(); 471 mSelectedImageUri = intent.getData(); 472 Uri loadUri = mSelectedImageUri; 473 if (mOriginalImageUri != null) { 474 loadUri = mOriginalImageUri; 475 } 476 if (loadUri != null) { 477 startLoadBitmap(loadUri); 478 } else { 479 pickImage(); 480 } 481 } 482 483 private void setupEditors() { 484 mEditorPlaceHolder.setContainer((FrameLayout) findViewById(R.id.editorContainer)); 485 EditorManager.addEditors(mEditorPlaceHolder); 486 mEditorPlaceHolder.setOldViews(mImageViews); 487 } 488 489 private void fillEditors() { 490 mEditorPlaceHolder.addEditor(new EditorChanSat()); 491 mEditorPlaceHolder.addEditor(new EditorGrad()); 492 mEditorPlaceHolder.addEditor(new EditorDraw()); 493 mEditorPlaceHolder.addEditor(new BasicEditor()); 494 mEditorPlaceHolder.addEditor(new ImageOnlyEditor()); 495 mEditorPlaceHolder.addEditor(new EditorTinyPlanet()); 496 mEditorPlaceHolder.addEditor(new EditorRedEye()); 497 mEditorPlaceHolder.addEditor(new EditorCrop()); 498 mEditorPlaceHolder.addEditor(new EditorMirror()); 499 mEditorPlaceHolder.addEditor(new EditorRotate()); 500 mEditorPlaceHolder.addEditor(new EditorStraighten()); 501 } 502 503 private void setDefaultValues() { 504 Resources res = getResources(); 505 506 // TODO: get those values from XML. 507 FramedTextButton.setTextSize((int) getPixelsFromDip(14)); 508 FramedTextButton.setTrianglePadding((int) getPixelsFromDip(4)); 509 FramedTextButton.setTriangleSize((int) getPixelsFromDip(10)); 510 511 Drawable curveHandle = res.getDrawable(R.drawable.camera_crop); 512 int curveHandleSize = (int) res.getDimension(R.dimen.crop_indicator_size); 513 Spline.setCurveHandle(curveHandle, curveHandleSize); 514 Spline.setCurveWidth((int) getPixelsFromDip(3)); 515 } 516 517 private void startLoadBitmap(Uri uri) { 518 final View loading = findViewById(R.id.loading); 519 final View imageShow = findViewById(R.id.imageShow); 520 imageShow.setVisibility(View.INVISIBLE); 521 loading.setVisibility(View.VISIBLE); 522 mShowingTinyPlanet = false; 523 mLoadBitmapTask = new LoadBitmapTask(); 524 mLoadBitmapTask.execute(uri); 525 } 526 527 private void fillBorders() { 528 FiltersManager filtersManager = FiltersManager.getManager(); 529 ArrayList<FilterRepresentation> borders = filtersManager.getBorders(); 530 531 for (int i = 0; i < borders.size(); i++) { 532 FilterRepresentation filter = borders.get(i); 533 filter.setName(getString(R.string.borders)); 534 if (i == 0) { 535 filter.setName(getString(R.string.none)); 536 } 537 } 538 539 mCategoryBordersAdapter = new CategoryAdapter(this); 540 for (FilterRepresentation representation : borders) { 541 if (representation.getTextId() != 0) { 542 representation.setName(getString(representation.getTextId())); 543 } 544 mCategoryBordersAdapter.add(new Action(this, representation, Action.FULL_VIEW)); 545 } 546 } 547 548 public UserPresetsAdapter getUserPresetsAdapter() { 549 return mUserPresetsAdapter; 550 } 551 552 public CategoryAdapter getCategoryLooksAdapter() { 553 return mCategoryLooksAdapter; 554 } 555 556 public CategoryAdapter getCategoryBordersAdapter() { 557 return mCategoryBordersAdapter; 558 } 559 560 public CategoryAdapter getCategoryGeometryAdapter() { 561 return mCategoryGeometryAdapter; 562 } 563 564 public CategoryAdapter getCategoryFiltersAdapter() { 565 return mCategoryFiltersAdapter; 566 } 567 568 public CategoryAdapter getCategoryVersionsAdapter() { 569 return mCategoryVersionsAdapter; 570 } 571 572 public void removeFilterRepresentation(FilterRepresentation filterRepresentation) { 573 if (filterRepresentation == null) { 574 return; 575 } 576 ImagePreset oldPreset = MasterImage.getImage().getPreset(); 577 ImagePreset copy = new ImagePreset(oldPreset); 578 copy.removeFilter(filterRepresentation); 579 MasterImage.getImage().setPreset(copy, copy.getLastRepresentation(), true); 580 if (MasterImage.getImage().getCurrentFilterRepresentation() == filterRepresentation) { 581 FilterRepresentation lastRepresentation = copy.getLastRepresentation(); 582 MasterImage.getImage().setCurrentFilterRepresentation(lastRepresentation); 583 } 584 } 585 586 public void useFilterRepresentation(FilterRepresentation filterRepresentation) { 587 if (filterRepresentation == null) { 588 return; 589 } 590 if (!(filterRepresentation instanceof FilterRotateRepresentation) 591 && !(filterRepresentation instanceof FilterMirrorRepresentation) 592 && MasterImage.getImage().getCurrentFilterRepresentation() == filterRepresentation) { 593 return; 594 } 595 ImagePreset oldPreset = MasterImage.getImage().getPreset(); 596 ImagePreset copy = new ImagePreset(oldPreset); 597 FilterRepresentation representation = copy.getRepresentation(filterRepresentation); 598 if (representation == null) { 599 filterRepresentation = filterRepresentation.copy(); 600 copy.addFilter(filterRepresentation); 601 } else { 602 if (filterRepresentation.allowsSingleInstanceOnly()) { 603 // Don't just update the filter representation. Centralize the 604 // logic in the addFilter(), such that we can keep "None" as 605 // null. 606 if (!representation.equals(filterRepresentation)) { 607 // Only do this if the filter isn't the same 608 // (state panel clicks can lead us here) 609 copy.removeFilter(representation); 610 copy.addFilter(filterRepresentation); 611 } 612 } 613 } 614 MasterImage.getImage().setPreset(copy, filterRepresentation, true); 615 MasterImage.getImage().setCurrentFilterRepresentation(filterRepresentation); 616 } 617 618 public void showRepresentation(FilterRepresentation representation) { 619 if (representation == null) { 620 return; 621 } 622 623 if (representation instanceof FilterRotateRepresentation) { 624 FilterRotateRepresentation r = (FilterRotateRepresentation) representation; 625 r.rotateCW(); 626 } 627 if (representation instanceof FilterMirrorRepresentation) { 628 FilterMirrorRepresentation r = (FilterMirrorRepresentation) representation; 629 r.cycle(); 630 } 631 useFilterRepresentation(representation); 632 633 // show representation 634 Editor mCurrentEditor = mEditorPlaceHolder.showEditor(representation.getEditorId()); 635 loadEditorPanel(representation, mCurrentEditor); 636 hideInformationPanel(); 637 } 638 639 public Editor getEditor(int editorID) { 640 return mEditorPlaceHolder.getEditor(editorID); 641 } 642 643 public void setCurrentPanel(int currentPanel) { 644 mCurrentPanel = currentPanel; 645 } 646 647 public int getCurrentPanel() { 648 return mCurrentPanel; 649 } 650 651 public void updateCategories() { 652 ImagePreset preset = mMasterImage.getPreset(); 653 mCategoryLooksAdapter.reflectImagePreset(preset); 654 mCategoryBordersAdapter.reflectImagePreset(preset); 655 } 656 657 public View getMainStatePanelContainer(int id) { 658 return findViewById(id); 659 } 660 661 private class LoadHighresBitmapTask extends AsyncTask<Void, Void, Boolean> { 662 @Override 663 protected Boolean doInBackground(Void... params) { 664 MasterImage master = MasterImage.getImage(); 665 Rect originalBounds = master.getOriginalBounds(); 666 if (master.supportsHighRes()) { 667 int highresPreviewSize = master.getOriginalBitmapLarge().getWidth() * 2; 668 if (highresPreviewSize > originalBounds.width()) { 669 highresPreviewSize = originalBounds.width(); 670 } 671 Rect bounds = new Rect(); 672 Bitmap originalHires = ImageLoader.loadOrientedConstrainedBitmap(master.getUri(), 673 master.getActivity(), highresPreviewSize, 674 master.getOrientation(), bounds); 675 master.setOriginalBounds(bounds); 676 master.setOriginalBitmapHighres(originalHires); 677 mBoundService.setOriginalBitmapHighres(originalHires); 678 master.warnListeners(); 679 } 680 return true; 681 } 682 683 @Override 684 protected void onPostExecute(Boolean result) { 685 Bitmap highresBitmap = MasterImage.getImage().getOriginalBitmapHighres(); 686 if (highresBitmap != null) { 687 float highResPreviewScale = (float) highresBitmap.getWidth() 688 / (float) MasterImage.getImage().getOriginalBounds().width(); 689 mBoundService.setHighresPreviewScaleFactor(highResPreviewScale); 690 } 691 } 692 } 693 694 private class LoadBitmapTask extends AsyncTask<Uri, Boolean, Boolean> { 695 int mBitmapSize; 696 697 public LoadBitmapTask() { 698 mBitmapSize = getScreenImageSize(); 699 } 700 701 @Override 702 protected Boolean doInBackground(Uri... params) { 703 if (!MasterImage.getImage().loadBitmap(params[0], mBitmapSize)) { 704 return false; 705 } 706 publishProgress(ImageLoader.queryLightCycle360(MasterImage.getImage().getActivity())); 707 return true; 708 } 709 710 @Override 711 protected void onProgressUpdate(Boolean... values) { 712 super.onProgressUpdate(values); 713 if (isCancelled()) { 714 return; 715 } 716 if (values[0]) { 717 mShowingTinyPlanet = true; 718 } 719 } 720 721 @Override 722 protected void onPostExecute(Boolean result) { 723 MasterImage.setMaster(mMasterImage); 724 if (isCancelled()) { 725 return; 726 } 727 728 if (!result) { 729 cannotLoadImage(); 730 // TODO: We should figure out the best way preventing this from 731 // happening, e.g: early checking. 732 return; 733 } 734 735 if (null == CachingPipeline.getRenderScriptContext()){ 736 Log.v(LOGTAG,"RenderScript context destroyed during load"); 737 return; 738 } 739 final View loading = findViewById(R.id.loading); 740 loading.setVisibility(View.GONE); 741 final View imageShow = findViewById(R.id.imageShow); 742 imageShow.setVisibility(View.VISIBLE); 743 744 Bitmap largeBitmap = MasterImage.getImage().getOriginalBitmapLarge(); 745 mBoundService.setOriginalBitmap(largeBitmap); 746 MasterImage.getImage().resetGeometryImages(true); 747 748 float previewScale = (float) largeBitmap.getWidth() 749 / (float) MasterImage.getImage().getOriginalBounds().width(); 750 mBoundService.setPreviewScaleFactor(previewScale); 751 if (!mShowingTinyPlanet) { 752 mCategoryFiltersAdapter.removeTinyPlanet(); 753 } 754 mCategoryLooksAdapter.imageLoaded(); 755 mCategoryBordersAdapter.imageLoaded(); 756 mCategoryGeometryAdapter.imageLoaded(); 757 mCategoryFiltersAdapter.imageLoaded(); 758 mLoadBitmapTask = null; 759 760 if (mOriginalPreset != null) { 761 MasterImage.getImage().setLoadedPreset(mOriginalPreset); 762 MasterImage.getImage().setPreset(mOriginalPreset, 763 mOriginalPreset.getLastRepresentation(), true); 764 mOriginalPreset = null; 765 } 766 767 if (mAction == TINY_PLANET_ACTION) { 768 showRepresentation(mCategoryFiltersAdapter.getTinyPlanet()); 769 } 770 LoadHighresBitmapTask highresLoad = new LoadHighresBitmapTask(); 771 highresLoad.execute(); 772 super.onPostExecute(result); 773 } 774 775 } 776 777 private void clearGalleryBitmapPool() { 778 (new AsyncTask<Void, Void, Void>() { 779 @Override 780 protected Void doInBackground(Void... params) { 781 // Free memory held in Gallery's Bitmap pool. May be O(n) for n bitmaps. 782 GalleryBitmapPool.getInstance().clear(); 783 return null; 784 } 785 }).execute(); 786 } 787 788 @Override 789 protected void onDestroy() { 790 if (mLoadBitmapTask != null) { 791 mLoadBitmapTask.cancel(false); 792 } 793 mUserPresetsManager.close(); 794 doUnbindService(); 795 super.onDestroy(); 796 } 797 798 // TODO: find a more robust way of handling image size selection 799 // for high screen densities. 800 private int getScreenImageSize() { 801 DisplayMetrics outMetrics = new DisplayMetrics(); 802 getWindowManager().getDefaultDisplay().getMetrics(outMetrics); 803 return Math.max(outMetrics.heightPixels, outMetrics.widthPixels); 804 } 805 806 private void showSavingProgress(String albumName) { 807 ProgressDialog progress; 808 if (mSavingProgressDialog != null) { 809 progress = mSavingProgressDialog.get(); 810 if (progress != null) { 811 progress.show(); 812 return; 813 } 814 } 815 // TODO: Allow cancellation of the saving process 816 String progressText; 817 if (albumName == null) { 818 progressText = getString(R.string.saving_image); 819 } else { 820 progressText = getString(R.string.filtershow_saving_image, albumName); 821 } 822 progress = ProgressDialog.show(this, "", progressText, true, false); 823 mSavingProgressDialog = new WeakReference<ProgressDialog>(progress); 824 } 825 826 private void hideSavingProgress() { 827 if (mSavingProgressDialog != null) { 828 ProgressDialog progress = mSavingProgressDialog.get(); 829 if (progress != null) 830 progress.dismiss(); 831 } 832 } 833 834 public void completeSaveImage(Uri saveUri) { 835 if (mSharingImage && mSharedOutputFile != null) { 836 // Image saved, we unblock the content provider 837 Uri uri = Uri.withAppendedPath(SharedImageProvider.CONTENT_URI, 838 Uri.encode(mSharedOutputFile.getAbsolutePath())); 839 ContentValues values = new ContentValues(); 840 values.put(SharedImageProvider.PREPARE, false); 841 getContentResolver().insert(uri, values); 842 } 843 setResult(RESULT_OK, new Intent().setData(saveUri)); 844 hideSavingProgress(); 845 finish(); 846 } 847 848 @Override 849 public boolean onShareTargetSelected(ShareActionProvider arg0, Intent arg1) { 850 // First, let's tell the SharedImageProvider that it will need to wait 851 // for the image 852 Uri uri = Uri.withAppendedPath(SharedImageProvider.CONTENT_URI, 853 Uri.encode(mSharedOutputFile.getAbsolutePath())); 854 ContentValues values = new ContentValues(); 855 values.put(SharedImageProvider.PREPARE, true); 856 getContentResolver().insert(uri, values); 857 mSharingImage = true; 858 859 // Process and save the image in the background. 860 showSavingProgress(null); 861 mImageShow.saveImage(this, mSharedOutputFile); 862 return true; 863 } 864 865 private Intent getDefaultShareIntent() { 866 Intent intent = new Intent(Intent.ACTION_SEND); 867 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); 868 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); 869 intent.setType(SharedImageProvider.MIME_TYPE); 870 mSharedOutputFile = SaveImage.getNewFile(this, MasterImage.getImage().getUri()); 871 Uri uri = Uri.withAppendedPath(SharedImageProvider.CONTENT_URI, 872 Uri.encode(mSharedOutputFile.getAbsolutePath())); 873 intent.putExtra(Intent.EXTRA_STREAM, uri); 874 return intent; 875 } 876 877 @Override 878 public boolean onCreateOptionsMenu(Menu menu) { 879 getMenuInflater().inflate(R.menu.filtershow_activity_menu, menu); 880 MenuItem showState = menu.findItem(R.id.showImageStateButton); 881 if (mShowingImageStatePanel) { 882 showState.setTitle(R.string.hide_imagestate_panel); 883 } else { 884 showState.setTitle(R.string.show_imagestate_panel); 885 } 886 mShareActionProvider = (ShareActionProvider) menu.findItem(R.id.menu_share) 887 .getActionProvider(); 888 mShareActionProvider.setShareIntent(getDefaultShareIntent()); 889 mShareActionProvider.setOnShareTargetSelectedListener(this); 890 891 MenuItem undoItem = menu.findItem(R.id.undoButton); 892 MenuItem redoItem = menu.findItem(R.id.redoButton); 893 MenuItem resetItem = menu.findItem(R.id.resetHistoryButton); 894 mMasterImage.getHistory().setMenuItems(undoItem, redoItem, resetItem); 895 return true; 896 } 897 898 @Override 899 public void onPause() { 900 super.onPause(); 901 if (mShareActionProvider != null) { 902 mShareActionProvider.setOnShareTargetSelectedListener(null); 903 } 904 } 905 906 @Override 907 public void onResume() { 908 super.onResume(); 909 if (mShareActionProvider != null) { 910 mShareActionProvider.setOnShareTargetSelectedListener(this); 911 } 912 } 913 914 @Override 915 public boolean onOptionsItemSelected(MenuItem item) { 916 switch (item.getItemId()) { 917 case R.id.undoButton: { 918 HistoryManager adapter = mMasterImage.getHistory(); 919 int position = adapter.undo(); 920 mMasterImage.onHistoryItemClick(position); 921 backToMain(); 922 invalidateViews(); 923 UsageStatistics.onEvent(UsageStatistics.COMPONENT_EDITOR, 924 UsageStatistics.CATEGORY_BUTTON_PRESS, "Undo"); 925 return true; 926 } 927 case R.id.redoButton: { 928 HistoryManager adapter = mMasterImage.getHistory(); 929 int position = adapter.redo(); 930 mMasterImage.onHistoryItemClick(position); 931 invalidateViews(); 932 UsageStatistics.onEvent(UsageStatistics.COMPONENT_EDITOR, 933 UsageStatistics.CATEGORY_BUTTON_PRESS, "Redo"); 934 return true; 935 } 936 case R.id.resetHistoryButton: { 937 resetHistory(); 938 UsageStatistics.onEvent(UsageStatistics.COMPONENT_EDITOR, 939 UsageStatistics.CATEGORY_BUTTON_PRESS, "ResetHistory"); 940 return true; 941 } 942 case R.id.showImageStateButton: { 943 toggleImageStatePanel(); 944 UsageStatistics.onEvent(UsageStatistics.COMPONENT_EDITOR, 945 UsageStatistics.CATEGORY_BUTTON_PRESS, 946 mShowingImageStatePanel ? "ShowPanel" : "HidePanel"); 947 return true; 948 } 949 case R.id.exportFlattenButton: { 950 showExportOptionsDialog(); 951 return true; 952 } 953 case android.R.id.home: { 954 saveImage(); 955 return true; 956 } 957 case R.id.manageUserPresets: { 958 manageUserPresets(); 959 return true; 960 } 961 case R.id.showInfoPanel: { 962 toggleInformationPanel(); 963 return true; 964 } 965 } 966 return false; 967 } 968 969 public void addNewPreset() { 970 DialogFragment dialog = new PresetManagementDialog(); 971 dialog.show(getSupportFragmentManager(), "NoticeDialogFragment"); 972 } 973 974 private void manageUserPresets() { 975 DialogFragment dialog = new PresetManagementDialog(); 976 dialog.show(getSupportFragmentManager(), "NoticeDialogFragment"); 977 } 978 979 private void showExportOptionsDialog() { 980 DialogFragment dialog = new ExportDialog(); 981 dialog.show(getSupportFragmentManager(), "ExportDialogFragment"); 982 } 983 984 public void updateUserPresetsFromAdapter(UserPresetsAdapter adapter) { 985 ArrayList<FilterUserPresetRepresentation> representations = 986 adapter.getDeletedRepresentations(); 987 for (FilterUserPresetRepresentation representation : representations) { 988 deletePreset(representation.getId()); 989 } 990 ArrayList<FilterUserPresetRepresentation> changedRepresentations = 991 adapter.getChangedRepresentations(); 992 for (FilterUserPresetRepresentation representation : changedRepresentations) { 993 updatePreset(representation); 994 } 995 adapter.clearDeletedRepresentations(); 996 adapter.clearChangedRepresentations(); 997 loadUserPresets(); 998 } 999 1000 public void loadUserPresets() { 1001 mUserPresetsManager.load(); 1002 updateUserPresetsFromManager(); 1003 } 1004 1005 public void updateUserPresetsFromManager() { 1006 ArrayList<FilterUserPresetRepresentation> presets = mUserPresetsManager.getRepresentations(); 1007 if (presets == null) { 1008 return; 1009 } 1010 if (mCategoryLooksAdapter != null) { 1011 fillLooks(); 1012 } 1013 if (presets.size() > 0) { 1014 mCategoryLooksAdapter.add(new Action(this, Action.SPACER)); 1015 } 1016 mUserPresetsAdapter.clear(); 1017 for (int i = 0; i < presets.size(); i++) { 1018 FilterUserPresetRepresentation representation = presets.get(i); 1019 mCategoryLooksAdapter.add( 1020 new Action(this, representation, Action.FULL_VIEW, true)); 1021 mUserPresetsAdapter.add(new Action(this, representation, Action.FULL_VIEW)); 1022 } 1023 if (presets.size() > 0) { 1024 mCategoryLooksAdapter.add(new Action(this, Action.ADD_ACTION)); 1025 } 1026 mCategoryLooksAdapter.notifyDataSetChanged(); 1027 mCategoryLooksAdapter.notifyDataSetInvalidated(); 1028 } 1029 1030 public void saveCurrentImagePreset(String name) { 1031 mUserPresetsManager.save(MasterImage.getImage().getPreset(), name); 1032 } 1033 1034 private void deletePreset(int id) { 1035 mUserPresetsManager.delete(id); 1036 } 1037 1038 private void updatePreset(FilterUserPresetRepresentation representation) { 1039 mUserPresetsManager.update(representation); 1040 } 1041 1042 public void enableSave(boolean enable) { 1043 if (mSaveButton != null) { 1044 mSaveButton.setEnabled(enable); 1045 } 1046 } 1047 1048 private void fillLooks() { 1049 FiltersManager filtersManager = FiltersManager.getManager(); 1050 ArrayList<FilterRepresentation> filtersRepresentations = filtersManager.getLooks(); 1051 1052 mCategoryLooksAdapter = new CategoryAdapter(this); 1053 int verticalItemHeight = (int) getResources().getDimension(R.dimen.action_item_height); 1054 mCategoryLooksAdapter.setItemHeight(verticalItemHeight); 1055 for (FilterRepresentation representation : filtersRepresentations) { 1056 mCategoryLooksAdapter.add(new Action(this, representation, Action.FULL_VIEW)); 1057 } 1058 if (mUserPresetsManager.getRepresentations() == null 1059 || mUserPresetsManager.getRepresentations().size() == 0) { 1060 mCategoryLooksAdapter.add(new Action(this, Action.ADD_ACTION)); 1061 } 1062 1063 Fragment panel = getSupportFragmentManager().findFragmentByTag(MainPanel.FRAGMENT_TAG); 1064 if (panel != null) { 1065 if (panel instanceof MainPanel) { 1066 MainPanel mainPanel = (MainPanel) panel; 1067 mainPanel.loadCategoryLookPanel(true); 1068 } 1069 } 1070 } 1071 1072 public void setDefaultPreset() { 1073 // Default preset (original) 1074 ImagePreset preset = new ImagePreset(); // empty 1075 mMasterImage.setPreset(preset, preset.getLastRepresentation(), true); 1076 } 1077 1078 // ////////////////////////////////////////////////////////////////////////////// 1079 // Some utility functions 1080 // TODO: finish the cleanup. 1081 1082 public void invalidateViews() { 1083 for (ImageShow views : mImageViews) { 1084 views.updateImage(); 1085 } 1086 } 1087 1088 public void hideImageViews() { 1089 for (View view : mImageViews) { 1090 view.setVisibility(View.GONE); 1091 } 1092 mEditorPlaceHolder.hide(); 1093 } 1094 1095 // ////////////////////////////////////////////////////////////////////////////// 1096 // imageState panel... 1097 1098 public void toggleImageStatePanel() { 1099 invalidateOptionsMenu(); 1100 mShowingImageStatePanel = !mShowingImageStatePanel; 1101 Fragment panel = getSupportFragmentManager().findFragmentByTag(MainPanel.FRAGMENT_TAG); 1102 if (panel != null) { 1103 if (panel instanceof EditorPanel) { 1104 EditorPanel editorPanel = (EditorPanel) panel; 1105 editorPanel.showImageStatePanel(mShowingImageStatePanel); 1106 } else if (panel instanceof MainPanel) { 1107 MainPanel mainPanel = (MainPanel) panel; 1108 mainPanel.showImageStatePanel(mShowingImageStatePanel); 1109 } 1110 } 1111 } 1112 1113 public void toggleVersionsPanel() { 1114 mShowingVersionsPanel = !mShowingVersionsPanel; 1115 Fragment panel = getSupportFragmentManager().findFragmentByTag(MainPanel.FRAGMENT_TAG); 1116 if (panel != null && panel instanceof MainPanel) { 1117 MainPanel mainPanel = (MainPanel) panel; 1118 mainPanel.loadCategoryVersionsPanel(); 1119 } 1120 } 1121 1122 @Override 1123 public void onConfigurationChanged(Configuration newConfig) 1124 { 1125 super.onConfigurationChanged(newConfig); 1126 setDefaultValues(); 1127 loadXML(); 1128 fillCategories(); 1129 loadMainPanel(); 1130 1131 // mLoadBitmapTask==null implies you have looked at the intent 1132 if (!mShowingTinyPlanet && (mLoadBitmapTask == null)) { 1133 mCategoryFiltersAdapter.removeTinyPlanet(); 1134 } 1135 final View loading = findViewById(R.id.loading); 1136 loading.setVisibility(View.GONE); 1137 } 1138 1139 public void setupMasterImage() { 1140 1141 HistoryManager historyManager = new HistoryManager(); 1142 StateAdapter imageStateAdapter = new StateAdapter(this, 0); 1143 MasterImage.reset(); 1144 mMasterImage = MasterImage.getImage(); 1145 mMasterImage.setHistoryManager(historyManager); 1146 mMasterImage.setStateAdapter(imageStateAdapter); 1147 mMasterImage.setActivity(this); 1148 1149 if (Runtime.getRuntime().maxMemory() > LIMIT_SUPPORTS_HIGHRES) { 1150 mMasterImage.setSupportsHighRes(true); 1151 } else { 1152 mMasterImage.setSupportsHighRes(false); 1153 } 1154 } 1155 1156 void resetHistory() { 1157 HistoryManager adapter = mMasterImage.getHistory(); 1158 adapter.reset(); 1159 HistoryItem historyItem = adapter.getItem(0); 1160 ImagePreset original = new ImagePreset(historyItem.getImagePreset()); 1161 mMasterImage.setPreset(original, historyItem.getFilterRepresentation(), true); 1162 invalidateViews(); 1163 backToMain(); 1164 } 1165 1166 public void showDefaultImageView() { 1167 hideInformationPanel(); 1168 mEditorPlaceHolder.hide(); 1169 mImageShow.setVisibility(View.VISIBLE); 1170 MasterImage.getImage().setCurrentFilter(null); 1171 MasterImage.getImage().setCurrentFilterRepresentation(null); 1172 } 1173 1174 public void backToMain() { 1175 Fragment currentPanel = getSupportFragmentManager().findFragmentByTag(MainPanel.FRAGMENT_TAG); 1176 if (currentPanel instanceof MainPanel) { 1177 return; 1178 } 1179 loadMainPanel(); 1180 showDefaultImageView(); 1181 } 1182 1183 @Override 1184 public void onBackPressed() { 1185 Fragment currentPanel = getSupportFragmentManager().findFragmentByTag(MainPanel.FRAGMENT_TAG); 1186 if (currentPanel instanceof MainPanel) { 1187 if (!mImageShow.hasModifications()) { 1188 done(); 1189 } else { 1190 AlertDialog.Builder builder = new AlertDialog.Builder(this); 1191 builder.setMessage(R.string.unsaved).setTitle(R.string.save_before_exit); 1192 builder.setPositiveButton(R.string.save_and_exit, new DialogInterface.OnClickListener() { 1193 @Override 1194 public void onClick(DialogInterface dialog, int id) { 1195 saveImage(); 1196 } 1197 }); 1198 builder.setNegativeButton(R.string.exit, new DialogInterface.OnClickListener() { 1199 @Override 1200 public void onClick(DialogInterface dialog, int id) { 1201 done(); 1202 } 1203 }); 1204 builder.show(); 1205 } 1206 } else { 1207 backToMain(); 1208 } 1209 } 1210 1211 public void cannotLoadImage() { 1212 Toast.makeText(this, R.string.cannot_load_image, Toast.LENGTH_SHORT).show(); 1213 finish(); 1214 } 1215 1216 // ////////////////////////////////////////////////////////////////////////////// 1217 1218 public float getPixelsFromDip(float value) { 1219 Resources r = getResources(); 1220 return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, value, 1221 r.getDisplayMetrics()); 1222 } 1223 1224 @Override 1225 public void onItemClick(AdapterView<?> parent, View view, int position, 1226 long id) { 1227 mMasterImage.onHistoryItemClick(position); 1228 invalidateViews(); 1229 } 1230 1231 public void pickImage() { 1232 Intent intent = new Intent(); 1233 intent.setType("image/*"); 1234 intent.setAction(Intent.ACTION_GET_CONTENT); 1235 startActivityForResult(Intent.createChooser(intent, getString(R.string.select_image)), 1236 SELECT_PICTURE); 1237 } 1238 1239 @Override 1240 public void onActivityResult(int requestCode, int resultCode, Intent data) { 1241 if (resultCode == RESULT_OK) { 1242 if (requestCode == SELECT_PICTURE) { 1243 Uri selectedImageUri = data.getData(); 1244 startLoadBitmap(selectedImageUri); 1245 } 1246 } 1247 } 1248 1249 1250 public void saveImage() { 1251 if (mImageShow.hasModifications()) { 1252 // Get the name of the album, to which the image will be saved 1253 File saveDir = SaveImage.getFinalSaveDirectory(this, mSelectedImageUri); 1254 int bucketId = GalleryUtils.getBucketId(saveDir.getPath()); 1255 String albumName = LocalAlbum.getLocalizedName(getResources(), bucketId, null); 1256 showSavingProgress(albumName); 1257 mImageShow.saveImage(this, null); 1258 } else { 1259 done(); 1260 } 1261 } 1262 1263 1264 public void done() { 1265 hideSavingProgress(); 1266 if (mLoadBitmapTask != null) { 1267 mLoadBitmapTask.cancel(false); 1268 } 1269 finish(); 1270 } 1271 1272 private void extractXMPData() { 1273 XMresults res = XmpPresets.extractXMPData( 1274 getBaseContext(), mMasterImage, getIntent().getData()); 1275 if (res == null) 1276 return; 1277 1278 mOriginalImageUri = res.originalimage; 1279 mOriginalPreset = res.preset; 1280 } 1281 1282 public Uri getSelectedImageUri() { 1283 return mSelectedImageUri; 1284 } 1285 1286 public void setHandlesSwipeForView(View view, float startX, float startY) { 1287 if (view != null) { 1288 mHandlingSwipeButton = true; 1289 } else { 1290 mHandlingSwipeButton = false; 1291 } 1292 mHandledSwipeView = view; 1293 int[] location = new int[2]; 1294 view.getLocationInWindow(location); 1295 mSwipeStartX = location[0] + startX; 1296 mSwipeStartY = location[1] + startY; 1297 } 1298 1299 public boolean dispatchTouchEvent (MotionEvent ev) { 1300 if (mHandlingSwipeButton) { 1301 int direction = CategoryView.HORIZONTAL; 1302 if (mHandledSwipeView instanceof CategoryView) { 1303 direction = ((CategoryView) mHandledSwipeView).getOrientation(); 1304 } 1305 if (ev.getActionMasked() == MotionEvent.ACTION_MOVE) { 1306 float delta = ev.getY() - mSwipeStartY; 1307 float distance = mHandledSwipeView.getHeight(); 1308 if (direction == CategoryView.VERTICAL) { 1309 delta = ev.getX() - mSwipeStartX; 1310 mHandledSwipeView.setTranslationX(delta); 1311 distance = mHandledSwipeView.getWidth(); 1312 } else { 1313 mHandledSwipeView.setTranslationY(delta); 1314 } 1315 delta = Math.abs(delta); 1316 float transparency = Math.min(1, delta / distance); 1317 mHandledSwipeView.setAlpha(1.f - transparency); 1318 mHandledSwipeViewLastDelta = delta; 1319 } 1320 if (ev.getActionMasked() == MotionEvent.ACTION_CANCEL 1321 || ev.getActionMasked() == MotionEvent.ACTION_UP) { 1322 mHandledSwipeView.setTranslationX(0); 1323 mHandledSwipeView.setTranslationY(0); 1324 mHandledSwipeView.setAlpha(1.f); 1325 mHandlingSwipeButton = false; 1326 float distance = mHandledSwipeView.getHeight(); 1327 if (direction == CategoryView.VERTICAL) { 1328 distance = mHandledSwipeView.getWidth(); 1329 } 1330 if (mHandledSwipeViewLastDelta > distance) { 1331 ((SwipableView) mHandledSwipeView).delete(); 1332 } 1333 } 1334 return true; 1335 } 1336 return super.dispatchTouchEvent(ev); 1337 } 1338} 1339