FilterShowActivity.java revision 33de212ec780eaf2bc8d86908f07da33ea8dd7f2
1/* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.gallery3d.filtershow; 18 19import android.app.ActionBar; 20import android.app.AlertDialog; 21import android.app.ProgressDialog; 22import android.app.WallpaperManager; 23import android.content.ContentValues; 24import android.content.DialogInterface; 25import android.content.Intent; 26import android.content.pm.ActivityInfo; 27import android.content.res.Configuration; 28import android.content.res.Resources; 29import android.graphics.Bitmap; 30import android.graphics.Point; 31import android.graphics.drawable.Drawable; 32import android.net.Uri; 33import android.os.AsyncTask; 34import android.os.Bundle; 35import android.support.v4.app.Fragment; 36import android.support.v4.app.FragmentActivity; 37import android.support.v4.app.FragmentTransaction; 38import android.util.DisplayMetrics; 39import android.util.Log; 40import android.util.TypedValue; 41import android.view.Display; 42import android.view.Menu; 43import android.view.MenuItem; 44import android.view.View; 45import android.view.View.OnClickListener; 46import android.view.WindowManager; 47import android.widget.AdapterView; 48import android.widget.AdapterView.OnItemClickListener; 49import android.widget.FrameLayout; 50import android.widget.ShareActionProvider; 51import android.widget.ShareActionProvider.OnShareTargetSelectedListener; 52 53import android.widget.Toast; 54import com.android.gallery3d.R; 55import com.android.gallery3d.data.LocalAlbum; 56import com.android.gallery3d.filtershow.cache.CachingPipeline; 57import com.android.gallery3d.filtershow.cache.FilteringPipeline; 58import com.android.gallery3d.filtershow.cache.ImageLoader; 59import com.android.gallery3d.filtershow.category.*; 60import com.android.gallery3d.filtershow.crop.CropExtras; 61import com.android.gallery3d.filtershow.editors.*; 62import com.android.gallery3d.filtershow.filters.*; 63import com.android.gallery3d.filtershow.imageshow.GeometryMetadata; 64import com.android.gallery3d.filtershow.imageshow.ImageCrop; 65import com.android.gallery3d.filtershow.imageshow.ImageShow; 66import com.android.gallery3d.filtershow.imageshow.MasterImage; 67import com.android.gallery3d.filtershow.presets.ImagePreset; 68import com.android.gallery3d.filtershow.provider.SharedImageProvider; 69import com.android.gallery3d.filtershow.state.StateAdapter; 70import com.android.gallery3d.filtershow.tools.BitmapTask; 71import com.android.gallery3d.filtershow.tools.SaveCopyTask; 72import com.android.gallery3d.filtershow.ui.FramedTextButton; 73import com.android.gallery3d.filtershow.ui.Spline; 74import com.android.gallery3d.util.GalleryUtils; 75import com.android.photos.data.GalleryBitmapPool; 76 77import java.io.File; 78import java.io.IOException; 79import java.lang.ref.WeakReference; 80import java.util.Vector; 81 82public class FilterShowActivity extends FragmentActivity implements OnItemClickListener, 83 OnShareTargetSelectedListener { 84 85 // fields for supporting crop action 86 public static final String CROP_ACTION = "com.android.camera.action.CROP"; 87 private CropExtras mCropExtras = null; 88 private String mAction = ""; 89 MasterImage mMasterImage = null; 90 91 private static final long LIMIT_SUPPORTS_HIGHRES = 134217728; // 128Mb 92 93 public static final String TINY_PLANET_ACTION = "com.android.camera.action.TINY_PLANET"; 94 public static final String LAUNCH_FULLSCREEN = "launch-fullscreen"; 95 public static final int MAX_BMAP_IN_INTENT = 990000; 96 private ImageLoader mImageLoader = null; 97 private ImageShow mImageShow = null; 98 99 private View mSaveButton = null; 100 101 private EditorPlaceHolder mEditorPlaceHolder = new EditorPlaceHolder(this); 102 103 private static final int SELECT_PICTURE = 1; 104 private static final String LOGTAG = "FilterShowActivity"; 105 protected static final boolean ANIMATE_PANELS = true; 106 107 private boolean mShowingTinyPlanet = false; 108 private boolean mShowingImageStatePanel = false; 109 110 private final Vector<ImageShow> mImageViews = new Vector<ImageShow>(); 111 112 private ShareActionProvider mShareActionProvider; 113 private File mSharedOutputFile = null; 114 115 private boolean mSharingImage = false; 116 117 private WeakReference<ProgressDialog> mSavingProgressDialog; 118 119 private LoadBitmapTask mLoadBitmapTask; 120 private boolean mLoading = true; 121 122 private CategoryAdapter mCategoryLooksAdapter = null; 123 private CategoryAdapter mCategoryBordersAdapter = null; 124 private CategoryAdapter mCategoryGeometryAdapter = null; 125 private CategoryAdapter mCategoryFiltersAdapter = null; 126 private int mCurrentPanel = MainPanel.LOOKS; 127 128 @Override 129 public void onCreate(Bundle savedInstanceState) { 130 super.onCreate(savedInstanceState); 131 132 boolean onlyUsePortrait = getResources().getBoolean(R.bool.only_use_portrait); 133 if (onlyUsePortrait) { 134 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); 135 } 136 MasterImage.setMaster(mMasterImage); 137 138 clearGalleryBitmapPool(); 139 140 CachingPipeline.createRenderscriptContext(this); 141 setupMasterImage(); 142 setDefaultValues(); 143 fillEditors(); 144 145 loadXML(); 146 loadMainPanel(); 147 148 setDefaultPreset(); 149 150 processIntent(); 151 } 152 153 public boolean isShowingImageStatePanel() { 154 return mShowingImageStatePanel; 155 } 156 157 public void loadMainPanel() { 158 if (findViewById(R.id.main_panel_container) == null) { 159 return; 160 } 161 MainPanel panel = new MainPanel(); 162 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); 163 transaction.replace(R.id.main_panel_container, panel, MainPanel.FRAGMENT_TAG); 164 transaction.commit(); 165 } 166 167 public void loadEditorPanel(FilterRepresentation representation, 168 Editor currentEditor) { 169 if (representation.getEditorId() == ImageOnlyEditor.ID) { 170 currentEditor.getImageShow().select(); 171 currentEditor.reflectCurrentFilter(); 172 return; 173 } 174 EditorPanel panel = new EditorPanel(); 175 panel.setEditor(currentEditor.getID()); 176 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); 177 transaction.remove(getSupportFragmentManager().findFragmentByTag(MainPanel.FRAGMENT_TAG)); 178 transaction.replace(R.id.main_panel_container, panel, MainPanel.FRAGMENT_TAG); 179 transaction.commit(); 180 } 181 182 private void loadXML() { 183 setContentView(R.layout.filtershow_activity); 184 185 ActionBar actionBar = getActionBar(); 186 actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM); 187 actionBar.setCustomView(R.layout.filtershow_actionbar); 188 189 mSaveButton = actionBar.getCustomView(); 190 mSaveButton.setOnClickListener(new OnClickListener() { 191 @Override 192 public void onClick(View view) { 193 saveImage(); 194 } 195 }); 196 197 mImageShow = (ImageShow) findViewById(R.id.imageShow); 198 mImageViews.add(mImageShow); 199 200 setupEditors(); 201 202 mEditorPlaceHolder.hide(); 203 204 mImageShow.setImageLoader(mImageLoader); 205 206 fillFx(); 207 fillBorders(); 208 fillGeometry(); 209 fillFilters(); 210 211 setupStatePanel(); 212 } 213 214 public void setupStatePanel() { 215 mImageLoader.setAdapter(mMasterImage.getHistory()); 216 } 217 218 private void fillFilters() { 219 Vector<FilterRepresentation> filtersRepresentations = new Vector<FilterRepresentation>(); 220 FiltersManager filtersManager = FiltersManager.getManager(); 221 filtersManager.addEffects(filtersRepresentations); 222 223 mCategoryFiltersAdapter = new CategoryAdapter(this); 224 for (FilterRepresentation representation : filtersRepresentations) { 225 if (representation.getTextId() != 0) { 226 representation.setName(getString(representation.getTextId())); 227 } 228 mCategoryFiltersAdapter.add(new Action(this, representation)); 229 } 230 } 231 232 private void fillGeometry() { 233 Vector<FilterRepresentation> filtersRepresentations = new Vector<FilterRepresentation>(); 234 FiltersManager filtersManager = FiltersManager.getManager(); 235 236 GeometryMetadata geo = new GeometryMetadata(); 237 int[] editorsId = geo.getEditorIds(); 238 for (int i = 0; i < editorsId.length; i++) { 239 int editorId = editorsId[i]; 240 GeometryMetadata geometry = new GeometryMetadata(geo); 241 geometry.setEditorId(editorId); 242 EditorInfo editorInfo = (EditorInfo) mEditorPlaceHolder.getEditor(editorId); 243 geometry.setTextId(editorInfo.getTextId()); 244 geometry.setOverlayId(editorInfo.getOverlayId()); 245 geometry.setOverlayOnly(editorInfo.getOverlayOnly()); 246 if (geometry.getTextId() != 0) { 247 geometry.setName(getString(geometry.getTextId())); 248 } 249 filtersRepresentations.add(geometry); 250 } 251 252 filtersManager.addTools(filtersRepresentations); 253 254 mCategoryGeometryAdapter = new CategoryAdapter(this); 255 for (FilterRepresentation representation : filtersRepresentations) { 256 mCategoryGeometryAdapter.add(new Action(this, representation)); 257 } 258 } 259 260 private void processIntent() { 261 Intent intent = getIntent(); 262 if (intent.getBooleanExtra(LAUNCH_FULLSCREEN, false)) { 263 getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); 264 } 265 266 mAction = intent.getAction(); 267 268 if (intent.getData() != null) { 269 startLoadBitmap(intent.getData()); 270 } else { 271 pickImage(); 272 } 273 } 274 275 private void setupEditors() { 276 mEditorPlaceHolder.setContainer((FrameLayout) findViewById(R.id.editorContainer)); 277 EditorManager.addEditors(mEditorPlaceHolder); 278 mEditorPlaceHolder.setOldViews(mImageViews); 279 mEditorPlaceHolder.setImageLoader(mImageLoader); 280 } 281 282 private void fillEditors() { 283 mEditorPlaceHolder.addEditor(new EditorDraw()); 284 mEditorPlaceHolder.addEditor(new BasicEditor()); 285 mEditorPlaceHolder.addEditor(new ImageOnlyEditor()); 286 mEditorPlaceHolder.addEditor(new EditorTinyPlanet()); 287 mEditorPlaceHolder.addEditor(new EditorRedEye()); 288 mEditorPlaceHolder.addEditor(new EditorCrop()); 289 mEditorPlaceHolder.addEditor(new EditorFlip()); 290 mEditorPlaceHolder.addEditor(new EditorRotate()); 291 mEditorPlaceHolder.addEditor(new EditorStraighten()); 292 } 293 294 private void setDefaultValues() { 295 ImageFilter.setActivityForMemoryToasts(this); 296 297 Resources res = getResources(); 298 FiltersManager.setResources(res); 299 300 CategoryView.setMargin((int) getPixelsFromDip(8)); 301 CategoryView.setTextSize((int) getPixelsFromDip(16)); 302 303 ImageShow.setDefaultBackgroundColor(res.getColor(R.color.background_screen)); 304 // TODO: get those values from XML. 305 FramedTextButton.setTextSize((int) getPixelsFromDip(14)); 306 FramedTextButton.setTrianglePadding((int) getPixelsFromDip(4)); 307 FramedTextButton.setTriangleSize((int) getPixelsFromDip(10)); 308 ImageShow.setTextSize((int) getPixelsFromDip(12)); 309 ImageShow.setTextPadding((int) getPixelsFromDip(10)); 310 ImageShow.setOriginalTextMargin((int) getPixelsFromDip(4)); 311 ImageShow.setOriginalTextSize((int) getPixelsFromDip(18)); 312 ImageShow.setOriginalText(res.getString(R.string.original_picture_text)); 313 314 Drawable curveHandle = res.getDrawable(R.drawable.camera_crop); 315 int curveHandleSize = (int) res.getDimension(R.dimen.crop_indicator_size); 316 Spline.setCurveHandle(curveHandle, curveHandleSize); 317 Spline.setCurveWidth((int) getPixelsFromDip(3)); 318 319 ImageCrop.setAspectTextSize((int) getPixelsFromDip(18)); 320 ImageCrop.setTouchTolerance((int) getPixelsFromDip(25)); 321 ImageCrop.setMinCropSize((int) getPixelsFromDip(55)); 322 } 323 324 private void startLoadBitmap(Uri uri) { 325 mLoading = true; 326 final View loading = findViewById(R.id.loading); 327 final View imageShow = findViewById(R.id.imageShow); 328 imageShow.setVisibility(View.INVISIBLE); 329 loading.setVisibility(View.VISIBLE); 330 mShowingTinyPlanet = false; 331 mLoadBitmapTask = new LoadBitmapTask(); 332 mLoadBitmapTask.execute(uri); 333 } 334 335 private void fillBorders() { 336 Vector<FilterRepresentation> borders = new Vector<FilterRepresentation>(); 337 338 // The "no border" implementation 339 borders.add(new FilterImageBorderRepresentation(0)); 340 341 // Google-build borders 342 FiltersManager.getManager().addBorders(this, borders); 343 344 for (int i = 0; i < borders.size(); i++) { 345 FilterRepresentation filter = borders.elementAt(i); 346 if (i == 0) { 347 filter.setName(getString(R.string.none)); 348 } 349 } 350 351 mCategoryBordersAdapter = new CategoryAdapter(this); 352 for (FilterRepresentation representation : borders) { 353 if (representation.getTextId() != 0) { 354 representation.setName(getString(representation.getTextId())); 355 } 356 mCategoryBordersAdapter.add(new Action(this, representation)); 357 } 358 } 359 360 public CategoryAdapter getCategoryLooksAdapter() { 361 return mCategoryLooksAdapter; 362 } 363 364 public CategoryAdapter getCategoryBordersAdapter() { 365 return mCategoryBordersAdapter; 366 } 367 368 public CategoryAdapter getCategoryGeometryAdapter() { 369 return mCategoryGeometryAdapter; 370 } 371 372 public CategoryAdapter getCategoryFiltersAdapter() { 373 return mCategoryFiltersAdapter; 374 } 375 376 public void removeFilterRepresentation(FilterRepresentation filterRepresentation) { 377 if (filterRepresentation == null) { 378 return; 379 } 380 ImagePreset oldPreset = MasterImage.getImage().getPreset(); 381 ImagePreset copy = new ImagePreset(oldPreset); 382 copy.removeFilter(filterRepresentation); 383 MasterImage.getImage().setPreset(copy, true); 384 if (MasterImage.getImage().getCurrentFilterRepresentation() == filterRepresentation) { 385 FilterRepresentation lastRepresentation = copy.getLastRepresentation(); 386 MasterImage.getImage().setCurrentFilterRepresentation(lastRepresentation); 387 } 388 } 389 390 public void useFilterRepresentation(FilterRepresentation filterRepresentation) { 391 if (filterRepresentation == null) { 392 return; 393 } 394 if (MasterImage.getImage().getCurrentFilterRepresentation() == filterRepresentation) { 395 return; 396 } 397 ImagePreset oldPreset = MasterImage.getImage().getPreset(); 398 ImagePreset copy = new ImagePreset(oldPreset); 399 FilterRepresentation representation = copy.getRepresentation(filterRepresentation); 400 if (representation == null) { 401 copy.addFilter(filterRepresentation); 402 } else { 403 if (filterRepresentation.allowsMultipleInstances()) { 404 representation.updateTempParametersFrom(filterRepresentation); 405 copy.setHistoryName(filterRepresentation.getName()); 406 representation.synchronizeRepresentation(); 407 } 408 filterRepresentation = representation; 409 } 410 MasterImage.getImage().setPreset(copy, true); 411 MasterImage.getImage().setCurrentFilterRepresentation(filterRepresentation); 412 } 413 414 public void showRepresentation(FilterRepresentation representation) { 415 useFilterRepresentation(representation); 416 417 // show representation 418 Editor mCurrentEditor = mEditorPlaceHolder.showEditor(representation.getEditorId()); 419 loadEditorPanel(representation, mCurrentEditor); 420 } 421 422 public Editor getEditor(int editorID) { 423 return mEditorPlaceHolder.getEditor(editorID); 424 } 425 426 public void setCurrentPanel(int currentPanel) { 427 mCurrentPanel = currentPanel; 428 } 429 430 public int getCurrentPanel() { 431 return mCurrentPanel; 432 } 433 434 private class LoadBitmapTask extends AsyncTask<Uri, Boolean, Boolean> { 435 int mBitmapSize; 436 437 public LoadBitmapTask() { 438 mBitmapSize = getScreenImageSize(); 439 } 440 441 @Override 442 protected Boolean doInBackground(Uri... params) { 443 if (!mImageLoader.loadBitmap(params[0], mBitmapSize)) { 444 return false; 445 } 446 publishProgress(mImageLoader.queryLightCycle360()); 447 return true; 448 } 449 450 @Override 451 protected void onProgressUpdate(Boolean... values) { 452 super.onProgressUpdate(values); 453 if (isCancelled()) { 454 return; 455 } 456 if (values[0]) { 457 mShowingTinyPlanet = true; 458 } 459 } 460 461 @Override 462 protected void onPostExecute(Boolean result) { 463 MasterImage.setMaster(mMasterImage); 464 if (isCancelled()) { 465 return; 466 } 467 468 if (!result) { 469 cannotLoadImage(); 470 } 471 472 final View loading = findViewById(R.id.loading); 473 loading.setVisibility(View.GONE); 474 final View imageShow = findViewById(R.id.imageShow); 475 imageShow.setVisibility(View.VISIBLE); 476 477 Bitmap largeBitmap = mImageLoader.getOriginalBitmapLarge(); 478 FilteringPipeline pipeline = FilteringPipeline.getPipeline(); 479 pipeline.setOriginal(largeBitmap); 480 float previewScale = (float) largeBitmap.getWidth() / (float) mImageLoader.getOriginalBounds().width(); 481 pipeline.setPreviewScaleFactor(previewScale); 482 Bitmap highresBitmap = mImageLoader.getOriginalBitmapHighres(); 483 if (highresBitmap != null) { 484 float highResPreviewScale = (float) highresBitmap.getWidth() / (float) mImageLoader.getOriginalBounds().width(); 485 pipeline.setHighResPreviewScaleFactor(highResPreviewScale); 486 } 487 if (!mShowingTinyPlanet) { 488 mCategoryFiltersAdapter.removeTinyPlanet(); 489 } 490 pipeline.turnOnPipeline(true); 491 MasterImage.getImage().setOriginalGeometry(largeBitmap); 492 mCategoryLooksAdapter.imageLoaded(); 493 mCategoryBordersAdapter.imageLoaded(); 494 mCategoryGeometryAdapter.imageLoaded(); 495 mCategoryFiltersAdapter.imageLoaded(); 496 mLoadBitmapTask = null; 497 498 if (mAction == TINY_PLANET_ACTION) { 499 showRepresentation(mCategoryFiltersAdapter.getTinyPlanet()); 500 } 501 mLoading = false; 502 super.onPostExecute(result); 503 } 504 505 } 506 507 private void clearGalleryBitmapPool() { 508 (new AsyncTask<Void, Void, Void>() { 509 @Override 510 protected Void doInBackground(Void... params) { 511 // Free memory held in Gallery's Bitmap pool. May be O(n) for n bitmaps. 512 GalleryBitmapPool.getInstance().clear(); 513 return null; 514 } 515 }).execute(); 516 } 517 518 @Override 519 protected void onDestroy() { 520 if (mLoadBitmapTask != null) { 521 mLoadBitmapTask.cancel(false); 522 } 523 // TODO: refactor, don't use so many singletons. 524 FilteringPipeline.getPipeline().turnOnPipeline(false); 525 MasterImage.reset(); 526 FilteringPipeline.reset(); 527 ImageFilter.resetStatics(); 528 FiltersManager.getPreviewManager().freeRSFilterScripts(); 529 FiltersManager.getManager().freeRSFilterScripts(); 530 FiltersManager.getHighresManager().freeRSFilterScripts(); 531 FiltersManager.reset(); 532 CachingPipeline.destroyRenderScriptContext(); 533 super.onDestroy(); 534 } 535 536 private int getScreenImageSize() { 537 DisplayMetrics metrics = new DisplayMetrics(); 538 Display display = getWindowManager().getDefaultDisplay(); 539 Point size = new Point(); 540 display.getSize(size); 541 display.getMetrics(metrics); 542 int msize = Math.min(size.x, size.y); 543 return (133 * msize) / metrics.densityDpi; 544 } 545 546 private void showSavingProgress(String albumName) { 547 ProgressDialog progress; 548 if (mSavingProgressDialog != null) { 549 progress = mSavingProgressDialog.get(); 550 if (progress != null) { 551 progress.show(); 552 return; 553 } 554 } 555 // TODO: Allow cancellation of the saving process 556 String progressText; 557 if (albumName == null) { 558 progressText = getString(R.string.saving_image); 559 } else { 560 progressText = getString(R.string.filtershow_saving_image, albumName); 561 } 562 progress = ProgressDialog.show(this, "", progressText, true, false); 563 mSavingProgressDialog = new WeakReference<ProgressDialog>(progress); 564 } 565 566 private void hideSavingProgress() { 567 if (mSavingProgressDialog != null) { 568 ProgressDialog progress = mSavingProgressDialog.get(); 569 if (progress != null) 570 progress.dismiss(); 571 } 572 } 573 574 public void completeSaveImage(Uri saveUri) { 575 if (mSharingImage && mSharedOutputFile != null) { 576 // Image saved, we unblock the content provider 577 Uri uri = Uri.withAppendedPath(SharedImageProvider.CONTENT_URI, 578 Uri.encode(mSharedOutputFile.getAbsolutePath())); 579 ContentValues values = new ContentValues(); 580 values.put(SharedImageProvider.PREPARE, false); 581 getContentResolver().insert(uri, values); 582 } 583 setResult(RESULT_OK, new Intent().setData(saveUri)); 584 hideSavingProgress(); 585 finish(); 586 } 587 588 @Override 589 public boolean onShareTargetSelected(ShareActionProvider arg0, Intent arg1) { 590 // First, let's tell the SharedImageProvider that it will need to wait 591 // for the image 592 Uri uri = Uri.withAppendedPath(SharedImageProvider.CONTENT_URI, 593 Uri.encode(mSharedOutputFile.getAbsolutePath())); 594 ContentValues values = new ContentValues(); 595 values.put(SharedImageProvider.PREPARE, true); 596 getContentResolver().insert(uri, values); 597 mSharingImage = true; 598 599 // Process and save the image in the background. 600 showSavingProgress(null); 601 mImageShow.saveImage(this, mSharedOutputFile); 602 return true; 603 } 604 605 private Intent getDefaultShareIntent() { 606 Intent intent = new Intent(Intent.ACTION_SEND); 607 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); 608 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); 609 intent.setType(SharedImageProvider.MIME_TYPE); 610 mSharedOutputFile = SaveCopyTask.getNewFile(this, mImageLoader.getUri()); 611 Uri uri = Uri.withAppendedPath(SharedImageProvider.CONTENT_URI, 612 Uri.encode(mSharedOutputFile.getAbsolutePath())); 613 intent.putExtra(Intent.EXTRA_STREAM, uri); 614 return intent; 615 } 616 617 @Override 618 public boolean onCreateOptionsMenu(Menu menu) { 619 getMenuInflater().inflate(R.menu.filtershow_activity_menu, menu); 620 MenuItem showState = menu.findItem(R.id.showImageStateButton); 621 if (mShowingImageStatePanel) { 622 showState.setTitle(R.string.hide_imagestate_panel); 623 } else { 624 showState.setTitle(R.string.show_imagestate_panel); 625 } 626 mShareActionProvider = (ShareActionProvider) menu.findItem(R.id.menu_share) 627 .getActionProvider(); 628 mShareActionProvider.setShareIntent(getDefaultShareIntent()); 629 mShareActionProvider.setOnShareTargetSelectedListener(this); 630 631 MenuItem undoItem = menu.findItem(R.id.undoButton); 632 MenuItem redoItem = menu.findItem(R.id.redoButton); 633 MenuItem resetItem = menu.findItem(R.id.resetHistoryButton); 634 mMasterImage.getHistory().setMenuItems(undoItem, redoItem, resetItem); 635 return true; 636 } 637 638 @Override 639 public void onPause() { 640 super.onPause(); 641 rsPause(); 642 if (mShareActionProvider != null) { 643 mShareActionProvider.setOnShareTargetSelectedListener(null); 644 } 645 } 646 647 @Override 648 public void onResume() { 649 super.onResume(); 650 rsResume(); 651 if (mShareActionProvider != null) { 652 mShareActionProvider.setOnShareTargetSelectedListener(this); 653 } 654 } 655 656 private void rsResume() { 657 ImageFilter.setActivityForMemoryToasts(this); 658 MasterImage.setMaster(mMasterImage); 659 if (CachingPipeline.getRenderScriptContext() == null) { 660 CachingPipeline.createRenderscriptContext(this); 661 } 662 FiltersManager.setResources(getResources()); 663 if (!mLoading) { 664 Bitmap largeBitmap = mImageLoader.getOriginalBitmapLarge(); 665 FilteringPipeline pipeline = FilteringPipeline.getPipeline(); 666 pipeline.setOriginal(largeBitmap); 667 float previewScale = (float) largeBitmap.getWidth() / 668 (float) mImageLoader.getOriginalBounds().width(); 669 pipeline.setPreviewScaleFactor(previewScale); 670 Bitmap highresBitmap = mImageLoader.getOriginalBitmapHighres(); 671 if (highresBitmap != null) { 672 float highResPreviewScale = (float) highresBitmap.getWidth() / 673 (float) mImageLoader.getOriginalBounds().width(); 674 pipeline.setHighResPreviewScaleFactor(highResPreviewScale); 675 } 676 pipeline.turnOnPipeline(true); 677 MasterImage.getImage().setOriginalGeometry(largeBitmap); 678 } 679 } 680 681 private void rsPause() { 682 FilteringPipeline.getPipeline().turnOnPipeline(false); 683 FilteringPipeline.reset(); 684 ImageFilter.resetStatics(); 685 FiltersManager.getPreviewManager().freeRSFilterScripts(); 686 FiltersManager.getManager().freeRSFilterScripts(); 687 FiltersManager.getHighresManager().freeRSFilterScripts(); 688 FiltersManager.reset(); 689 CachingPipeline.destroyRenderScriptContext(); 690 } 691 692 @Override 693 public boolean onOptionsItemSelected(MenuItem item) { 694 switch (item.getItemId()) { 695 case R.id.undoButton: { 696 HistoryAdapter adapter = mMasterImage.getHistory(); 697 int position = adapter.undo(); 698 mMasterImage.onHistoryItemClick(position); 699 mImageShow.showToast("Undo"); 700 invalidateViews(); 701 return true; 702 } 703 case R.id.redoButton: { 704 HistoryAdapter adapter = mMasterImage.getHistory(); 705 int position = adapter.redo(); 706 mMasterImage.onHistoryItemClick(position); 707 mImageShow.showToast("Redo"); 708 invalidateViews(); 709 return true; 710 } 711 case R.id.resetHistoryButton: { 712 resetHistory(); 713 return true; 714 } 715 case R.id.showImageStateButton: { 716 toggleImageStatePanel(); 717 return true; 718 } 719 case android.R.id.home: { 720 saveImage(); 721 return true; 722 } 723 } 724 return false; 725 } 726 727 public void enableSave(boolean enable) { 728 if (mSaveButton != null) 729 mSaveButton.setEnabled(enable); 730 } 731 732 private void fillFx() { 733 FilterFxRepresentation nullFx = 734 new FilterFxRepresentation(getString(R.string.none), 0, R.string.none); 735 Vector<FilterRepresentation> filtersRepresentations = new Vector<FilterRepresentation>(); 736 FiltersManager.getManager().addLooks(this, filtersRepresentations); 737 738 mCategoryLooksAdapter = new CategoryAdapter(this); 739 int verticalItemHeight = (int) getResources().getDimension(R.dimen.action_item_height); 740 mCategoryLooksAdapter.setItemHeight(verticalItemHeight); 741 mCategoryLooksAdapter.add(new Action(this, nullFx, Action.CROP_VIEW)); 742 for (FilterRepresentation representation : filtersRepresentations) { 743 mCategoryLooksAdapter.add(new Action(this, representation, Action.FULL_VIEW)); 744 } 745 } 746 747 public void setDefaultPreset() { 748 // Default preset (original) 749 ImagePreset preset = new ImagePreset(getString(R.string.history_original)); // empty 750 preset.setImageLoader(mImageLoader); 751 752 mMasterImage.setPreset(preset, true); 753 } 754 755 // ////////////////////////////////////////////////////////////////////////////// 756 // Some utility functions 757 // TODO: finish the cleanup. 758 759 public void invalidateViews() { 760 for (ImageShow views : mImageViews) { 761 views.invalidate(); 762 views.updateImage(); 763 } 764 } 765 766 public void hideImageViews() { 767 for (View view : mImageViews) { 768 view.setVisibility(View.GONE); 769 } 770 mEditorPlaceHolder.hide(); 771 } 772 773 // ////////////////////////////////////////////////////////////////////////////// 774 // imageState panel... 775 776 public void toggleImageStatePanel() { 777 invalidateOptionsMenu(); 778 mShowingImageStatePanel = !mShowingImageStatePanel; 779 Fragment panel = getSupportFragmentManager().findFragmentByTag(MainPanel.FRAGMENT_TAG); 780 if (panel != null) { 781 if (panel instanceof EditorPanel) { 782 EditorPanel editorPanel = (EditorPanel) panel; 783 editorPanel.showImageStatePanel(mShowingImageStatePanel); 784 } else if (panel instanceof MainPanel) { 785 MainPanel mainPanel = (MainPanel) panel; 786 mainPanel.showImageStatePanel(mShowingImageStatePanel); 787 } 788 } 789 } 790 791 @Override 792 public void onConfigurationChanged(Configuration newConfig) 793 { 794 super.onConfigurationChanged(newConfig); 795 setDefaultValues(); 796 loadXML(); 797 loadMainPanel(); 798 799 if (!mShowingTinyPlanet) { 800 mCategoryFiltersAdapter.removeTinyPlanet(); 801 } 802 final View loading = findViewById(R.id.loading); 803 loading.setVisibility(View.GONE); 804 } 805 806 public void setupMasterImage() { 807 mImageLoader = new ImageLoader(this, getApplicationContext()); 808 809 HistoryAdapter mHistoryAdapter = new HistoryAdapter( 810 this, R.layout.filtershow_history_operation_row, 811 R.id.rowTextView); 812 813 StateAdapter mImageStateAdapter = new StateAdapter(this, 0); 814 MasterImage.reset(); 815 mMasterImage = MasterImage.getImage(); 816 mMasterImage.setHistoryAdapter(mHistoryAdapter); 817 mMasterImage.setStateAdapter(mImageStateAdapter); 818 mMasterImage.setActivity(this); 819 mMasterImage.setImageLoader(mImageLoader); 820 821 if (Runtime.getRuntime().maxMemory() > LIMIT_SUPPORTS_HIGHRES) { 822 mMasterImage.setSupportsHighRes(true); 823 } else { 824 mMasterImage.setSupportsHighRes(false); 825 } 826 } 827 828 void resetHistory() { 829 HistoryAdapter adapter = mMasterImage.getHistory(); 830 adapter.reset(); 831 ImagePreset original = new ImagePreset(adapter.getItem(0)); 832 mMasterImage.setPreset(original, true); 833 invalidateViews(); 834 } 835 836 public void showDefaultImageView() { 837 mEditorPlaceHolder.hide(); 838 mImageShow.setVisibility(View.VISIBLE); 839 MasterImage.getImage().setCurrentFilter(null); 840 MasterImage.getImage().setCurrentFilterRepresentation(null); 841 } 842 843 public void backToMain() { 844 Fragment currentPanel = getSupportFragmentManager().findFragmentByTag(MainPanel.FRAGMENT_TAG); 845 if (currentPanel instanceof MainPanel) { 846 return; 847 } 848 loadMainPanel(); 849 showDefaultImageView(); 850 } 851 852 @Override 853 public void onBackPressed() { 854 Fragment currentPanel = getSupportFragmentManager().findFragmentByTag(MainPanel.FRAGMENT_TAG); 855 if (currentPanel instanceof MainPanel) { 856 if (!mImageShow.hasModifications()) { 857 done(); 858 } else { 859 AlertDialog.Builder builder = new AlertDialog.Builder(this); 860 builder.setMessage(R.string.unsaved).setTitle(R.string.save_before_exit); 861 builder.setPositiveButton(R.string.save_and_exit, new DialogInterface.OnClickListener() { 862 public void onClick(DialogInterface dialog, int id) { 863 saveImage(); 864 } 865 }); 866 builder.setNegativeButton(R.string.exit, new DialogInterface.OnClickListener() { 867 public void onClick(DialogInterface dialog, int id) { 868 done(); 869 } 870 }); 871 builder.show(); 872 } 873 } else { 874 backToMain(); 875 } 876 } 877 878 public void cannotLoadImage() { 879 CharSequence text = getString(R.string.cannot_load_image); 880 Toast toast = Toast.makeText(this, text, Toast.LENGTH_SHORT); 881 toast.show(); 882 finish(); 883 } 884 885 // ////////////////////////////////////////////////////////////////////////////// 886 887 public float getPixelsFromDip(float value) { 888 Resources r = getResources(); 889 return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, value, 890 r.getDisplayMetrics()); 891 } 892 893 @Override 894 public void onItemClick(AdapterView<?> parent, View view, int position, 895 long id) { 896 mMasterImage.onHistoryItemClick(position); 897 invalidateViews(); 898 } 899 900 public void pickImage() { 901 Intent intent = new Intent(); 902 intent.setType("image/*"); 903 intent.setAction(Intent.ACTION_GET_CONTENT); 904 startActivityForResult(Intent.createChooser(intent, getString(R.string.select_image)), 905 SELECT_PICTURE); 906 } 907 908 @Override 909 public void onActivityResult(int requestCode, int resultCode, Intent data) { 910 if (resultCode == RESULT_OK) { 911 if (requestCode == SELECT_PICTURE) { 912 Uri selectedImageUri = data.getData(); 913 startLoadBitmap(selectedImageUri); 914 } 915 } 916 } 917 918 private boolean mSaveToExtraUri = false; 919 private boolean mSaveAsWallpaper = false; 920 private boolean mReturnAsExtra = false; 921 private boolean mOutputted = false; 922 923 public void saveImage() { 924 handleSpecialExitCases(); 925 if (!mOutputted) { 926 if (mImageShow.hasModifications()) { 927 // Get the name of the album, to which the image will be saved 928 File saveDir = SaveCopyTask.getFinalSaveDirectory(this, mImageLoader.getUri()); 929 int bucketId = GalleryUtils.getBucketId(saveDir.getPath()); 930 String albumName = LocalAlbum.getLocalizedName(getResources(), bucketId, null); 931 showSavingProgress(albumName); 932 mImageShow.saveImage(this, null); 933 } else { 934 done(); 935 } 936 } 937 } 938 939 public boolean detectSpecialExitCases() { 940 return mCropExtras != null && (mCropExtras.getExtraOutput() != null 941 || mCropExtras.getSetAsWallpaper() || mCropExtras.getReturnData()); 942 } 943 944 public void handleSpecialExitCases() { 945 if (mCropExtras != null) { 946 if (mCropExtras.getExtraOutput() != null) { 947 mSaveToExtraUri = true; 948 mOutputted = true; 949 } 950 if (mCropExtras.getSetAsWallpaper()) { 951 mSaveAsWallpaper = true; 952 mOutputted = true; 953 } 954 if (mCropExtras.getReturnData()) { 955 mReturnAsExtra = true; 956 mOutputted = true; 957 } 958 if (mOutputted) { 959 mImageShow.getImagePreset().mGeoData.setUseCropExtrasFlag(true); 960 showSavingProgress(null); 961 mImageShow.returnFilteredResult(this); 962 } 963 } 964 } 965 966 public void onFilteredResult(Bitmap filtered) { 967 Intent intent = new Intent(); 968 intent.putExtra(CropExtras.KEY_CROPPED_RECT, mImageShow.getImageCropBounds()); 969 if (mSaveToExtraUri) { 970 mImageShow.saveToUri(filtered, mCropExtras.getExtraOutput(), 971 mCropExtras.getOutputFormat(), this); 972 } 973 if (mSaveAsWallpaper) { 974 setWallpaperInBackground(filtered); 975 } 976 if (mReturnAsExtra) { 977 if (filtered != null) { 978 int bmapSize = filtered.getRowBytes() * filtered.getHeight(); 979 /* 980 * Max size of Binder transaction buffer is 1Mb, so constrain 981 * Bitmap to be somewhat less than this, otherwise we get 982 * TransactionTooLargeExceptions. 983 */ 984 if (bmapSize > MAX_BMAP_IN_INTENT) { 985 Log.w(LOGTAG, "Bitmap too large to be returned via intent"); 986 } else { 987 intent.putExtra(CropExtras.KEY_DATA, filtered); 988 } 989 } 990 } 991 setResult(RESULT_OK, intent); 992 if (!mSaveToExtraUri) { 993 done(); 994 } 995 } 996 997 void setWallpaperInBackground(final Bitmap bmap) { 998 Toast.makeText(this, R.string.setting_wallpaper, Toast.LENGTH_LONG).show(); 999 BitmapTask.Callbacks<FilterShowActivity> cb = new BitmapTask.Callbacks<FilterShowActivity>() { 1000 @Override 1001 public void onComplete(Bitmap result) {} 1002 1003 @Override 1004 public void onCancel() {} 1005 1006 @Override 1007 public Bitmap onExecute(FilterShowActivity param) { 1008 try { 1009 WallpaperManager.getInstance(param).setBitmap(bmap); 1010 } catch (IOException e) { 1011 Log.w(LOGTAG, "fail to set wall paper", e); 1012 } 1013 return null; 1014 } 1015 }; 1016 (new BitmapTask<FilterShowActivity>(cb)).execute(this); 1017 } 1018 1019 public void done() { 1020 if (mOutputted) { 1021 hideSavingProgress(); 1022 } 1023 finish(); 1024 } 1025 1026 static { 1027 System.loadLibrary("jni_filtershow_filters"); 1028 } 1029 1030} 1031