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