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