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