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