2 * Copyright (C) 2012 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.gallery3d.filtershow;
19 import android.annotation.TargetApi;
20 import android.app.ActionBar;
21 import android.app.Activity;
22 import android.app.ProgressDialog;
23 import android.app.WallpaperManager;
24 import android.content.ContentValues;
25 import android.content.Intent;
26 import android.content.res.Configuration;
27 import android.content.res.Resources;
28 import android.graphics.Bitmap;
29 import android.graphics.BitmapFactory;
30 import android.graphics.Color;
31 import android.graphics.Point;
32 import android.graphics.drawable.Drawable;
33 import android.net.Uri;
34 import android.os.AsyncTask;
35 import android.os.Bundle;
36 import android.provider.MediaStore;
37 import android.util.DisplayMetrics;
38 import android.util.Log;
39 import android.util.TypedValue;
40 import android.view.Display;
41 import android.view.Menu;
42 import android.view.MenuItem;
43 import android.view.View;
44 import android.view.View.OnClickListener;
45 import android.view.WindowManager;
46 import android.widget.AdapterView;
47 import android.widget.AdapterView.OnItemClickListener;
48 import android.widget.ImageButton;
49 import android.widget.LinearLayout;
50 import android.widget.ListView;
51 import android.widget.SeekBar;
52 import android.widget.ShareActionProvider;
53 import android.widget.ShareActionProvider.OnShareTargetSelectedListener;
54 import android.widget.Toast;
56 import com.android.gallery3d.R;
57 import com.android.gallery3d.data.LocalAlbum;
58 import com.android.gallery3d.filtershow.cache.ImageLoader;
59 import com.android.gallery3d.filtershow.filters.ImageFilter;
60 import com.android.gallery3d.filtershow.filters.ImageFilterBorder;
61 import com.android.gallery3d.filtershow.filters.ImageFilterBwFilter;
62 import com.android.gallery3d.filtershow.filters.ImageFilterContrast;
63 import com.android.gallery3d.filtershow.filters.ImageFilterCurves;
64 import com.android.gallery3d.filtershow.filters.ImageFilterExposure;
65 import com.android.gallery3d.filtershow.filters.ImageFilterFx;
66 import com.android.gallery3d.filtershow.filters.ImageFilterHue;
67 import com.android.gallery3d.filtershow.filters.ImageFilterParametricBorder;
68 import com.android.gallery3d.filtershow.filters.ImageFilterRS;
69 import com.android.gallery3d.filtershow.filters.ImageFilterSaturated;
70 import com.android.gallery3d.filtershow.filters.ImageFilterShadows;
71 import com.android.gallery3d.filtershow.filters.ImageFilterSharpen;
72 import com.android.gallery3d.filtershow.filters.ImageFilterTinyPlanet;
73 import com.android.gallery3d.filtershow.filters.ImageFilterVibrance;
74 import com.android.gallery3d.filtershow.filters.ImageFilterVignette;
75 import com.android.gallery3d.filtershow.filters.ImageFilterWBalance;
76 import com.android.gallery3d.filtershow.imageshow.ImageBorder;
77 import com.android.gallery3d.filtershow.imageshow.ImageCrop;
78 import com.android.gallery3d.filtershow.imageshow.ImageFlip;
79 import com.android.gallery3d.filtershow.imageshow.ImageRedEyes;
80 import com.android.gallery3d.filtershow.imageshow.ImageRotate;
81 import com.android.gallery3d.filtershow.imageshow.ImageShow;
82 import com.android.gallery3d.filtershow.imageshow.ImageSmallBorder;
83 import com.android.gallery3d.filtershow.imageshow.ImageSmallFilter;
84 import com.android.gallery3d.filtershow.imageshow.ImageStraighten;
85 import com.android.gallery3d.filtershow.imageshow.ImageTinyPlanet;
86 import com.android.gallery3d.filtershow.imageshow.ImageZoom;
87 import com.android.gallery3d.filtershow.presets.ImagePreset;
88 import com.android.gallery3d.filtershow.provider.SharedImageProvider;
89 import com.android.gallery3d.filtershow.tools.SaveCopyTask;
90 import com.android.gallery3d.filtershow.ui.FramedTextButton;
91 import com.android.gallery3d.filtershow.ui.ImageButtonTitle;
92 import com.android.gallery3d.filtershow.ui.ImageCurves;
93 import com.android.gallery3d.filtershow.ui.Spline;
94 import com.android.gallery3d.util.GalleryUtils;
97 import java.io.IOException;
98 import java.lang.ref.WeakReference;
99 import java.util.Vector;
102 public class FilterShowActivity extends Activity implements OnItemClickListener,
103 OnShareTargetSelectedListener {
105 // fields for supporting crop action
106 public static final String CROP_ACTION = "com.android.camera.action.CROP";
107 private CropExtras mCropExtras = null;
109 public static final String TINY_PLANET_ACTION = "com.android.camera.action.TINY_PLANET";
110 public static final String LAUNCH_FULLSCREEN = "launch-fullscreen";
111 public static final int MAX_BMAP_IN_INTENT = 990000;
112 private final PanelController mPanelController = new PanelController();
113 private ImageLoader mImageLoader = null;
114 private ImageShow mImageShow = null;
115 private ImageCurves mImageCurves = null;
116 private ImageBorder mImageBorders = null;
117 private ImageRedEyes mImageRedEyes = null;
118 private ImageStraighten mImageStraighten = null;
119 private ImageZoom mImageZoom = null;
120 private ImageCrop mImageCrop = null;
121 private ImageRotate mImageRotate = null;
122 private ImageFlip mImageFlip = null;
123 private ImageTinyPlanet mImageTinyPlanet = null;
125 private View mListFx = null;
126 private View mListBorders = null;
127 private View mListGeometry = null;
128 private View mListColors = null;
129 private View mListFilterButtons = null;
130 private View mSaveButton = null;
132 private ImageButton mFxButton = null;
133 private ImageButton mBorderButton = null;
134 private ImageButton mGeometryButton = null;
135 private ImageButton mColorsButton = null;
137 private ImageSmallFilter mCurrentImageSmallFilter = null;
138 private static final int SELECT_PICTURE = 1;
139 private static final String LOGTAG = "FilterShowActivity";
140 protected static final boolean ANIMATE_PANELS = true;
141 private static int mImageBorderSize = 4; // in percent
143 private boolean mShowingHistoryPanel = false;
144 private boolean mShowingImageStatePanel = false;
146 private final Vector<ImageShow> mImageViews = new Vector<ImageShow>();
147 private final Vector<View> mListViews = new Vector<View>();
148 private final Vector<ImageButton> mBottomPanelButtons = new Vector<ImageButton>();
150 private ShareActionProvider mShareActionProvider;
151 private File mSharedOutputFile = null;
153 private boolean mSharingImage = false;
155 private WeakReference<ProgressDialog> mSavingProgressDialog;
156 private static final int SEEK_BAR_MAX = 600;
158 private LoadBitmapTask mLoadBitmapTask;
159 private ImageSmallFilter mNullFxFilter;
160 private ImageSmallFilter mNullBorderFilter;
163 public void onCreate(Bundle savedInstanceState) {
164 super.onCreate(savedInstanceState);
166 ImageFilterRS.setRenderScriptContext(this);
168 ImageShow.setDefaultBackgroundColor(getResources().getColor(R.color.background_screen));
169 ImageSmallFilter.setDefaultBackgroundColor(getResources().getColor(
170 R.color.background_main_toolbar));
171 // TODO: get those values from XML.
172 ImageZoom.setZoomedSize(getPixelsFromDip(256));
173 FramedTextButton.setTextSize((int) getPixelsFromDip(14));
174 FramedTextButton.setTrianglePadding((int) getPixelsFromDip(4));
175 FramedTextButton.setTriangleSize((int) getPixelsFromDip(10));
176 ImageShow.setTextSize((int) getPixelsFromDip(12));
177 ImageShow.setTextPadding((int) getPixelsFromDip(10));
178 ImageShow.setOriginalTextMargin((int) getPixelsFromDip(4));
179 ImageShow.setOriginalTextSize((int) getPixelsFromDip(18));
180 ImageShow.setOriginalText(getResources().getString(R.string.original_picture_text));
181 ImageButtonTitle.setTextSize((int) getPixelsFromDip(12));
182 ImageButtonTitle.setTextPadding((int) getPixelsFromDip(10));
183 ImageSmallFilter.setMargin((int) getPixelsFromDip(3));
184 ImageSmallFilter.setTextMargin((int) getPixelsFromDip(4));
185 Drawable curveHandle = getResources().getDrawable(R.drawable.camera_crop);
186 int curveHandleSize = (int) getResources().getDimension(R.dimen.crop_indicator_size);
187 Spline.setCurveHandle(curveHandle, curveHandleSize);
188 Spline.setCurveWidth((int) getPixelsFromDip(3));
190 setContentView(R.layout.filtershow_activity);
191 ActionBar actionBar = getActionBar();
192 actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
193 actionBar.setCustomView(R.layout.filtershow_actionbar);
195 mSaveButton = actionBar.getCustomView();
196 mSaveButton.setOnClickListener(new OnClickListener() {
198 public void onClick(View view) {
203 mImageLoader = new ImageLoader(this, getApplicationContext());
205 LinearLayout listFilters = (LinearLayout) findViewById(R.id.listFilters);
206 LinearLayout listBorders = (LinearLayout) findViewById(R.id.listBorders);
207 LinearLayout listColors = (LinearLayout) findViewById(R.id.listColorsFx);
209 mImageShow = (ImageShow) findViewById(R.id.imageShow);
210 mImageCurves = (ImageCurves) findViewById(R.id.imageCurves);
211 mImageBorders = (ImageBorder) findViewById(R.id.imageBorder);
212 mImageStraighten = (ImageStraighten) findViewById(R.id.imageStraighten);
213 mImageZoom = (ImageZoom) findViewById(R.id.imageZoom);
214 mImageCrop = (ImageCrop) findViewById(R.id.imageCrop);
215 mImageRotate = (ImageRotate) findViewById(R.id.imageRotate);
216 mImageFlip = (ImageFlip) findViewById(R.id.imageFlip);
217 mImageTinyPlanet = (ImageTinyPlanet) findViewById(R.id.imageTinyPlanet);
218 mImageRedEyes = (ImageRedEyes) findViewById(R.id.imageRedEyes);
220 mImageCrop.setAspectTextSize((int) getPixelsFromDip(18));
221 ImageCrop.setTouchTolerance((int) getPixelsFromDip(25));
222 ImageCrop.setMinCropSize((int) getPixelsFromDip(55));
223 mImageViews.add(mImageShow);
224 mImageViews.add(mImageCurves);
225 mImageViews.add(mImageBorders);
226 mImageViews.add(mImageStraighten);
227 mImageViews.add(mImageZoom);
228 mImageViews.add(mImageCrop);
229 mImageViews.add(mImageRotate);
230 mImageViews.add(mImageFlip);
231 mImageViews.add(mImageTinyPlanet);
232 mImageViews.add(mImageRedEyes);
233 for (ImageShow imageShow : mImageViews) {
234 mImageLoader.addCacheListener(imageShow);
237 mListFx = findViewById(R.id.fxList);
238 mListBorders = findViewById(R.id.bordersList);
239 mListGeometry = findViewById(R.id.geometryList);
240 mListFilterButtons = findViewById(R.id.filterButtonsList);
241 mListColors = findViewById(R.id.colorsFxList);
242 mListViews.add(mListFx);
243 mListViews.add(mListBorders);
244 mListViews.add(mListGeometry);
245 mListViews.add(mListFilterButtons);
246 mListViews.add(mListColors);
248 mFxButton = (ImageButton) findViewById(R.id.fxButton);
249 mBorderButton = (ImageButton) findViewById(R.id.borderButton);
250 mGeometryButton = (ImageButton) findViewById(R.id.geometryButton);
251 mColorsButton = (ImageButton) findViewById(R.id.colorsButton);
253 mImageShow.setImageLoader(mImageLoader);
254 mImageCurves.setImageLoader(mImageLoader);
255 mImageCurves.setMaster(mImageShow);
256 mImageBorders.setImageLoader(mImageLoader);
257 mImageBorders.setMaster(mImageShow);
258 mImageStraighten.setImageLoader(mImageLoader);
259 mImageStraighten.setMaster(mImageShow);
260 mImageZoom.setImageLoader(mImageLoader);
261 mImageZoom.setMaster(mImageShow);
262 mImageCrop.setImageLoader(mImageLoader);
263 mImageCrop.setMaster(mImageShow);
264 mImageRotate.setImageLoader(mImageLoader);
265 mImageRotate.setMaster(mImageShow);
266 mImageFlip.setImageLoader(mImageLoader);
267 mImageFlip.setMaster(mImageShow);
268 mImageTinyPlanet.setImageLoader(mImageLoader);
269 mImageTinyPlanet.setMaster(mImageShow);
270 mImageRedEyes.setImageLoader(mImageLoader);
271 mImageRedEyes.setMaster(mImageShow);
273 mPanelController.setActivity(this);
275 mPanelController.addImageView(findViewById(R.id.imageShow));
276 mPanelController.addImageView(findViewById(R.id.imageCurves));
277 mPanelController.addImageView(findViewById(R.id.imageBorder));
278 mPanelController.addImageView(findViewById(R.id.imageStraighten));
279 mPanelController.addImageView(findViewById(R.id.imageCrop));
280 mPanelController.addImageView(findViewById(R.id.imageRotate));
281 mPanelController.addImageView(findViewById(R.id.imageFlip));
282 mPanelController.addImageView(findViewById(R.id.imageZoom));
283 mPanelController.addImageView(findViewById(R.id.imageTinyPlanet));
284 mPanelController.addImageView(findViewById(R.id.imageRedEyes));
286 mPanelController.addPanel(mFxButton, mListFx, 0);
287 mPanelController.addPanel(mBorderButton, mListBorders, 1);
289 mPanelController.addPanel(mGeometryButton, mListGeometry, 2);
290 mPanelController.addComponent(mGeometryButton, findViewById(R.id.straightenButton));
291 mPanelController.addComponent(mGeometryButton, findViewById(R.id.cropButton));
292 mPanelController.addComponent(mGeometryButton, findViewById(R.id.rotateButton));
293 mPanelController.addComponent(mGeometryButton, findViewById(R.id.flipButton));
294 mPanelController.addComponent(mGeometryButton, findViewById(R.id.redEyeButton));
296 mPanelController.addPanel(mColorsButton, mListColors, 3);
298 ImageFilter[] filters = {
299 new ImageFilterTinyPlanet(),
300 new ImageFilterWBalance(),
301 new ImageFilterExposure(),
302 new ImageFilterVignette(),
303 new ImageFilterContrast(),
304 new ImageFilterShadows(),
305 new ImageFilterVibrance(),
306 new ImageFilterSharpen(),
307 new ImageFilterCurves(),
308 new ImageFilterHue(),
309 new ImageFilterSaturated(),
310 new ImageFilterBwFilter()
313 for (int i = 0; i < filters.length; i++) {
314 ImageSmallFilter fView = new ImageSmallFilter(this);
315 filters[i].setParameter(filters[i].getPreviewParameter());
316 filters[i].setName(getString(filters[i].getTextId()));
317 fView.setImageFilter(filters[i]);
318 fView.setController(this);
319 fView.setImageLoader(mImageLoader);
320 fView.setId(filters[i].getButtonId());
321 if (filters[i].getOverlayBitmaps() != 0) {
322 Bitmap bitmap = BitmapFactory.decodeResource(getResources(),
323 filters[i].getOverlayBitmaps());
324 fView.setOverlayBitmap(bitmap);
326 mPanelController.addComponent(mColorsButton, fView);
327 mPanelController.addFilter(filters[i]);
328 listColors.addView(fView);
331 mPanelController.addView(findViewById(R.id.applyEffect));
332 mPanelController.addView(findViewById(R.id.pickCurvesChannel));
333 mPanelController.addView(findViewById(R.id.aspect));
334 findViewById(R.id.resetOperationsButton).setOnClickListener(
335 createOnClickResetOperationsButton());
337 ListView operationsList = (ListView) findViewById(R.id.operationsList);
338 operationsList.setAdapter(mImageShow.getHistory());
339 operationsList.setOnItemClickListener(this);
340 ListView imageStateList = (ListView) findViewById(R.id.imageStateList);
341 imageStateList.setAdapter(mImageShow.getImageStateAdapter());
342 mImageLoader.setAdapter(mImageShow.getHistory());
344 fillListImages(listFilters);
345 fillListBorders(listBorders);
347 SeekBar seekBar = (SeekBar) findViewById(R.id.filterSeekBar);
348 seekBar.setMax(SEEK_BAR_MAX);
350 mImageShow.setSeekBar(seekBar);
351 mImageZoom.setSeekBar(seekBar);
352 mImageTinyPlanet.setSeekBar(seekBar);
353 mPanelController.setRowPanel(findViewById(R.id.secondRowPanel));
354 mPanelController.setUtilityPanel(this, findViewById(R.id.filterButtonsList),
355 findViewById(R.id.applyEffect), findViewById(R.id.aspect),
356 findViewById(R.id.pickCurvesChannel));
357 mPanelController.setMasterImage(mImageShow);
358 mPanelController.setCurrentPanel(mFxButton);
359 Intent intent = getIntent();
360 if (intent.getBooleanExtra(LAUNCH_FULLSCREEN, false)) {
361 getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
364 if (intent.getData() != null) {
365 startLoadBitmap(intent.getData());
370 // Handle behavior for various actions
371 String action = intent.getAction();
372 if (action.equalsIgnoreCase(CROP_ACTION)) {
373 Bundle extras = intent.getExtras();
374 if (extras != null) {
375 mCropExtras = new CropExtras(extras.getInt(CropExtras.KEY_OUTPUT_X, 0),
376 extras.getInt(CropExtras.KEY_OUTPUT_Y, 0),
377 extras.getBoolean(CropExtras.KEY_SCALE, true) &&
378 extras.getBoolean(CropExtras.KEY_SCALE_UP_IF_NEEDED, false),
379 extras.getInt(CropExtras.KEY_ASPECT_X, 0),
380 extras.getInt(CropExtras.KEY_ASPECT_Y, 0),
381 extras.getBoolean(CropExtras.KEY_SET_AS_WALLPAPER, false),
382 extras.getBoolean(CropExtras.KEY_RETURN_DATA, false),
383 (Uri) extras.getParcelable(MediaStore.EXTRA_OUTPUT),
384 extras.getString(CropExtras.KEY_OUTPUT_FORMAT),
385 extras.getBoolean(CropExtras.KEY_SHOW_WHEN_LOCKED, false),
386 extras.getFloat(CropExtras.KEY_SPOTLIGHT_X),
387 extras.getFloat(CropExtras.KEY_SPOTLIGHT_Y));
389 if (mCropExtras.getShowWhenLocked()) {
390 getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
392 mImageShow.getImagePreset().mGeoData.setCropExtras(mCropExtras);
394 mImageCrop.setExtras(mCropExtras);
395 String s = getString(R.string.Fixed);
396 mImageCrop.setAspectString(s);
397 mImageCrop.setCropActionFlag(true);
398 mPanelController.setFixedAspect(mCropExtras.getAspectX() > 0
399 && mCropExtras.getAspectY() > 0);
401 mPanelController.showComponent(findViewById(R.id.cropButton));
402 } else if (action.equalsIgnoreCase(TINY_PLANET_ACTION)) {
403 mPanelController.showComponent(findViewById(R.id.tinyplanetButton));
407 private void startLoadBitmap(Uri uri) {
408 final View filters = findViewById(R.id.filtersPanel);
409 final View loading = findViewById(R.id.loading);
410 loading.setVisibility(View.VISIBLE);
411 filters.setVisibility(View.INVISIBLE);
412 View tinyPlanetView = findViewById(R.id.tinyplanetButton);
413 if (tinyPlanetView != null) {
414 tinyPlanetView.setVisibility(View.GONE);
416 mLoadBitmapTask = new LoadBitmapTask(tinyPlanetView);
417 mLoadBitmapTask.execute(uri);
420 private class LoadBitmapTask extends AsyncTask<Uri, Boolean, Boolean> {
421 View mTinyPlanetButton;
424 public LoadBitmapTask(View button) {
425 mTinyPlanetButton = button;
426 mBitmapSize = getScreenImageSize();
430 protected Boolean doInBackground(Uri... params) {
431 if (!mImageLoader.loadBitmap(params[0], mBitmapSize)) {
434 publishProgress(mImageLoader.queryLightCycle360());
439 protected void onProgressUpdate(Boolean... values) {
440 super.onProgressUpdate(values);
444 final View filters = findViewById(R.id.filtersPanel);
445 final View loading = findViewById(R.id.loading);
446 loading.setVisibility(View.GONE);
447 filters.setVisibility(View.VISIBLE);
449 mTinyPlanetButton.setVisibility(View.VISIBLE);
454 protected void onPostExecute(Boolean result) {
462 mLoadBitmapTask = null;
463 super.onPostExecute(result);
469 protected void onDestroy() {
470 if (mLoadBitmapTask != null) {
471 mLoadBitmapTask.cancel(false);
476 private int translateMainPanel(View viewPanel) {
477 int accessoryPanelWidth = viewPanel.getWidth();
478 int mainViewWidth = findViewById(R.id.mainView).getWidth();
479 int mainPanelWidth = mImageShow.getDisplayedImageBounds().width();
480 if (mainPanelWidth == 0) {
481 mainPanelWidth = mainViewWidth;
483 int filtersPanelWidth = findViewById(R.id.filtersPanel).getWidth();
484 if (mainPanelWidth < filtersPanelWidth) {
485 mainPanelWidth = filtersPanelWidth;
487 int leftOver = mainViewWidth - mainPanelWidth - accessoryPanelWidth;
489 return -accessoryPanelWidth;
494 private int getScreenImageSize() {
495 DisplayMetrics metrics = new DisplayMetrics();
496 Display display = getWindowManager().getDefaultDisplay();
497 Point size = new Point();
498 display.getSize(size);
499 display.getMetrics(metrics);
500 int msize = Math.min(size.x, size.y);
501 return (133 * msize) / metrics.densityDpi;
504 private void showSavingProgress(String albumName) {
505 ProgressDialog progress;
506 if (mSavingProgressDialog != null) {
507 progress = mSavingProgressDialog.get();
508 if (progress != null) {
513 // TODO: Allow cancellation of the saving process
515 if (albumName == null) {
516 progressText = getString(R.string.saving_image);
518 progressText = getString(R.string.filtershow_saving_image, albumName);
520 progress = ProgressDialog.show(this, "", progressText, true, false);
521 mSavingProgressDialog = new WeakReference<ProgressDialog>(progress);
524 private void hideSavingProgress() {
525 if (mSavingProgressDialog != null) {
526 ProgressDialog progress = mSavingProgressDialog.get();
527 if (progress != null)
532 public void completeSaveImage(Uri saveUri) {
533 if (mSharingImage && mSharedOutputFile != null) {
534 // Image saved, we unblock the content provider
535 Uri uri = Uri.withAppendedPath(SharedImageProvider.CONTENT_URI,
536 Uri.encode(mSharedOutputFile.getAbsolutePath()));
537 ContentValues values = new ContentValues();
538 values.put(SharedImageProvider.PREPARE, false);
539 getContentResolver().insert(uri, values);
541 setResult(RESULT_OK, new Intent().setData(saveUri));
542 hideSavingProgress();
547 public boolean onShareTargetSelected(ShareActionProvider arg0, Intent arg1) {
548 // First, let's tell the SharedImageProvider that it will need to wait
550 Uri uri = Uri.withAppendedPath(SharedImageProvider.CONTENT_URI,
551 Uri.encode(mSharedOutputFile.getAbsolutePath()));
552 ContentValues values = new ContentValues();
553 values.put(SharedImageProvider.PREPARE, true);
554 getContentResolver().insert(uri, values);
555 mSharingImage = true;
557 // Process and save the image in the background.
558 showSavingProgress(null);
559 mImageShow.saveImage(this, mSharedOutputFile);
563 private Intent getDefaultShareIntent() {
564 Intent intent = new Intent(Intent.ACTION_SEND);
565 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
566 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
567 intent.setType(SharedImageProvider.MIME_TYPE);
568 mSharedOutputFile = SaveCopyTask.getNewFile(this, mImageLoader.getUri());
569 Uri uri = Uri.withAppendedPath(SharedImageProvider.CONTENT_URI,
570 Uri.encode(mSharedOutputFile.getAbsolutePath()));
571 intent.putExtra(Intent.EXTRA_STREAM, uri);
576 public boolean onCreateOptionsMenu(Menu menu) {
577 getMenuInflater().inflate(R.menu.filtershow_activity_menu, menu);
578 MenuItem showHistory = menu.findItem(R.id.operationsButton);
579 if (mShowingHistoryPanel) {
580 showHistory.setTitle(R.string.hide_history_panel);
582 showHistory.setTitle(R.string.show_history_panel);
584 MenuItem showState = menu.findItem(R.id.showImageStateButton);
585 if (mShowingImageStatePanel) {
586 showState.setTitle(R.string.hide_imagestate_panel);
588 showState.setTitle(R.string.show_imagestate_panel);
590 mShareActionProvider = (ShareActionProvider) menu.findItem(R.id.menu_share)
591 .getActionProvider();
592 mShareActionProvider.setShareIntent(getDefaultShareIntent());
593 mShareActionProvider.setOnShareTargetSelectedListener(this);
595 MenuItem undoItem = menu.findItem(R.id.undoButton);
596 MenuItem redoItem = menu.findItem(R.id.redoButton);
597 MenuItem resetItem = menu.findItem(R.id.resetHistoryButton);
598 mImageShow.getHistory().setMenuItems(undoItem, redoItem, resetItem);
603 public void onPause() {
605 if (mShareActionProvider != null) {
606 mShareActionProvider.setOnShareTargetSelectedListener(null);
611 public void onResume() {
613 if (mShareActionProvider != null) {
614 mShareActionProvider.setOnShareTargetSelectedListener(this);
619 public boolean onOptionsItemSelected(MenuItem item) {
620 switch (item.getItemId()) {
621 case R.id.undoButton: {
622 HistoryAdapter adapter = mImageShow.getHistory();
623 int position = adapter.undo();
624 mImageShow.onItemClick(position);
625 mImageShow.showToast("Undo");
629 case R.id.redoButton: {
630 HistoryAdapter adapter = mImageShow.getHistory();
631 int position = adapter.redo();
632 mImageShow.onItemClick(position);
633 mImageShow.showToast("Redo");
637 case R.id.resetHistoryButton: {
641 case R.id.showImageStateButton: {
642 toggleImageStatePanel();
645 case R.id.operationsButton: {
646 toggleHistoryPanel();
649 case android.R.id.home: {
657 public void enableSave(boolean enable) {
658 if (mSaveButton != null)
659 mSaveButton.setEnabled(enable);
662 private void fillListImages(LinearLayout listFilters) {
663 // TODO: use listview
664 // TODO: load the filters straight from the filesystem
666 ImageFilterFx[] fxArray = new ImageFilterFx[18];
670 R.drawable.filtershow_fx_0005_punch,
671 R.drawable.filtershow_fx_0000_vintage,
672 R.drawable.filtershow_fx_0004_bw_contrast,
673 R.drawable.filtershow_fx_0002_bleach,
674 R.drawable.filtershow_fx_0001_instant,
675 R.drawable.filtershow_fx_0007_washout,
676 R.drawable.filtershow_fx_0003_blue_crush,
677 R.drawable.filtershow_fx_0008_washout_color,
678 R.drawable.filtershow_fx_0006_x_process
683 R.string.ffx_vintage,
684 R.string.ffx_bw_contrast,
686 R.string.ffx_instant,
687 R.string.ffx_washout,
688 R.string.ffx_blue_crush,
689 R.string.ffx_washout_color,
690 R.string.ffx_x_process
693 ImagePreset preset = new ImagePreset(getString(R.string.history_original)); // empty
694 preset.setImageLoader(mImageLoader);
695 mNullFxFilter = new ImageSmallFilter(this);
697 mNullFxFilter.setSelected(true);
698 mCurrentImageSmallFilter = mNullFxFilter;
700 mNullFxFilter.setImageFilter(new ImageFilterFx(null, getString(R.string.none)));
702 mNullFxFilter.setController(this);
703 mNullFxFilter.setImageLoader(mImageLoader);
704 listFilters.addView(mNullFxFilter);
705 ImageSmallFilter previousFilter = mNullFxFilter;
707 BitmapFactory.Options o = new BitmapFactory.Options();
710 for (int i = 0; i < drawid.length; i++) {
711 Bitmap b = BitmapFactory.decodeResource(getResources(), drawid[i], o);
712 fxArray[p++] = new ImageFilterFx(b, getString(fxNameid[i]));
714 ImageSmallFilter filter;
715 for (int i = 0; i < p; i++) {
716 filter = new ImageSmallFilter(this);
717 filter.setImageFilter(fxArray[i]);
718 filter.setController(this);
719 filter.setNulfilter(mNullFxFilter);
720 filter.setImageLoader(mImageLoader);
721 listFilters.addView(filter);
722 previousFilter = filter;
725 // Default preset (original)
726 mImageShow.setImagePreset(preset);
729 private void fillListBorders(LinearLayout listBorders) {
730 // TODO: use listview
731 // TODO: load the borders straight from the filesystem
733 ImageFilter[] borders = new ImageFilter[12];
734 borders[p++] = new ImageFilterBorder(null);
736 Drawable npd1 = getResources().getDrawable(R.drawable.filtershow_border_4x5);
737 borders[p++] = new ImageFilterBorder(npd1);
738 Drawable npd2 = getResources().getDrawable(R.drawable.filtershow_border_brush);
739 borders[p++] = new ImageFilterBorder(npd2);
740 Drawable npd3 = getResources().getDrawable(R.drawable.filtershow_border_grunge);
741 borders[p++] = new ImageFilterBorder(npd3);
742 Drawable npd4 = getResources().getDrawable(R.drawable.filtershow_border_sumi_e);
743 borders[p++] = new ImageFilterBorder(npd4);
744 Drawable npd5 = getResources().getDrawable(R.drawable.filtershow_border_tape);
745 borders[p++] = new ImageFilterBorder(npd5);
746 borders[p++] = new ImageFilterParametricBorder(Color.BLACK, mImageBorderSize, 0);
747 borders[p++] = new ImageFilterParametricBorder(Color.BLACK, mImageBorderSize,
749 borders[p++] = new ImageFilterParametricBorder(Color.WHITE, mImageBorderSize, 0);
750 borders[p++] = new ImageFilterParametricBorder(Color.WHITE, mImageBorderSize,
752 int creamColor = Color.argb(255, 237, 237, 227);
753 borders[p++] = new ImageFilterParametricBorder(creamColor, mImageBorderSize, 0);
754 borders[p++] = new ImageFilterParametricBorder(creamColor, mImageBorderSize,
757 ImageSmallFilter previousFilter = null;
758 for (int i = 0; i < p; i++) {
759 ImageSmallBorder filter = new ImageSmallBorder(this);
760 if (i == 0) { // save the first to reset it
761 mNullBorderFilter = filter;
763 filter.setNulfilter(mNullBorderFilter);
765 borders[i].setName(getString(R.string.borders));
766 filter.setImageFilter(borders[i]);
767 filter.setController(this);
768 filter.setBorder(true);
769 filter.setImageLoader(mImageLoader);
770 filter.setShowTitle(false);
771 listBorders.addView(filter);
772 previousFilter = filter;
776 // //////////////////////////////////////////////////////////////////////////////
777 // Some utility functions
778 // TODO: finish the cleanup.
780 public void showOriginalViews(boolean value) {
781 for (ImageShow views : mImageViews) {
782 views.showOriginal(value);
786 public void invalidateViews() {
787 for (ImageShow views : mImageViews) {
793 public void hideListViews() {
794 for (View view : mListViews) {
795 view.setVisibility(View.GONE);
799 public void hideImageViews() {
800 mImageShow.setShowControls(false); // reset
801 for (View view : mImageViews) {
802 view.setVisibility(View.GONE);
806 public void unselectBottomPanelButtons() {
807 for (ImageButton button : mBottomPanelButtons) {
808 button.setSelected(false);
812 public void unselectPanelButtons(Vector<ImageButton> buttons) {
813 for (ImageButton button : buttons) {
814 button.setSelected(false);
818 // //////////////////////////////////////////////////////////////////////////////
819 // imageState panel...
821 public boolean isShowingHistoryPanel() {
822 return mShowingHistoryPanel;
825 private void toggleImageStatePanel() {
826 final View view = findViewById(R.id.mainPanel);
827 final View viewList = findViewById(R.id.imageStatePanel);
829 if (mShowingHistoryPanel) {
830 findViewById(R.id.historyPanel).setVisibility(View.INVISIBLE);
831 mShowingHistoryPanel = false;
834 int translate = translateMainPanel(viewList);
835 if (!mShowingImageStatePanel) {
836 mShowingImageStatePanel = true;
837 view.animate().setDuration(200).x(translate)
838 .withLayer().withEndAction(new Runnable() {
841 viewList.setAlpha(0);
842 viewList.setVisibility(View.VISIBLE);
843 viewList.animate().setDuration(100)
844 .alpha(1.0f).start();
848 mShowingImageStatePanel = false;
849 viewList.setVisibility(View.INVISIBLE);
850 view.animate().setDuration(200).x(0).withLayer()
853 invalidateOptionsMenu();
857 public void onConfigurationChanged(Configuration newConfig)
859 super.onConfigurationChanged(newConfig);
860 if (mShowingHistoryPanel) {
861 toggleHistoryPanel();
865 // //////////////////////////////////////////////////////////////////////////////
868 public void toggleHistoryPanel() {
869 final View view = findViewById(R.id.mainPanel);
870 final View viewList = findViewById(R.id.historyPanel);
872 if (mShowingImageStatePanel) {
873 findViewById(R.id.imageStatePanel).setVisibility(View.INVISIBLE);
874 mShowingImageStatePanel = false;
877 int translate = translateMainPanel(viewList);
878 if (!mShowingHistoryPanel) {
879 mShowingHistoryPanel = true;
880 view.animate().setDuration(200).x(translate)
881 .withLayer().withEndAction(new Runnable() {
884 viewList.setAlpha(0);
885 viewList.setVisibility(View.VISIBLE);
886 viewList.animate().setDuration(100)
887 .alpha(1.0f).start();
891 mShowingHistoryPanel = false;
892 viewList.setVisibility(View.INVISIBLE);
893 view.animate().setDuration(200).x(0).withLayer()
896 invalidateOptionsMenu();
899 private void resetHistory() {
900 mNullFxFilter.onClick(mNullFxFilter);
901 mNullBorderFilter.onClick(mNullBorderFilter);
903 HistoryAdapter adapter = mImageShow.getHistory();
905 ImagePreset original = new ImagePreset(adapter.getItem(0));
906 mImageShow.setImagePreset(original);
907 mPanelController.resetParameters();
911 // reset button in the history panel.
912 private OnClickListener createOnClickResetOperationsButton() {
913 return new View.OnClickListener() {
915 public void onClick(View v) {
923 public void onBackPressed() {
924 if (mPanelController.onBackPressed()) {
929 public void cannotLoadImage() {
930 CharSequence text = getString(R.string.cannot_load_image);
931 Toast toast = Toast.makeText(this, text, Toast.LENGTH_SHORT);
936 // //////////////////////////////////////////////////////////////////////////////
938 public float getPixelsFromDip(float value) {
939 Resources r = getResources();
940 return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, value,
941 r.getDisplayMetrics());
944 public void useImagePreset(ImageSmallFilter imageSmallFilter, ImagePreset preset) {
945 if (preset == null) {
949 if (mCurrentImageSmallFilter != null) {
950 mCurrentImageSmallFilter.setSelected(false);
952 mCurrentImageSmallFilter = imageSmallFilter;
953 mCurrentImageSmallFilter.setSelected(true);
955 ImagePreset copy = new ImagePreset(preset);
956 mImageShow.setImagePreset(copy);
958 // if it's an FX we rest the curve adjustment too
959 mImageCurves.resetCurve();
964 public void useImageFilter(ImageSmallFilter imageSmallFilter, ImageFilter imageFilter,
966 if (imageFilter == null) {
970 if (mCurrentImageSmallFilter != null) {
971 mCurrentImageSmallFilter.setSelected(false);
973 mCurrentImageSmallFilter = imageSmallFilter;
974 mCurrentImageSmallFilter.setSelected(true);
976 ImagePreset oldPreset = mImageShow.getImagePreset();
977 ImagePreset copy = new ImagePreset(oldPreset);
978 // TODO: use a numerical constant instead.
980 copy.add(imageFilter);
982 mImageShow.setImagePreset(copy);
987 public void onItemClick(AdapterView<?> parent, View view, int position,
989 mImageShow.onItemClick(position);
993 public void pickImage() {
994 Intent intent = new Intent();
995 intent.setType("image/*");
996 intent.setAction(Intent.ACTION_GET_CONTENT);
997 startActivityForResult(Intent.createChooser(intent, getString(R.string.select_image)),
1002 public void onActivityResult(int requestCode, int resultCode, Intent data) {
1003 Log.v(LOGTAG, "onActivityResult");
1004 if (resultCode == RESULT_OK) {
1005 if (requestCode == SELECT_PICTURE) {
1006 Uri selectedImageUri = data.getData();
1007 startLoadBitmap(selectedImageUri);
1012 private boolean mSaveToExtraUri = false;
1013 private boolean mSaveAsWallpaper = false;
1014 private boolean mReturnAsExtra = false;
1015 private boolean outputted = false;
1017 public void saveImage() {
1018 // boolean outputted = false;
1019 if (mCropExtras != null) {
1020 if (mCropExtras.getExtraOutput() != null) {
1021 mSaveToExtraUri = true;
1024 if (mCropExtras.getSetAsWallpaper()) {
1025 mSaveAsWallpaper = true;
1028 if (mCropExtras.getReturnData()) {
1030 mReturnAsExtra = true;
1035 mImageShow.getImagePreset().mGeoData.setUseCropExtrasFlag(true);
1036 showSavingProgress(null);
1037 mImageShow.returnFilteredResult(this);
1041 if (mImageShow.hasModifications()) {
1042 // Get the name of the album, to which the image will be saved
1043 File saveDir = SaveCopyTask.getFinalSaveDirectory(this, mImageLoader.getUri());
1044 int bucketId = GalleryUtils.getBucketId(saveDir.getPath());
1045 String albumName = LocalAlbum.getLocalizedName(getResources(), bucketId, null);
1046 showSavingProgress(albumName);
1047 mImageShow.saveImage(this, null);
1054 public void onFilteredResult(Bitmap filtered) {
1055 Intent intent = new Intent();
1056 intent.putExtra(CropExtras.KEY_CROPPED_RECT, mImageShow.getImageCropBounds());
1057 if (mSaveToExtraUri) {
1058 mImageShow.saveToUri(filtered, mCropExtras.getExtraOutput(),
1059 mCropExtras.getOutputFormat(), this);
1061 if (mSaveAsWallpaper) {
1063 WallpaperManager.getInstance(this).setBitmap(filtered);
1064 } catch (IOException e) {
1065 Log.w(LOGTAG, "fail to set wall paper", e);
1068 if (mReturnAsExtra) {
1069 if (filtered != null) {
1070 int bmapSize = filtered.getRowBytes() * filtered.getHeight();
1072 * Max size of Binder transaction buffer is 1Mb, so constrain
1073 * Bitmap to be somewhat less than this, otherwise we get
1074 * TransactionTooLargeExceptions.
1076 if (bmapSize > MAX_BMAP_IN_INTENT) {
1077 Log.w(LOGTAG, "Bitmap too large to be returned via intent");
1079 intent.putExtra(CropExtras.KEY_DATA, filtered);
1083 setResult(RESULT_OK, intent);
1084 if (!mSaveToExtraUri) {
1089 public void done() {
1091 hideSavingProgress();
1097 System.loadLibrary("jni_filtershow_filters");