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