FilterShowActivity.java revision ce178c1fa02362636e4992834592d6e019e4ee80
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.annotation.TargetApi; 20import android.app.ActionBar; 21import android.app.Activity; 22import android.app.ProgressDialog; 23import android.app.WallpaperManager; 24import android.content.ContentValues; 25import android.content.Intent; 26import android.content.res.Configuration; 27import android.content.res.Resources; 28import android.graphics.Bitmap; 29import android.graphics.BitmapFactory; 30import android.graphics.Color; 31import android.graphics.Point; 32import android.graphics.drawable.Drawable; 33import android.net.Uri; 34import android.os.AsyncTask; 35import android.os.Bundle; 36import android.provider.MediaStore; 37import android.util.DisplayMetrics; 38import android.util.Log; 39import android.util.TypedValue; 40import android.view.Display; 41import android.view.Menu; 42import android.view.MenuItem; 43import android.view.View; 44import android.view.View.OnClickListener; 45import android.view.WindowManager; 46import android.widget.AdapterView; 47import android.widget.AdapterView.OnItemClickListener; 48import android.widget.ImageButton; 49import android.widget.LinearLayout; 50import android.widget.ListView; 51import android.widget.SeekBar; 52import android.widget.ShareActionProvider; 53import android.widget.ShareActionProvider.OnShareTargetSelectedListener; 54import android.widget.Toast; 55 56import com.android.gallery3d.R; 57import com.android.gallery3d.data.LocalAlbum; 58import com.android.gallery3d.filtershow.cache.ImageLoader; 59import com.android.gallery3d.filtershow.filters.ImageFilter; 60import com.android.gallery3d.filtershow.filters.ImageFilterBorder; 61import com.android.gallery3d.filtershow.filters.ImageFilterBwFilter; 62import com.android.gallery3d.filtershow.filters.ImageFilterContrast; 63import com.android.gallery3d.filtershow.filters.ImageFilterCurves; 64import com.android.gallery3d.filtershow.filters.ImageFilterExposure; 65import com.android.gallery3d.filtershow.filters.ImageFilterFx; 66import com.android.gallery3d.filtershow.filters.ImageFilterHue; 67import com.android.gallery3d.filtershow.filters.ImageFilterNegative; 68import com.android.gallery3d.filtershow.filters.ImageFilterParametricBorder; 69import com.android.gallery3d.filtershow.filters.ImageFilterRS; 70import com.android.gallery3d.filtershow.filters.ImageFilterSaturated; 71import com.android.gallery3d.filtershow.filters.ImageFilterShadows; 72import com.android.gallery3d.filtershow.filters.ImageFilterSharpen; 73import com.android.gallery3d.filtershow.filters.ImageFilterTinyPlanet; 74import com.android.gallery3d.filtershow.filters.ImageFilterVibrance; 75import com.android.gallery3d.filtershow.filters.ImageFilterVignette; 76import com.android.gallery3d.filtershow.filters.ImageFilterWBalance; 77import com.android.gallery3d.filtershow.imageshow.ImageBorder; 78import com.android.gallery3d.filtershow.imageshow.ImageCrop; 79import com.android.gallery3d.filtershow.imageshow.ImageFlip; 80import com.android.gallery3d.filtershow.imageshow.ImageRedEyes; 81import com.android.gallery3d.filtershow.imageshow.ImageRotate; 82import com.android.gallery3d.filtershow.imageshow.ImageShow; 83import com.android.gallery3d.filtershow.imageshow.ImageSmallBorder; 84import com.android.gallery3d.filtershow.imageshow.ImageSmallFilter; 85import com.android.gallery3d.filtershow.imageshow.ImageStraighten; 86import com.android.gallery3d.filtershow.imageshow.ImageTinyPlanet; 87import com.android.gallery3d.filtershow.imageshow.ImageZoom; 88import com.android.gallery3d.filtershow.presets.ImagePreset; 89import com.android.gallery3d.filtershow.provider.SharedImageProvider; 90import com.android.gallery3d.filtershow.tools.SaveCopyTask; 91import com.android.gallery3d.filtershow.ui.FramedTextButton; 92import com.android.gallery3d.filtershow.ui.ImageButtonTitle; 93import com.android.gallery3d.filtershow.ui.ImageCurves; 94import com.android.gallery3d.filtershow.ui.Spline; 95import com.android.gallery3d.util.GalleryUtils; 96 97import java.io.File; 98import java.io.IOException; 99import java.lang.ref.WeakReference; 100import java.util.Vector; 101 102@TargetApi(16) 103public class FilterShowActivity extends Activity implements OnItemClickListener, 104 OnShareTargetSelectedListener { 105 106 // fields for supporting crop action 107 public static final String CROP_ACTION = "com.android.camera.action.CROP"; 108 private CropExtras mCropExtras = null; 109 110 public static final String TINY_PLANET_ACTION = "com.android.camera.action.TINY_PLANET"; 111 public static final String LAUNCH_FULLSCREEN = "launch-fullscreen"; 112 public static final int MAX_BMAP_IN_INTENT = 990000; 113 private final PanelController mPanelController = new PanelController(); 114 private ImageLoader mImageLoader = null; 115 private ImageShow mImageShow = null; 116 private ImageCurves mImageCurves = null; 117 private ImageBorder mImageBorders = null; 118 private ImageRedEyes mImageRedEyes = null; 119 private ImageStraighten mImageStraighten = null; 120 private ImageZoom mImageZoom = null; 121 private ImageCrop mImageCrop = null; 122 private ImageRotate mImageRotate = null; 123 private ImageFlip mImageFlip = null; 124 private ImageTinyPlanet mImageTinyPlanet = null; 125 126 private View mListFx = null; 127 private View mListBorders = null; 128 private View mListGeometry = null; 129 private View mListColors = null; 130 private View mListFilterButtons = null; 131 private View mSaveButton = null; 132 133 private ImageButton mFxButton = null; 134 private ImageButton mBorderButton = null; 135 private ImageButton mGeometryButton = null; 136 private ImageButton mColorsButton = null; 137 138 private ImageSmallFilter mCurrentImageSmallFilter = null; 139 private static final int SELECT_PICTURE = 1; 140 private static final String LOGTAG = "FilterShowActivity"; 141 protected static final boolean ANIMATE_PANELS = true; 142 private static int mImageBorderSize = 4; // in percent 143 144 private boolean mShowingHistoryPanel = false; 145 private boolean mShowingImageStatePanel = false; 146 147 private final Vector<ImageShow> mImageViews = new Vector<ImageShow>(); 148 private final Vector<View> mListViews = new Vector<View>(); 149 private final Vector<ImageButton> mBottomPanelButtons = new Vector<ImageButton>(); 150 151 private ShareActionProvider mShareActionProvider; 152 private File mSharedOutputFile = null; 153 154 private boolean mSharingImage = false; 155 156 private WeakReference<ProgressDialog> mSavingProgressDialog; 157 private static final int SEEK_BAR_MAX = 600; 158 159 private LoadBitmapTask mLoadBitmapTask; 160 private ImageSmallFilter mNullFxFilter; 161 private ImageSmallFilter mNullBorderFilter; 162 163 @Override 164 public void onCreate(Bundle savedInstanceState) { 165 super.onCreate(savedInstanceState); 166 167 ImageFilterRS.setRenderScriptContext(this); 168 169 ImageShow.setDefaultBackgroundColor(getResources().getColor(R.color.background_screen)); 170 ImageSmallFilter.setDefaultBackgroundColor(getResources().getColor( 171 R.color.background_main_toolbar)); 172 // TODO: get those values from XML. 173 ImageZoom.setZoomedSize(getPixelsFromDip(256)); 174 FramedTextButton.setTextSize((int) getPixelsFromDip(14)); 175 FramedTextButton.setTrianglePadding((int) getPixelsFromDip(4)); 176 FramedTextButton.setTriangleSize((int) getPixelsFromDip(10)); 177 ImageShow.setTextSize((int) getPixelsFromDip(12)); 178 ImageShow.setTextPadding((int) getPixelsFromDip(10)); 179 ImageShow.setOriginalTextMargin((int) getPixelsFromDip(4)); 180 ImageShow.setOriginalTextSize((int) getPixelsFromDip(18)); 181 ImageShow.setOriginalText(getResources().getString(R.string.original_picture_text)); 182 ImageButtonTitle.setTextSize((int) getPixelsFromDip(12)); 183 ImageButtonTitle.setTextPadding((int) getPixelsFromDip(10)); 184 ImageSmallFilter.setMargin((int) getPixelsFromDip(3)); 185 ImageSmallFilter.setTextMargin((int) getPixelsFromDip(4)); 186 Drawable curveHandle = getResources().getDrawable(R.drawable.camera_crop); 187 int curveHandleSize = (int) getResources().getDimension(R.dimen.crop_indicator_size); 188 Spline.setCurveHandle(curveHandle, curveHandleSize); 189 Spline.setCurveWidth((int) getPixelsFromDip(3)); 190 191 setContentView(R.layout.filtershow_activity); 192 ActionBar actionBar = getActionBar(); 193 actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM); 194 actionBar.setCustomView(R.layout.filtershow_actionbar); 195 196 mSaveButton = actionBar.getCustomView(); 197 mSaveButton.setOnClickListener(new OnClickListener() { 198 @Override 199 public void onClick(View view) { 200 saveImage(); 201 } 202 }); 203 204 mImageLoader = new ImageLoader(this, getApplicationContext()); 205 206 LinearLayout listFilters = (LinearLayout) findViewById(R.id.listFilters); 207 LinearLayout listBorders = (LinearLayout) findViewById(R.id.listBorders); 208 LinearLayout listColors = (LinearLayout) findViewById(R.id.listColorsFx); 209 210 mImageShow = (ImageShow) findViewById(R.id.imageShow); 211 mImageCurves = (ImageCurves) findViewById(R.id.imageCurves); 212 mImageBorders = (ImageBorder) findViewById(R.id.imageBorder); 213 mImageStraighten = (ImageStraighten) findViewById(R.id.imageStraighten); 214 mImageZoom = (ImageZoom) findViewById(R.id.imageZoom); 215 mImageCrop = (ImageCrop) findViewById(R.id.imageCrop); 216 mImageRotate = (ImageRotate) findViewById(R.id.imageRotate); 217 mImageFlip = (ImageFlip) findViewById(R.id.imageFlip); 218 mImageTinyPlanet = (ImageTinyPlanet) findViewById(R.id.imageTinyPlanet); 219 mImageRedEyes = (ImageRedEyes) findViewById(R.id.imageRedEyes); 220 221 mImageCrop.setAspectTextSize((int) getPixelsFromDip(18)); 222 ImageCrop.setTouchTolerance((int) getPixelsFromDip(25)); 223 ImageCrop.setMinCropSize((int) getPixelsFromDip(55)); 224 mImageViews.add(mImageShow); 225 mImageViews.add(mImageCurves); 226 mImageViews.add(mImageBorders); 227 mImageViews.add(mImageStraighten); 228 mImageViews.add(mImageZoom); 229 mImageViews.add(mImageCrop); 230 mImageViews.add(mImageRotate); 231 mImageViews.add(mImageFlip); 232 mImageViews.add(mImageTinyPlanet); 233 mImageViews.add(mImageRedEyes); 234 for (ImageShow imageShow : mImageViews) { 235 mImageLoader.addCacheListener(imageShow); 236 } 237 238 mListFx = findViewById(R.id.fxList); 239 mListBorders = findViewById(R.id.bordersList); 240 mListGeometry = findViewById(R.id.geometryList); 241 mListFilterButtons = findViewById(R.id.filterButtonsList); 242 mListColors = findViewById(R.id.colorsFxList); 243 mListViews.add(mListFx); 244 mListViews.add(mListBorders); 245 mListViews.add(mListGeometry); 246 mListViews.add(mListFilterButtons); 247 mListViews.add(mListColors); 248 249 mFxButton = (ImageButton) findViewById(R.id.fxButton); 250 mBorderButton = (ImageButton) findViewById(R.id.borderButton); 251 mGeometryButton = (ImageButton) findViewById(R.id.geometryButton); 252 mColorsButton = (ImageButton) findViewById(R.id.colorsButton); 253 254 mImageShow.setImageLoader(mImageLoader); 255 mImageCurves.setImageLoader(mImageLoader); 256 mImageCurves.setMaster(mImageShow); 257 mImageBorders.setImageLoader(mImageLoader); 258 mImageBorders.setMaster(mImageShow); 259 mImageStraighten.setImageLoader(mImageLoader); 260 mImageStraighten.setMaster(mImageShow); 261 mImageZoom.setImageLoader(mImageLoader); 262 mImageZoom.setMaster(mImageShow); 263 mImageCrop.setImageLoader(mImageLoader); 264 mImageCrop.setMaster(mImageShow); 265 mImageRotate.setImageLoader(mImageLoader); 266 mImageRotate.setMaster(mImageShow); 267 mImageFlip.setImageLoader(mImageLoader); 268 mImageFlip.setMaster(mImageShow); 269 mImageTinyPlanet.setImageLoader(mImageLoader); 270 mImageTinyPlanet.setMaster(mImageShow); 271 mImageRedEyes.setImageLoader(mImageLoader); 272 mImageRedEyes.setMaster(mImageShow); 273 274 mPanelController.setActivity(this); 275 276 mPanelController.addImageView(findViewById(R.id.imageShow)); 277 mPanelController.addImageView(findViewById(R.id.imageCurves)); 278 mPanelController.addImageView(findViewById(R.id.imageBorder)); 279 mPanelController.addImageView(findViewById(R.id.imageStraighten)); 280 mPanelController.addImageView(findViewById(R.id.imageCrop)); 281 mPanelController.addImageView(findViewById(R.id.imageRotate)); 282 mPanelController.addImageView(findViewById(R.id.imageFlip)); 283 mPanelController.addImageView(findViewById(R.id.imageZoom)); 284 mPanelController.addImageView(findViewById(R.id.imageTinyPlanet)); 285 mPanelController.addImageView(findViewById(R.id.imageRedEyes)); 286 287 mPanelController.addPanel(mFxButton, mListFx, 0); 288 mPanelController.addPanel(mBorderButton, mListBorders, 1); 289 290 mPanelController.addPanel(mGeometryButton, mListGeometry, 2); 291 mPanelController.addComponent(mGeometryButton, findViewById(R.id.straightenButton)); 292 mPanelController.addComponent(mGeometryButton, findViewById(R.id.cropButton)); 293 mPanelController.addComponent(mGeometryButton, findViewById(R.id.rotateButton)); 294 mPanelController.addComponent(mGeometryButton, findViewById(R.id.flipButton)); 295 mPanelController.addComponent(mGeometryButton, findViewById(R.id.redEyeButton)); 296 297 mPanelController.addPanel(mColorsButton, mListColors, 3); 298 299 ImageFilter[] filters = { 300 new ImageFilterTinyPlanet(), 301 new ImageFilterWBalance(), 302 new ImageFilterExposure(), 303 new ImageFilterVignette(), 304 new ImageFilterContrast(), 305 new ImageFilterShadows(), 306 new ImageFilterVibrance(), 307 new ImageFilterSharpen(), 308 new ImageFilterCurves(), 309 new ImageFilterHue(), 310 new ImageFilterSaturated(), 311 new ImageFilterBwFilter(), 312 new ImageFilterNegative() 313 }; 314 315 for (int i = 0; i < filters.length; i++) { 316 ImageSmallFilter fView = new ImageSmallFilter(this); 317 filters[i].setParameter(filters[i].getPreviewParameter()); 318 filters[i].setName(getString(filters[i].getTextId())); 319 fView.setImageFilter(filters[i]); 320 fView.setController(this); 321 fView.setImageLoader(mImageLoader); 322 fView.setId(filters[i].getButtonId()); 323 if (filters[i].getOverlayBitmaps() != 0) { 324 Bitmap bitmap = BitmapFactory.decodeResource(getResources(), 325 filters[i].getOverlayBitmaps()); 326 fView.setOverlayBitmap(bitmap); 327 } 328 mPanelController.addComponent(mColorsButton, fView); 329 mPanelController.addFilter(filters[i]); 330 listColors.addView(fView); 331 } 332 333 mPanelController.addView(findViewById(R.id.applyEffect)); 334 mPanelController.addView(findViewById(R.id.pickCurvesChannel)); 335 mPanelController.addView(findViewById(R.id.aspect)); 336 findViewById(R.id.resetOperationsButton).setOnClickListener( 337 createOnClickResetOperationsButton()); 338 339 ListView operationsList = (ListView) findViewById(R.id.operationsList); 340 operationsList.setAdapter(mImageShow.getHistory()); 341 operationsList.setOnItemClickListener(this); 342 ListView imageStateList = (ListView) findViewById(R.id.imageStateList); 343 imageStateList.setAdapter(mImageShow.getImageStateAdapter()); 344 mImageLoader.setAdapter(mImageShow.getHistory()); 345 346 fillListImages(listFilters); 347 fillListBorders(listBorders); 348 349 SeekBar seekBar = (SeekBar) findViewById(R.id.filterSeekBar); 350 seekBar.setMax(SEEK_BAR_MAX); 351 352 mImageShow.setSeekBar(seekBar); 353 mImageZoom.setSeekBar(seekBar); 354 mImageTinyPlanet.setSeekBar(seekBar); 355 mPanelController.setRowPanel(findViewById(R.id.secondRowPanel)); 356 mPanelController.setUtilityPanel(this, findViewById(R.id.filterButtonsList), 357 findViewById(R.id.applyEffect), findViewById(R.id.aspect), 358 findViewById(R.id.pickCurvesChannel)); 359 mPanelController.setMasterImage(mImageShow); 360 mPanelController.setCurrentPanel(mFxButton); 361 Intent intent = getIntent(); 362 if (intent.getBooleanExtra(LAUNCH_FULLSCREEN, false)) { 363 getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); 364 } 365 366 if (intent.getData() != null) { 367 startLoadBitmap(intent.getData()); 368 } else { 369 pickImage(); 370 } 371 372 // Handle behavior for various actions 373 String action = intent.getAction(); 374 if (action.equalsIgnoreCase(CROP_ACTION)) { 375 Bundle extras = intent.getExtras(); 376 if (extras != null) { 377 mCropExtras = new CropExtras(extras.getInt(CropExtras.KEY_OUTPUT_X, 0), 378 extras.getInt(CropExtras.KEY_OUTPUT_Y, 0), 379 extras.getBoolean(CropExtras.KEY_SCALE, true) && 380 extras.getBoolean(CropExtras.KEY_SCALE_UP_IF_NEEDED, false), 381 extras.getInt(CropExtras.KEY_ASPECT_X, 0), 382 extras.getInt(CropExtras.KEY_ASPECT_Y, 0), 383 extras.getBoolean(CropExtras.KEY_SET_AS_WALLPAPER, false), 384 extras.getBoolean(CropExtras.KEY_RETURN_DATA, false), 385 (Uri) extras.getParcelable(MediaStore.EXTRA_OUTPUT), 386 extras.getString(CropExtras.KEY_OUTPUT_FORMAT), 387 extras.getBoolean(CropExtras.KEY_SHOW_WHEN_LOCKED, false), 388 extras.getFloat(CropExtras.KEY_SPOTLIGHT_X), 389 extras.getFloat(CropExtras.KEY_SPOTLIGHT_Y)); 390 391 if (mCropExtras.getShowWhenLocked()) { 392 getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED); 393 } 394 mImageShow.getImagePreset().mGeoData.setCropExtras(mCropExtras); 395 396 mImageCrop.setExtras(mCropExtras); 397 String s = getString(R.string.Fixed); 398 mImageCrop.setAspectString(s); 399 mImageCrop.setCropActionFlag(true); 400 mPanelController.setFixedAspect(mCropExtras.getAspectX() > 0 401 && mCropExtras.getAspectY() > 0); 402 } 403 mPanelController.showComponent(findViewById(R.id.cropButton)); 404 } else if (action.equalsIgnoreCase(TINY_PLANET_ACTION)) { 405 mPanelController.showComponent(findViewById(R.id.tinyplanetButton)); 406 } 407 } 408 409 private void startLoadBitmap(Uri uri) { 410 final View filters = findViewById(R.id.filtersPanel); 411 final View loading = findViewById(R.id.loading); 412 loading.setVisibility(View.VISIBLE); 413 filters.setVisibility(View.INVISIBLE); 414 View tinyPlanetView = findViewById(R.id.tinyplanetButton); 415 if (tinyPlanetView != null) { 416 tinyPlanetView.setVisibility(View.GONE); 417 } 418 mLoadBitmapTask = new LoadBitmapTask(tinyPlanetView); 419 mLoadBitmapTask.execute(uri); 420 } 421 422 private class LoadBitmapTask extends AsyncTask<Uri, Boolean, Boolean> { 423 View mTinyPlanetButton; 424 int mBitmapSize; 425 426 public LoadBitmapTask(View button) { 427 mTinyPlanetButton = button; 428 mBitmapSize = getScreenImageSize(); 429 } 430 431 @Override 432 protected Boolean doInBackground(Uri... params) { 433 if (!mImageLoader.loadBitmap(params[0], mBitmapSize)) { 434 return false; 435 } 436 publishProgress(mImageLoader.queryLightCycle360()); 437 return true; 438 } 439 440 @Override 441 protected void onProgressUpdate(Boolean... values) { 442 super.onProgressUpdate(values); 443 if (isCancelled()) { 444 return; 445 } 446 final View filters = findViewById(R.id.filtersPanel); 447 final View loading = findViewById(R.id.loading); 448 loading.setVisibility(View.GONE); 449 filters.setVisibility(View.VISIBLE); 450 if (values[0]) { 451 mTinyPlanetButton.setVisibility(View.VISIBLE); 452 } 453 } 454 455 @Override 456 protected void onPostExecute(Boolean result) { 457 if (isCancelled()) { 458 return; 459 } 460 if (!result) { 461 cannotLoadImage(); 462 } 463 464 mLoadBitmapTask = null; 465 super.onPostExecute(result); 466 } 467 468 } 469 470 @Override 471 protected void onDestroy() { 472 if (mLoadBitmapTask != null) { 473 mLoadBitmapTask.cancel(false); 474 } 475 super.onDestroy(); 476 } 477 478 private int translateMainPanel(View viewPanel) { 479 int accessoryPanelWidth = viewPanel.getWidth(); 480 int mainViewWidth = findViewById(R.id.mainView).getWidth(); 481 int mainPanelWidth = mImageShow.getDisplayedImageBounds().width(); 482 if (mainPanelWidth == 0) { 483 mainPanelWidth = mainViewWidth; 484 } 485 int filtersPanelWidth = findViewById(R.id.filtersPanel).getWidth(); 486 if (mainPanelWidth < filtersPanelWidth) { 487 mainPanelWidth = filtersPanelWidth; 488 } 489 int leftOver = mainViewWidth - mainPanelWidth - accessoryPanelWidth; 490 if (leftOver < 0) { 491 return -accessoryPanelWidth; 492 } 493 return 0; 494 } 495 496 private int getScreenImageSize() { 497 DisplayMetrics metrics = new DisplayMetrics(); 498 Display display = getWindowManager().getDefaultDisplay(); 499 Point size = new Point(); 500 display.getSize(size); 501 display.getMetrics(metrics); 502 int msize = Math.min(size.x, size.y); 503 return (133 * msize) / metrics.densityDpi; 504 } 505 506 private void showSavingProgress(String albumName) { 507 ProgressDialog progress; 508 if (mSavingProgressDialog != null) { 509 progress = mSavingProgressDialog.get(); 510 if (progress != null) { 511 progress.show(); 512 return; 513 } 514 } 515 // TODO: Allow cancellation of the saving process 516 String progressText; 517 if (albumName == null) { 518 progressText = getString(R.string.saving_image); 519 } else { 520 progressText = getString(R.string.filtershow_saving_image, albumName); 521 } 522 progress = ProgressDialog.show(this, "", progressText, true, false); 523 mSavingProgressDialog = new WeakReference<ProgressDialog>(progress); 524 } 525 526 private void hideSavingProgress() { 527 if (mSavingProgressDialog != null) { 528 ProgressDialog progress = mSavingProgressDialog.get(); 529 if (progress != null) 530 progress.dismiss(); 531 } 532 } 533 534 public void completeSaveImage(Uri saveUri) { 535 if (mSharingImage && mSharedOutputFile != null) { 536 // Image saved, we unblock the content provider 537 Uri uri = Uri.withAppendedPath(SharedImageProvider.CONTENT_URI, 538 Uri.encode(mSharedOutputFile.getAbsolutePath())); 539 ContentValues values = new ContentValues(); 540 values.put(SharedImageProvider.PREPARE, false); 541 getContentResolver().insert(uri, values); 542 } 543 setResult(RESULT_OK, new Intent().setData(saveUri)); 544 hideSavingProgress(); 545 finish(); 546 } 547 548 @Override 549 public boolean onShareTargetSelected(ShareActionProvider arg0, Intent arg1) { 550 // First, let's tell the SharedImageProvider that it will need to wait 551 // for the image 552 Uri uri = Uri.withAppendedPath(SharedImageProvider.CONTENT_URI, 553 Uri.encode(mSharedOutputFile.getAbsolutePath())); 554 ContentValues values = new ContentValues(); 555 values.put(SharedImageProvider.PREPARE, true); 556 getContentResolver().insert(uri, values); 557 mSharingImage = true; 558 559 // Process and save the image in the background. 560 showSavingProgress(null); 561 mImageShow.saveImage(this, mSharedOutputFile); 562 return true; 563 } 564 565 private Intent getDefaultShareIntent() { 566 Intent intent = new Intent(Intent.ACTION_SEND); 567 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); 568 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); 569 intent.setType(SharedImageProvider.MIME_TYPE); 570 mSharedOutputFile = SaveCopyTask.getNewFile(this, mImageLoader.getUri()); 571 Uri uri = Uri.withAppendedPath(SharedImageProvider.CONTENT_URI, 572 Uri.encode(mSharedOutputFile.getAbsolutePath())); 573 intent.putExtra(Intent.EXTRA_STREAM, uri); 574 return intent; 575 } 576 577 @Override 578 public boolean onCreateOptionsMenu(Menu menu) { 579 getMenuInflater().inflate(R.menu.filtershow_activity_menu, menu); 580 MenuItem showHistory = menu.findItem(R.id.operationsButton); 581 if (mShowingHistoryPanel) { 582 showHistory.setTitle(R.string.hide_history_panel); 583 } else { 584 showHistory.setTitle(R.string.show_history_panel); 585 } 586 MenuItem showState = menu.findItem(R.id.showImageStateButton); 587 if (mShowingImageStatePanel) { 588 showState.setTitle(R.string.hide_imagestate_panel); 589 } else { 590 showState.setTitle(R.string.show_imagestate_panel); 591 } 592 mShareActionProvider = (ShareActionProvider) menu.findItem(R.id.menu_share) 593 .getActionProvider(); 594 mShareActionProvider.setShareIntent(getDefaultShareIntent()); 595 mShareActionProvider.setOnShareTargetSelectedListener(this); 596 597 MenuItem undoItem = menu.findItem(R.id.undoButton); 598 MenuItem redoItem = menu.findItem(R.id.redoButton); 599 MenuItem resetItem = menu.findItem(R.id.resetHistoryButton); 600 mImageShow.getHistory().setMenuItems(undoItem, redoItem, resetItem); 601 return true; 602 } 603 604 @Override 605 public void onPause() { 606 super.onPause(); 607 if (mShareActionProvider != null) { 608 mShareActionProvider.setOnShareTargetSelectedListener(null); 609 } 610 } 611 612 @Override 613 public void onResume() { 614 super.onResume(); 615 if (mShareActionProvider != null) { 616 mShareActionProvider.setOnShareTargetSelectedListener(this); 617 } 618 } 619 620 @Override 621 public boolean onOptionsItemSelected(MenuItem item) { 622 switch (item.getItemId()) { 623 case R.id.undoButton: { 624 HistoryAdapter adapter = mImageShow.getHistory(); 625 int position = adapter.undo(); 626 mImageShow.onItemClick(position); 627 mImageShow.showToast("Undo"); 628 invalidateViews(); 629 return true; 630 } 631 case R.id.redoButton: { 632 HistoryAdapter adapter = mImageShow.getHistory(); 633 int position = adapter.redo(); 634 mImageShow.onItemClick(position); 635 mImageShow.showToast("Redo"); 636 invalidateViews(); 637 return true; 638 } 639 case R.id.resetHistoryButton: { 640 resetHistory(); 641 return true; 642 } 643 case R.id.showImageStateButton: { 644 toggleImageStatePanel(); 645 return true; 646 } 647 case R.id.operationsButton: { 648 toggleHistoryPanel(); 649 return true; 650 } 651 case android.R.id.home: { 652 saveImage(); 653 return true; 654 } 655 } 656 return false; 657 } 658 659 public void enableSave(boolean enable) { 660 if (mSaveButton != null) 661 mSaveButton.setEnabled(enable); 662 } 663 664 private void fillListImages(LinearLayout listFilters) { 665 // TODO: use listview 666 // TODO: load the filters straight from the filesystem 667 668 ImageFilterFx[] fxArray = new ImageFilterFx[18]; 669 int p = 0; 670 671 int[] drawid = { 672 R.drawable.filtershow_fx_0005_punch, 673 R.drawable.filtershow_fx_0000_vintage, 674 R.drawable.filtershow_fx_0004_bw_contrast, 675 R.drawable.filtershow_fx_0002_bleach, 676 R.drawable.filtershow_fx_0001_instant, 677 R.drawable.filtershow_fx_0007_washout, 678 R.drawable.filtershow_fx_0003_blue_crush, 679 R.drawable.filtershow_fx_0008_washout_color, 680 R.drawable.filtershow_fx_0006_x_process 681 }; 682 683 int[] fxNameid = { 684 R.string.ffx_punch, 685 R.string.ffx_vintage, 686 R.string.ffx_bw_contrast, 687 R.string.ffx_bleach, 688 R.string.ffx_instant, 689 R.string.ffx_washout, 690 R.string.ffx_blue_crush, 691 R.string.ffx_washout_color, 692 R.string.ffx_x_process 693 }; 694 695 ImagePreset preset = new ImagePreset(getString(R.string.history_original)); // empty 696 preset.setImageLoader(mImageLoader); 697 mNullFxFilter = new ImageSmallFilter(this); 698 699 mNullFxFilter.setSelected(true); 700 mCurrentImageSmallFilter = mNullFxFilter; 701 702 mNullFxFilter.setImageFilter(new ImageFilterFx(null, getString(R.string.none))); 703 704 mNullFxFilter.setController(this); 705 mNullFxFilter.setImageLoader(mImageLoader); 706 listFilters.addView(mNullFxFilter); 707 ImageSmallFilter previousFilter = mNullFxFilter; 708 709 BitmapFactory.Options o = new BitmapFactory.Options(); 710 o.inScaled = false; 711 712 for (int i = 0; i < drawid.length; i++) { 713 Bitmap b = BitmapFactory.decodeResource(getResources(), drawid[i], o); 714 fxArray[p++] = new ImageFilterFx(b, getString(fxNameid[i])); 715 } 716 ImageSmallFilter filter; 717 for (int i = 0; i < p; i++) { 718 filter = new ImageSmallFilter(this); 719 filter.setImageFilter(fxArray[i]); 720 filter.setController(this); 721 filter.setNulfilter(mNullFxFilter); 722 filter.setImageLoader(mImageLoader); 723 listFilters.addView(filter); 724 previousFilter = filter; 725 } 726 727 // Default preset (original) 728 mImageShow.setImagePreset(preset); 729 } 730 731 private void fillListBorders(LinearLayout listBorders) { 732 // TODO: use listview 733 // TODO: load the borders straight from the filesystem 734 int p = 0; 735 ImageFilter[] borders = new ImageFilter[12]; 736 borders[p++] = new ImageFilterBorder(null); 737 738 Drawable npd1 = getResources().getDrawable(R.drawable.filtershow_border_4x5); 739 borders[p++] = new ImageFilterBorder(npd1); 740 Drawable npd2 = getResources().getDrawable(R.drawable.filtershow_border_brush); 741 borders[p++] = new ImageFilterBorder(npd2); 742 Drawable npd3 = getResources().getDrawable(R.drawable.filtershow_border_grunge); 743 borders[p++] = new ImageFilterBorder(npd3); 744 Drawable npd4 = getResources().getDrawable(R.drawable.filtershow_border_sumi_e); 745 borders[p++] = new ImageFilterBorder(npd4); 746 Drawable npd5 = getResources().getDrawable(R.drawable.filtershow_border_tape); 747 borders[p++] = new ImageFilterBorder(npd5); 748 borders[p++] = new ImageFilterParametricBorder(Color.BLACK, mImageBorderSize, 0); 749 borders[p++] = new ImageFilterParametricBorder(Color.BLACK, mImageBorderSize, 750 mImageBorderSize); 751 borders[p++] = new ImageFilterParametricBorder(Color.WHITE, mImageBorderSize, 0); 752 borders[p++] = new ImageFilterParametricBorder(Color.WHITE, mImageBorderSize, 753 mImageBorderSize); 754 int creamColor = Color.argb(255, 237, 237, 227); 755 borders[p++] = new ImageFilterParametricBorder(creamColor, mImageBorderSize, 0); 756 borders[p++] = new ImageFilterParametricBorder(creamColor, mImageBorderSize, 757 mImageBorderSize); 758 759 ImageSmallFilter previousFilter = null; 760 for (int i = 0; i < p; i++) { 761 ImageSmallBorder filter = new ImageSmallBorder(this); 762 if (i == 0) { // save the first to reset it 763 mNullBorderFilter = filter; 764 } else { 765 filter.setNulfilter(mNullBorderFilter); 766 } 767 borders[i].setName(getString(R.string.borders)); 768 filter.setImageFilter(borders[i]); 769 filter.setController(this); 770 filter.setBorder(true); 771 filter.setImageLoader(mImageLoader); 772 filter.setShowTitle(false); 773 listBorders.addView(filter); 774 previousFilter = filter; 775 } 776 } 777 778 // ////////////////////////////////////////////////////////////////////////////// 779 // Some utility functions 780 // TODO: finish the cleanup. 781 782 public void showOriginalViews(boolean value) { 783 for (ImageShow views : mImageViews) { 784 views.showOriginal(value); 785 } 786 } 787 788 public void invalidateViews() { 789 for (ImageShow views : mImageViews) { 790 views.invalidate(); 791 views.updateImage(); 792 } 793 } 794 795 public void hideListViews() { 796 for (View view : mListViews) { 797 view.setVisibility(View.GONE); 798 } 799 } 800 801 public void hideImageViews() { 802 mImageShow.setShowControls(false); // reset 803 for (View view : mImageViews) { 804 view.setVisibility(View.GONE); 805 } 806 } 807 808 public void unselectBottomPanelButtons() { 809 for (ImageButton button : mBottomPanelButtons) { 810 button.setSelected(false); 811 } 812 } 813 814 public void unselectPanelButtons(Vector<ImageButton> buttons) { 815 for (ImageButton button : buttons) { 816 button.setSelected(false); 817 } 818 } 819 820 // ////////////////////////////////////////////////////////////////////////////// 821 // imageState panel... 822 823 public boolean isShowingHistoryPanel() { 824 return mShowingHistoryPanel; 825 } 826 827 private void toggleImageStatePanel() { 828 final View view = findViewById(R.id.mainPanel); 829 final View viewList = findViewById(R.id.imageStatePanel); 830 831 if (mShowingHistoryPanel) { 832 findViewById(R.id.historyPanel).setVisibility(View.INVISIBLE); 833 mShowingHistoryPanel = false; 834 } 835 836 int translate = translateMainPanel(viewList); 837 if (!mShowingImageStatePanel) { 838 mShowingImageStatePanel = true; 839 view.animate().setDuration(200).x(translate) 840 .withLayer().withEndAction(new Runnable() { 841 @Override 842 public void run() { 843 viewList.setAlpha(0); 844 viewList.setVisibility(View.VISIBLE); 845 viewList.animate().setDuration(100) 846 .alpha(1.0f).start(); 847 } 848 }).start(); 849 } else { 850 mShowingImageStatePanel = false; 851 viewList.setVisibility(View.INVISIBLE); 852 view.animate().setDuration(200).x(0).withLayer() 853 .start(); 854 } 855 invalidateOptionsMenu(); 856 } 857 858 @Override 859 public void onConfigurationChanged(Configuration newConfig) 860 { 861 super.onConfigurationChanged(newConfig); 862 if (mShowingHistoryPanel) { 863 toggleHistoryPanel(); 864 } 865 } 866 867 // ////////////////////////////////////////////////////////////////////////////// 868 // history panel... 869 870 public void toggleHistoryPanel() { 871 final View view = findViewById(R.id.mainPanel); 872 final View viewList = findViewById(R.id.historyPanel); 873 874 if (mShowingImageStatePanel) { 875 findViewById(R.id.imageStatePanel).setVisibility(View.INVISIBLE); 876 mShowingImageStatePanel = false; 877 } 878 879 int translate = translateMainPanel(viewList); 880 if (!mShowingHistoryPanel) { 881 mShowingHistoryPanel = true; 882 view.animate().setDuration(200).x(translate) 883 .withLayer().withEndAction(new Runnable() { 884 @Override 885 public void run() { 886 viewList.setAlpha(0); 887 viewList.setVisibility(View.VISIBLE); 888 viewList.animate().setDuration(100) 889 .alpha(1.0f).start(); 890 } 891 }).start(); 892 } else { 893 mShowingHistoryPanel = false; 894 viewList.setVisibility(View.INVISIBLE); 895 view.animate().setDuration(200).x(0).withLayer() 896 .start(); 897 } 898 invalidateOptionsMenu(); 899 } 900 901 private void resetHistory() { 902 mNullFxFilter.onClick(mNullFxFilter); 903 mNullBorderFilter.onClick(mNullBorderFilter); 904 905 HistoryAdapter adapter = mImageShow.getHistory(); 906 adapter.reset(); 907 ImagePreset original = new ImagePreset(adapter.getItem(0)); 908 mImageShow.setImagePreset(original); 909 mPanelController.resetParameters(); 910 invalidateViews(); 911 } 912 913 // reset button in the history panel. 914 private OnClickListener createOnClickResetOperationsButton() { 915 return new View.OnClickListener() { 916 @Override 917 public void onClick(View v) { 918 919 resetHistory(); 920 } 921 }; 922 } 923 924 @Override 925 public void onBackPressed() { 926 if (mPanelController.onBackPressed()) { 927 saveImage(); 928 } 929 } 930 931 public void cannotLoadImage() { 932 CharSequence text = getString(R.string.cannot_load_image); 933 Toast toast = Toast.makeText(this, text, Toast.LENGTH_SHORT); 934 toast.show(); 935 finish(); 936 } 937 938 // ////////////////////////////////////////////////////////////////////////////// 939 940 public float getPixelsFromDip(float value) { 941 Resources r = getResources(); 942 return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, value, 943 r.getDisplayMetrics()); 944 } 945 946 public void useImagePreset(ImageSmallFilter imageSmallFilter, ImagePreset preset) { 947 if (preset == null) { 948 return; 949 } 950 951 if (mCurrentImageSmallFilter != null) { 952 mCurrentImageSmallFilter.setSelected(false); 953 } 954 mCurrentImageSmallFilter = imageSmallFilter; 955 mCurrentImageSmallFilter.setSelected(true); 956 957 ImagePreset copy = new ImagePreset(preset); 958 mImageShow.setImagePreset(copy); 959 if (preset.isFx()) { 960 // if it's an FX we rest the curve adjustment too 961 mImageCurves.resetCurve(); 962 } 963 invalidateViews(); 964 } 965 966 public void useImageFilter(ImageSmallFilter imageSmallFilter, ImageFilter imageFilter, 967 boolean setBorder) { 968 if (imageFilter == null) { 969 return; 970 } 971 972 if (mCurrentImageSmallFilter != null) { 973 mCurrentImageSmallFilter.setSelected(false); 974 } 975 mCurrentImageSmallFilter = imageSmallFilter; 976 mCurrentImageSmallFilter.setSelected(true); 977 978 ImagePreset oldPreset = mImageShow.getImagePreset(); 979 ImagePreset copy = new ImagePreset(oldPreset); 980 // TODO: use a numerical constant instead. 981 982 copy.add(imageFilter); 983 984 mImageShow.setImagePreset(copy); 985 invalidateViews(); 986 } 987 988 @Override 989 public void onItemClick(AdapterView<?> parent, View view, int position, 990 long id) { 991 mImageShow.onItemClick(position); 992 invalidateViews(); 993 } 994 995 public void pickImage() { 996 Intent intent = new Intent(); 997 intent.setType("image/*"); 998 intent.setAction(Intent.ACTION_GET_CONTENT); 999 startActivityForResult(Intent.createChooser(intent, getString(R.string.select_image)), 1000 SELECT_PICTURE); 1001 } 1002 1003 @Override 1004 public void onActivityResult(int requestCode, int resultCode, Intent data) { 1005 Log.v(LOGTAG, "onActivityResult"); 1006 if (resultCode == RESULT_OK) { 1007 if (requestCode == SELECT_PICTURE) { 1008 Uri selectedImageUri = data.getData(); 1009 startLoadBitmap(selectedImageUri); 1010 } 1011 } 1012 } 1013 1014 private boolean mSaveToExtraUri = false; 1015 private boolean mSaveAsWallpaper = false; 1016 private boolean mReturnAsExtra = false; 1017 private boolean outputted = false; 1018 1019 public void saveImage() { 1020 // boolean outputted = false; 1021 if (mCropExtras != null) { 1022 if (mCropExtras.getExtraOutput() != null) { 1023 mSaveToExtraUri = true; 1024 outputted = true; 1025 } 1026 if (mCropExtras.getSetAsWallpaper()) { 1027 mSaveAsWallpaper = true; 1028 outputted = true; 1029 } 1030 if (mCropExtras.getReturnData()) { 1031 1032 mReturnAsExtra = true; 1033 outputted = true; 1034 } 1035 1036 if (outputted) { 1037 mImageShow.getImagePreset().mGeoData.setUseCropExtrasFlag(true); 1038 showSavingProgress(null); 1039 mImageShow.returnFilteredResult(this); 1040 } 1041 } 1042 if (!outputted) { 1043 if (mImageShow.hasModifications()) { 1044 // Get the name of the album, to which the image will be saved 1045 File saveDir = SaveCopyTask.getFinalSaveDirectory(this, mImageLoader.getUri()); 1046 int bucketId = GalleryUtils.getBucketId(saveDir.getPath()); 1047 String albumName = LocalAlbum.getLocalizedName(getResources(), bucketId, null); 1048 showSavingProgress(albumName); 1049 mImageShow.saveImage(this, null); 1050 } else { 1051 done(); 1052 } 1053 } 1054 } 1055 1056 public void onFilteredResult(Bitmap filtered) { 1057 Intent intent = new Intent(); 1058 intent.putExtra(CropExtras.KEY_CROPPED_RECT, mImageShow.getImageCropBounds()); 1059 if (mSaveToExtraUri) { 1060 mImageShow.saveToUri(filtered, mCropExtras.getExtraOutput(), 1061 mCropExtras.getOutputFormat(), this); 1062 } 1063 if (mSaveAsWallpaper) { 1064 try { 1065 WallpaperManager.getInstance(this).setBitmap(filtered); 1066 } catch (IOException e) { 1067 Log.w(LOGTAG, "fail to set wall paper", e); 1068 } 1069 } 1070 if (mReturnAsExtra) { 1071 if (filtered != null) { 1072 int bmapSize = filtered.getRowBytes() * filtered.getHeight(); 1073 /* 1074 * Max size of Binder transaction buffer is 1Mb, so constrain 1075 * Bitmap to be somewhat less than this, otherwise we get 1076 * TransactionTooLargeExceptions. 1077 */ 1078 if (bmapSize > MAX_BMAP_IN_INTENT) { 1079 Log.w(LOGTAG, "Bitmap too large to be returned via intent"); 1080 } else { 1081 intent.putExtra(CropExtras.KEY_DATA, filtered); 1082 } 1083 } 1084 } 1085 setResult(RESULT_OK, intent); 1086 if (!mSaveToExtraUri) { 1087 done(); 1088 } 1089 } 1090 1091 public void done() { 1092 if (outputted) { 1093 hideSavingProgress(); 1094 } 1095 finish(); 1096 } 1097 1098 static { 1099 System.loadLibrary("jni_filtershow_filters"); 1100 } 1101 1102} 1103