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