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