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