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.app.ActionBar;
20 import android.app.Activity;
21 import android.app.ProgressDialog;
22 import android.app.WallpaperManager;
23 import android.content.ContentValues;
24 import android.content.Context;
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.LayoutInflater;
42 import android.view.Menu;
43 import android.view.MenuItem;
44 import android.view.View;
45 import android.view.View.OnClickListener;
46 import android.view.WindowManager;
47 import android.widget.*;
48 import android.widget.AdapterView.OnItemClickListener;
49 import android.widget.ShareActionProvider.OnShareTargetSelectedListener;
51 import com.android.gallery3d.R;
52 import com.android.gallery3d.data.LocalAlbum;
53 import com.android.gallery3d.filtershow.cache.FilteringPipeline;
54 import com.android.gallery3d.filtershow.cache.ImageLoader;
55 import com.android.gallery3d.filtershow.editors.BasicEditor;
56 import com.android.gallery3d.filtershow.editors.EditorDraw;
57 import com.android.gallery3d.filtershow.editors.EditorManager;
58 import com.android.gallery3d.filtershow.editors.EditorRedEye;
59 import com.android.gallery3d.filtershow.editors.ImageOnlyEditor;
60 import com.android.gallery3d.filtershow.editors.EditorTinyPlanet;
61 import com.android.gallery3d.filtershow.filters.*;
62 import com.android.gallery3d.filtershow.imageshow.ImageCrop;
63 import com.android.gallery3d.filtershow.imageshow.ImageDraw;
64 import com.android.gallery3d.filtershow.imageshow.ImageFlip;
65 import com.android.gallery3d.filtershow.imageshow.ImageRedEye;
66 import com.android.gallery3d.filtershow.imageshow.ImageRotate;
67 import com.android.gallery3d.filtershow.imageshow.ImageShow;
68 import com.android.gallery3d.filtershow.imageshow.ImageStraighten;
69 import com.android.gallery3d.filtershow.imageshow.ImageTinyPlanet;
70 import com.android.gallery3d.filtershow.imageshow.ImageZoom;
71 import com.android.gallery3d.filtershow.imageshow.MasterImage;
72 import com.android.gallery3d.filtershow.presets.ImagePreset;
73 import com.android.gallery3d.filtershow.provider.SharedImageProvider;
74 import com.android.gallery3d.filtershow.tools.BitmapTask;
75 import com.android.gallery3d.filtershow.tools.SaveCopyTask;
76 import com.android.gallery3d.filtershow.ui.FilterIconButton;
77 import com.android.gallery3d.filtershow.ui.FramedTextButton;
78 import com.android.gallery3d.filtershow.ui.Spline;
79 import com.android.gallery3d.util.GalleryUtils;
82 import java.io.IOException;
83 import java.lang.ref.WeakReference;
84 import java.util.Vector;
86 public class FilterShowActivity extends Activity implements OnItemClickListener,
87 OnShareTargetSelectedListener {
89 // fields for supporting crop action
90 public static final String CROP_ACTION = "com.android.camera.action.CROP";
91 private CropExtras mCropExtras = null;
92 private String mAction = "";
93 MasterImage mMasterImage = null;
95 public static final String TINY_PLANET_ACTION = "com.android.camera.action.TINY_PLANET";
96 public static final String LAUNCH_FULLSCREEN = "launch-fullscreen";
97 public static final int MAX_BMAP_IN_INTENT = 990000;
98 private final PanelController mPanelController = new PanelController();
99 private ImageLoader mImageLoader = null;
100 private ImageShow mImageShow = null;
101 private ImageDraw mImageDraw = null;
102 private ImageStraighten mImageStraighten = null;
103 private ImageCrop mImageCrop = null;
104 private ImageRotate mImageRotate = null;
105 private ImageFlip mImageFlip = null;
106 private ImageTinyPlanet mImageTinyPlanet = null;
108 private View mListFx = null;
109 private View mListBorders = null;
110 private View mListGeometry = null;
111 private View mListColors = null;
112 private View mListFilterButtons = null;
113 private View mSaveButton = null;
115 private ImageButton mFxButton = null;
116 private ImageButton mBorderButton = null;
117 private ImageButton mGeometryButton = null;
118 private ImageButton mColorsButton = null;
120 private LinearLayout listColors = null;
121 private LinearLayout listFilters = null;
122 private LinearLayout listBorders = null;
124 private EditorPlaceHolder mEditorPlaceHolder = new EditorPlaceHolder(this);
126 private static final int SELECT_PICTURE = 1;
127 private static final String LOGTAG = "FilterShowActivity";
128 protected static final boolean ANIMATE_PANELS = true;
129 private static int mImageBorderSize = 4; // in percent
131 private boolean mShowingHistoryPanel = false;
132 private boolean mShowingImageStatePanel = false;
134 private final Vector<ImageShow> mImageViews = new Vector<ImageShow>();
135 private final Vector<View> mListViews = new Vector<View>();
136 private final Vector<ImageButton> mBottomPanelButtons = new Vector<ImageButton>();
138 private ShareActionProvider mShareActionProvider;
139 private File mSharedOutputFile = null;
141 private boolean mSharingImage = false;
143 private WeakReference<ProgressDialog> mSavingProgressDialog;
144 private static final int SEEK_BAR_MAX = 600;
146 private LoadBitmapTask mLoadBitmapTask;
147 private FilterIconButton mNullFxFilter;
148 private FilterIconButton mNullBorderFilter;
149 private int mIconSeedSize = 140;
153 public void onCreate(Bundle savedInstanceState) {
154 super.onCreate(savedInstanceState);
157 Resources res = getResources();
159 ImageFilterRS.setRenderScriptContext(this);
161 ImageShow.setDefaultBackgroundColor(res.getColor(R.color.background_screen));
162 // TODO: get those values from XML.
163 ImageZoom.setZoomedSize(getPixelsFromDip(256));
164 FramedTextButton.setTextSize((int) getPixelsFromDip(14));
165 FramedTextButton.setTrianglePadding((int) getPixelsFromDip(4));
166 FramedTextButton.setTriangleSize((int) getPixelsFromDip(10));
167 ImageShow.setTextSize((int) getPixelsFromDip(12));
168 ImageShow.setTextPadding((int) getPixelsFromDip(10));
169 ImageShow.setOriginalTextMargin((int) getPixelsFromDip(4));
170 ImageShow.setOriginalTextSize((int) getPixelsFromDip(18));
171 ImageShow.setOriginalText(res.getString(R.string.original_picture_text));
172 mIconSeedSize = res.getDimensionPixelSize(R.dimen.thumbnail_size);
174 Drawable curveHandle = res.getDrawable(R.drawable.camera_crop);
175 int curveHandleSize = (int) res.getDimension(R.dimen.crop_indicator_size);
176 Spline.setCurveHandle(curveHandle, curveHandleSize);
177 Spline.setCurveWidth((int) getPixelsFromDip(3));
179 setContentView(R.layout.filtershow_activity);
180 ActionBar actionBar = getActionBar();
181 actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
182 actionBar.setCustomView(R.layout.filtershow_actionbar);
184 mSaveButton = actionBar.getCustomView();
185 mSaveButton.setOnClickListener(new OnClickListener() {
187 public void onClick(View view) {
192 mImageLoader = new ImageLoader(this, getApplicationContext());
194 listFilters = (LinearLayout) findViewById(R.id.listFilters);
195 listBorders = (LinearLayout) findViewById(R.id.listBorders);
196 listColors = (LinearLayout) findViewById(R.id.listColorsFx);
198 mImageShow = (ImageShow) findViewById(R.id.imageShow);
199 mImageStraighten = (ImageStraighten) findViewById(R.id.imageStraighten);
200 mImageCrop = (ImageCrop) findViewById(R.id.imageCrop);
201 mImageRotate = (ImageRotate) findViewById(R.id.imageRotate);
202 mImageFlip = (ImageFlip) findViewById(R.id.imageFlip);
203 mImageTinyPlanet = (ImageTinyPlanet) findViewById(R.id.imageTinyPlanet);
204 mImageDraw = (ImageDraw) findViewById(R.id.imageDraw);
206 mImageCrop.setAspectTextSize((int) getPixelsFromDip(18));
207 ImageCrop.setTouchTolerance((int) getPixelsFromDip(25));
208 ImageCrop.setMinCropSize((int) getPixelsFromDip(55));
209 mImageViews.add(mImageShow);
210 mImageViews.add(mImageStraighten);
211 mImageViews.add(mImageCrop);
212 mImageViews.add(mImageRotate);
213 mImageViews.add(mImageFlip);
214 mImageViews.add(mImageTinyPlanet);
216 mEditorPlaceHolder.setContainer((FrameLayout) findViewById(R.id.editorContainer));
217 mEditorPlaceHolder.addEditor(new EditorDraw());
218 mEditorPlaceHolder.addEditor(new BasicEditor());
219 mEditorPlaceHolder.addEditor(new ImageOnlyEditor());
220 mEditorPlaceHolder.addEditor(new EditorTinyPlanet());
221 mEditorPlaceHolder.addEditor(new EditorRedEye());
222 EditorManager.addEditors(mEditorPlaceHolder);
223 mEditorPlaceHolder.setOldViews(mImageViews);
224 mEditorPlaceHolder.setImageLoader(mImageLoader);
226 mEditorPlaceHolder.hide();
228 mListFx = findViewById(R.id.fxList);
229 mListBorders = findViewById(R.id.bordersList);
230 mListGeometry = findViewById(R.id.geometryList);
231 mListFilterButtons = findViewById(R.id.filterButtonsList);
232 mListColors = findViewById(R.id.colorsFxList);
233 mListViews.add(mListFx);
234 mListViews.add(mListBorders);
235 mListViews.add(mListGeometry);
236 mListViews.add(mListFilterButtons);
237 mListViews.add(mListColors);
239 mFxButton = (ImageButton) findViewById(R.id.fxButton);
240 mBorderButton = (ImageButton) findViewById(R.id.borderButton);
241 mGeometryButton = (ImageButton) findViewById(R.id.geometryButton);
242 mColorsButton = (ImageButton) findViewById(R.id.colorsButton);
244 mBottomPanelButtons.add(mFxButton);
245 mBottomPanelButtons.add(mBorderButton);
246 mBottomPanelButtons.add(mGeometryButton);
247 mBottomPanelButtons.add(mColorsButton);
249 mImageShow.setImageLoader(mImageLoader);
250 mImageStraighten.setImageLoader(mImageLoader);
251 mImageCrop.setImageLoader(mImageLoader);
252 mImageRotate.setImageLoader(mImageLoader);
253 mImageFlip.setImageLoader(mImageLoader);
254 mImageTinyPlanet.setImageLoader(mImageLoader);
255 mImageDraw.setImageLoader(mImageLoader);
257 mPanelController.setActivity(this);
258 mPanelController.setEditorPlaceHolder(mEditorPlaceHolder);
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.imageDraw));
268 mPanelController.addPanel(mFxButton, mListFx, 0);
269 mPanelController.addPanel(mBorderButton, mListBorders, 1);
271 mPanelController.addPanel(mGeometryButton, mListGeometry, 2);
272 mPanelController.addComponent(mGeometryButton, findViewById(R.id.straightenButton));
273 mPanelController.addComponent(mGeometryButton, findViewById(R.id.cropButton));
274 mPanelController.addComponent(mGeometryButton, findViewById(R.id.rotateButton));
275 mPanelController.addComponent(mGeometryButton, findViewById(R.id.flipButton));
277 mPanelController.addPanel(mColorsButton, mListColors, 3);
279 Vector<FilterRepresentation> filtersRepresentations = new Vector<FilterRepresentation>();
281 FiltersManager filtersManager = FiltersManager.getManager();
282 filtersManager.addEffects(filtersRepresentations);
284 for (FilterRepresentation representation : filtersRepresentations) {
285 setupFilterRepresentationButton(representation, listColors, mColorsButton);
288 mPanelController.addView(findViewById(R.id.applyEffect));
289 findViewById(R.id.resetOperationsButton).setOnClickListener(
290 createOnClickResetOperationsButton());
292 ListView operationsList = (ListView) findViewById(R.id.operationsList);
293 operationsList.setAdapter(mMasterImage.getHistory());
294 operationsList.setOnItemClickListener(this);
295 ListView imageStateList = (ListView) findViewById(R.id.imageStateList);
296 imageStateList.setAdapter(mMasterImage.getState());
297 mImageLoader.setAdapter(mMasterImage.getHistory());
299 fillListImages(listFilters);
300 LoadBordersTask loadBorders = new LoadBordersTask(listBorders);
301 loadBorders.execute();
303 mPanelController.setRowPanel(findViewById(R.id.secondRowPanel));
304 mPanelController.setUtilityPanel(this, findViewById(R.id.filterButtonsList),
305 findViewById(R.id.panelAccessoryViewList),
306 findViewById(R.id.applyEffect));
308 mPanelController.setCurrentPanel(mFxButton);
309 Intent intent = getIntent();
310 if (intent.getBooleanExtra(LAUNCH_FULLSCREEN, false)) {
311 getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
314 mAction = intent.getAction();
316 if (intent.getData() != null) {
317 startLoadBitmap(intent.getData());
322 // Handle behavior for various actions
323 if (mAction.equalsIgnoreCase(CROP_ACTION)) {
324 Bundle extras = intent.getExtras();
325 if (extras != null) {
326 mCropExtras = new CropExtras(extras.getInt(CropExtras.KEY_OUTPUT_X, 0),
327 extras.getInt(CropExtras.KEY_OUTPUT_Y, 0),
328 extras.getBoolean(CropExtras.KEY_SCALE, true) &&
329 extras.getBoolean(CropExtras.KEY_SCALE_UP_IF_NEEDED, false),
330 extras.getInt(CropExtras.KEY_ASPECT_X, 0),
331 extras.getInt(CropExtras.KEY_ASPECT_Y, 0),
332 extras.getBoolean(CropExtras.KEY_SET_AS_WALLPAPER, false),
333 extras.getBoolean(CropExtras.KEY_RETURN_DATA, false),
334 (Uri) extras.getParcelable(MediaStore.EXTRA_OUTPUT),
335 extras.getString(CropExtras.KEY_OUTPUT_FORMAT),
336 extras.getBoolean(CropExtras.KEY_SHOW_WHEN_LOCKED, false),
337 extras.getFloat(CropExtras.KEY_SPOTLIGHT_X),
338 extras.getFloat(CropExtras.KEY_SPOTLIGHT_Y));
340 if (mCropExtras.getShowWhenLocked()) {
341 getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
343 mImageShow.getImagePreset().mGeoData.setCropExtras(mCropExtras);
345 mImageCrop.setExtras(mCropExtras);
346 String s = getString(R.string.Fixed);
347 mImageCrop.setAspectString(s);
348 mImageCrop.setCropActionFlag(true);
349 mPanelController.setFixedAspect(mCropExtras.getAspectX() > 0
350 && mCropExtras.getAspectY() > 0);
355 private void startLoadBitmap(Uri uri) {
356 final View filters = findViewById(R.id.filtersPanel);
357 final View loading = findViewById(R.id.loading);
358 final View imageShow = findViewById(R.id.imageShow);
359 imageShow.setVisibility(View.INVISIBLE);
360 filters.setVisibility(View.INVISIBLE);
361 loading.setVisibility(View.VISIBLE);
363 View tinyPlanetView = findViewById(R.id.tinyplanetButton);
364 if (tinyPlanetView != null) {
365 tinyPlanetView.setVisibility(View.GONE);
367 mLoadBitmapTask = new LoadBitmapTask(tinyPlanetView);
368 mLoadBitmapTask.execute(uri);
371 private class LoadBordersTask extends AsyncTask<Void, Boolean, Boolean> {
372 Vector<FilterRepresentation> mBorders;
375 public LoadBordersTask(LinearLayout list) {
377 mBorders = new Vector<FilterRepresentation>();
381 protected Boolean doInBackground(Void... params) {
382 mBorders.add(new FilterImageBorderRepresentation(0));
383 mBorders.add(new FilterImageBorderRepresentation(R.drawable.filtershow_border_4x5));
384 mBorders.add(new FilterImageBorderRepresentation(R.drawable.filtershow_border_brush));
385 mBorders.add(new FilterImageBorderRepresentation(R.drawable.filtershow_border_grunge));
386 mBorders.add(new FilterImageBorderRepresentation(R.drawable.filtershow_border_sumi_e));
387 mBorders.add(new FilterImageBorderRepresentation(R.drawable.filtershow_border_tape));
388 mBorders.add(new FilterColorBorderRepresentation(Color.BLACK, mImageBorderSize, 0));
389 mBorders.add(new FilterColorBorderRepresentation(Color.BLACK, mImageBorderSize, mImageBorderSize));
390 mBorders.add(new FilterColorBorderRepresentation(Color.WHITE, mImageBorderSize, 0));
391 mBorders.add(new FilterColorBorderRepresentation(Color.WHITE, mImageBorderSize, mImageBorderSize));
392 int creamColor = Color.argb(255, 237, 237, 227);
393 mBorders.add(new FilterColorBorderRepresentation(creamColor, mImageBorderSize, 0));
394 mBorders.add(new FilterColorBorderRepresentation(creamColor, mImageBorderSize, mImageBorderSize));
399 protected void onPostExecute(Boolean result) {
403 for (int i = 0; i < mBorders.size(); i++) {
404 FilterRepresentation filter = mBorders.elementAt(i);
405 filter.setName(getString(R.string.borders));
407 filter.setName(getString(R.string.none));
409 FilterIconButton b = setupFilterRepresentationButton(filter, mList, mBorderButton);
411 mNullBorderFilter = b;
412 mNullBorderFilter.setSelected(true);
418 private class LoadBitmapTask extends AsyncTask<Uri, Boolean, Boolean> {
419 View mTinyPlanetButton;
422 public LoadBitmapTask(View button) {
423 mTinyPlanetButton = button;
424 mBitmapSize = getScreenImageSize();
428 protected Boolean doInBackground(Uri... params) {
429 if (!mImageLoader.loadBitmap(params[0], mBitmapSize)) {
432 publishProgress(mImageLoader.queryLightCycle360());
437 protected void onProgressUpdate(Boolean... values) {
438 super.onProgressUpdate(values);
443 mTinyPlanetButton.setVisibility(View.VISIBLE);
448 protected void onPostExecute(Boolean result) {
458 final View loading = findViewById(R.id.loading);
459 loading.setVisibility(View.GONE);
460 final View filters = findViewById(R.id.filtersPanel);
461 filters.setVisibility(View.VISIBLE);
462 if (PanelController.useAnimations()) {
463 float y = filters.getY();
464 filters.setY(y + filters.getHeight());
465 filters.animate().setDuration(600).y(y).withLayer().start();
467 final View imageShow = findViewById(R.id.imageShow);
468 imageShow.setVisibility(View.VISIBLE);
470 Bitmap largeBitmap = mImageLoader.getOriginalBitmapLarge();
471 FilteringPipeline pipeline = FilteringPipeline.getPipeline();
472 pipeline.setOriginal(largeBitmap);
473 float previewScale = (float) largeBitmap.getWidth() / (float) mImageLoader.getOriginalBounds().width();
474 pipeline.setPreviewScaleFactor(previewScale);
476 Bitmap bmap = mImageLoader.getOriginalBitmapSmall();
477 if (bmap != null && bmap.getWidth() > 0 && bmap.getHeight() > 0) {
478 float w = bmap.getWidth();
479 float h = bmap.getHeight();
480 float f = mIconSeedSize / Math.min(w, h);
483 bmap = Bitmap.createScaledBitmap(bmap, (int) w, (int) h, true);
485 int num_colors_buttons = listColors.getChildCount();
486 for (int i = 0; i < num_colors_buttons; i++) {
487 FilterIconButton b = (FilterIconButton) listColors.getChildAt(i);
491 int num_filters_buttons = listFilters.getChildCount();
492 for (int i = 0; i < num_filters_buttons; i++) {
493 FilterIconButton b = (FilterIconButton) listFilters.getChildAt(i);
497 int num_borders_buttons = listBorders.getChildCount();
498 for (int i = 0; i < num_borders_buttons; i++) {
499 FilterIconButton b = (FilterIconButton) listBorders.getChildAt(i);
505 mLoadBitmapTask = null;
507 if (mAction == CROP_ACTION) {
508 mPanelController.showComponent(findViewById(R.id.cropButton));
509 } else if (mAction == TINY_PLANET_ACTION) {
510 mPanelController.showComponent(findViewById(R.id.tinyplanetButton));
513 super.onPostExecute(result);
519 protected void onDestroy() {
520 if (mLoadBitmapTask != null) {
521 mLoadBitmapTask.cancel(false);
526 private int translateMainPanel(View viewPanel) {
527 int accessoryPanelWidth = viewPanel.getWidth();
528 int mainViewWidth = findViewById(R.id.mainView).getWidth();
529 int mainPanelWidth = mImageShow.getDisplayedImageBounds().width();
530 if (mainPanelWidth == 0) {
531 mainPanelWidth = mainViewWidth;
533 int filtersPanelWidth = findViewById(R.id.filtersPanel).getWidth();
534 if (mainPanelWidth < filtersPanelWidth) {
535 mainPanelWidth = filtersPanelWidth;
537 int leftOver = mainViewWidth - mainPanelWidth - accessoryPanelWidth;
539 return -accessoryPanelWidth;
544 private int getScreenImageSize() {
545 DisplayMetrics metrics = new DisplayMetrics();
546 Display display = getWindowManager().getDefaultDisplay();
547 Point size = new Point();
548 display.getSize(size);
549 display.getMetrics(metrics);
550 int msize = Math.min(size.x, size.y);
551 return (133 * msize) / metrics.densityDpi;
554 private void showSavingProgress(String albumName) {
555 ProgressDialog progress;
556 if (mSavingProgressDialog != null) {
557 progress = mSavingProgressDialog.get();
558 if (progress != null) {
563 // TODO: Allow cancellation of the saving process
565 if (albumName == null) {
566 progressText = getString(R.string.saving_image);
568 progressText = getString(R.string.filtershow_saving_image, albumName);
570 progress = ProgressDialog.show(this, "", progressText, true, false);
571 mSavingProgressDialog = new WeakReference<ProgressDialog>(progress);
574 private void hideSavingProgress() {
575 if (mSavingProgressDialog != null) {
576 ProgressDialog progress = mSavingProgressDialog.get();
577 if (progress != null)
582 public void completeSaveImage(Uri saveUri) {
583 if (mSharingImage && mSharedOutputFile != null) {
584 // Image saved, we unblock the content provider
585 Uri uri = Uri.withAppendedPath(SharedImageProvider.CONTENT_URI,
586 Uri.encode(mSharedOutputFile.getAbsolutePath()));
587 ContentValues values = new ContentValues();
588 values.put(SharedImageProvider.PREPARE, false);
589 getContentResolver().insert(uri, values);
591 setResult(RESULT_OK, new Intent().setData(saveUri));
592 hideSavingProgress();
597 public boolean onShareTargetSelected(ShareActionProvider arg0, Intent arg1) {
598 // First, let's tell the SharedImageProvider that it will need to wait
600 Uri uri = Uri.withAppendedPath(SharedImageProvider.CONTENT_URI,
601 Uri.encode(mSharedOutputFile.getAbsolutePath()));
602 ContentValues values = new ContentValues();
603 values.put(SharedImageProvider.PREPARE, true);
604 getContentResolver().insert(uri, values);
605 mSharingImage = true;
607 // Process and save the image in the background.
608 showSavingProgress(null);
609 mImageShow.saveImage(this, mSharedOutputFile);
613 private Intent getDefaultShareIntent() {
614 Intent intent = new Intent(Intent.ACTION_SEND);
615 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
616 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
617 intent.setType(SharedImageProvider.MIME_TYPE);
618 mSharedOutputFile = SaveCopyTask.getNewFile(this, mImageLoader.getUri());
619 Uri uri = Uri.withAppendedPath(SharedImageProvider.CONTENT_URI,
620 Uri.encode(mSharedOutputFile.getAbsolutePath()));
621 intent.putExtra(Intent.EXTRA_STREAM, uri);
626 public boolean onCreateOptionsMenu(Menu menu) {
627 getMenuInflater().inflate(R.menu.filtershow_activity_menu, menu);
628 MenuItem showHistory = menu.findItem(R.id.operationsButton);
629 if (mShowingHistoryPanel) {
630 showHistory.setTitle(R.string.hide_history_panel);
632 showHistory.setTitle(R.string.show_history_panel);
634 MenuItem showState = menu.findItem(R.id.showImageStateButton);
635 if (mShowingImageStatePanel) {
636 showState.setTitle(R.string.hide_imagestate_panel);
638 showState.setTitle(R.string.show_imagestate_panel);
640 mShareActionProvider = (ShareActionProvider) menu.findItem(R.id.menu_share)
641 .getActionProvider();
642 mShareActionProvider.setShareIntent(getDefaultShareIntent());
643 mShareActionProvider.setOnShareTargetSelectedListener(this);
645 MenuItem undoItem = menu.findItem(R.id.undoButton);
646 MenuItem redoItem = menu.findItem(R.id.redoButton);
647 MenuItem resetItem = menu.findItem(R.id.resetHistoryButton);
648 mMasterImage.getHistory().setMenuItems(undoItem, redoItem, resetItem);
653 public void onPause() {
655 if (mShareActionProvider != null) {
656 mShareActionProvider.setOnShareTargetSelectedListener(null);
661 public void onResume() {
663 if (mShareActionProvider != null) {
664 mShareActionProvider.setOnShareTargetSelectedListener(this);
669 public boolean onOptionsItemSelected(MenuItem item) {
670 switch (item.getItemId()) {
671 case R.id.undoButton: {
672 HistoryAdapter adapter = mMasterImage.getHistory();
673 int position = adapter.undo();
674 mMasterImage.onHistoryItemClick(position);
675 mImageShow.showToast("Undo");
679 case R.id.redoButton: {
680 HistoryAdapter adapter = mMasterImage.getHistory();
681 int position = adapter.redo();
682 mMasterImage.onHistoryItemClick(position);
683 mImageShow.showToast("Redo");
687 case R.id.resetHistoryButton: {
691 case R.id.showImageStateButton: {
692 toggleImageStatePanel();
695 case R.id.operationsButton: {
696 toggleHistoryPanel();
699 case android.R.id.home: {
707 public void enableSave(boolean enable) {
708 if (mSaveButton != null)
709 mSaveButton.setEnabled(enable);
712 public FilterIconButton setupFilterRepresentationButton(FilterRepresentation representation, LinearLayout panel, View button) {
713 LayoutInflater inflater =
714 (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
715 FilterIconButton icon = (FilterIconButton) inflater.inflate(R.layout.filtericonbutton,
717 if (representation.getTextId() != 0) {
718 representation.setName(getString(representation.getTextId()));
720 String text = representation.getName();
721 icon.setup(text, mPanelController, panel);
722 icon.setFilterRepresentation(representation);
723 if (representation instanceof FilterTinyPlanetRepresentation) {
724 // needed to hide tinyplanet on startup
725 icon.setId(R.id.tinyplanetButton);
727 mPanelController.addComponent(button, icon);
732 private void fillListImages(LinearLayout listFilters) {
733 // TODO: use listview
734 // TODO: load the filters straight from the filesystem
736 FilterFxRepresentation[] fxArray = new FilterFxRepresentation[18];
740 R.drawable.filtershow_fx_0005_punch,
741 R.drawable.filtershow_fx_0000_vintage,
742 R.drawable.filtershow_fx_0004_bw_contrast,
743 R.drawable.filtershow_fx_0002_bleach,
744 R.drawable.filtershow_fx_0001_instant,
745 R.drawable.filtershow_fx_0007_washout,
746 R.drawable.filtershow_fx_0003_blue_crush,
747 R.drawable.filtershow_fx_0008_washout_color,
748 R.drawable.filtershow_fx_0006_x_process
753 R.string.ffx_vintage,
754 R.string.ffx_bw_contrast,
756 R.string.ffx_instant,
757 R.string.ffx_washout,
758 R.string.ffx_blue_crush,
759 R.string.ffx_washout_color,
760 R.string.ffx_x_process
763 ImagePreset preset = new ImagePreset(getString(R.string.history_original)); // empty
764 preset.setImageLoader(mImageLoader);
766 BitmapFactory.Options o = new BitmapFactory.Options();
769 for (int i = 0; i < drawid.length; i++) {
770 Bitmap b = BitmapFactory.decodeResource(getResources(), drawid[i], o);
771 FilterFxRepresentation fx = new FilterFxRepresentation(getString(fxNameid[i]), drawid[i], fxNameid[i]);
776 FilterFxRepresentation nullFx = new FilterFxRepresentation(getString(R.string.none), 0, R.string.none);
777 mNullFxFilter = setupFilterRepresentationButton(nullFx, listFilters, mFxButton);
778 mNullFxFilter.setSelected(true);
780 Vector<FilterRepresentation> filtersRepresentations = new Vector<FilterRepresentation>();
781 FiltersManager.getManager().addLooks(filtersRepresentations);
782 for (FilterRepresentation representation : filtersRepresentations) {
783 setupFilterRepresentationButton(representation, listFilters, mFxButton);
786 for (int i = 0; i < p; i++) {
787 setupFilterRepresentationButton(fxArray[i], listFilters, mFxButton);
790 // Default preset (original)
791 mMasterImage.setPreset(preset, true);
794 // //////////////////////////////////////////////////////////////////////////////
795 // Some utility functions
796 // TODO: finish the cleanup.
798 public void showOriginalViews(boolean value) {
799 for (ImageShow views : mImageViews) {
800 views.showOriginal(value);
804 public void invalidateViews() {
805 for (ImageShow views : mImageViews) {
811 public void hideListViews() {
812 for (View view : mListViews) {
813 view.setVisibility(View.GONE);
817 public void hideImageViews() {
818 for (View view : mImageViews) {
819 view.setVisibility(View.GONE);
821 mEditorPlaceHolder.hide();
824 public void unselectBottomPanelButtons() {
825 for (ImageButton button : mBottomPanelButtons) {
826 button.setSelected(false);
830 public void unselectPanelButtons(Vector<ImageButton> buttons) {
831 for (ImageButton button : buttons) {
832 button.setSelected(false);
836 public void disableFilterButtons() {
837 for (ImageButton b : mBottomPanelButtons) {
839 b.setClickable(false);
844 public void enableFilterButtons() {
845 for (ImageButton b : mBottomPanelButtons) {
847 b.setClickable(true);
852 // //////////////////////////////////////////////////////////////////////////////
853 // imageState panel...
855 public boolean isShowingHistoryPanel() {
856 return mShowingHistoryPanel;
859 private void toggleImageStatePanel() {
860 final View view = findViewById(R.id.mainPanel);
861 final View viewList = findViewById(R.id.imageStatePanel);
863 if (mShowingHistoryPanel) {
864 findViewById(R.id.historyPanel).setVisibility(View.INVISIBLE);
865 mShowingHistoryPanel = false;
868 int translate = translateMainPanel(viewList);
869 if (!mShowingImageStatePanel) {
870 mShowingImageStatePanel = true;
871 if (PanelController.useAnimations()) {
872 view.animate().setDuration(200).x(translate)
873 .withLayer().withEndAction(new Runnable() {
876 viewList.setAlpha(0);
877 viewList.setVisibility(View.VISIBLE);
878 viewList.animate().setDuration(100)
879 .alpha(1.0f).start();
883 view.setX(translate);
884 viewList.setAlpha(0);
885 viewList.setVisibility(View.VISIBLE);
886 viewList.animate().setDuration(100)
887 .alpha(1.0f).start();
890 mShowingImageStatePanel = false;
891 viewList.setVisibility(View.INVISIBLE);
892 if (PanelController.useAnimations()) {
893 view.animate().setDuration(200).x(0).withLayer()
899 invalidateOptionsMenu();
903 public void onConfigurationChanged(Configuration newConfig)
905 super.onConfigurationChanged(newConfig);
907 if (mShowingHistoryPanel) {
908 toggleHistoryPanel();
912 public void setupMasterImage() {
913 HistoryAdapter mHistoryAdapter = new HistoryAdapter(
914 this, R.layout.filtershow_history_operation_row,
916 ImageStateAdapter mImageStateAdapter = new ImageStateAdapter(this,
917 R.layout.filtershow_imagestate_row);
920 mMasterImage = MasterImage.getImage();
921 mMasterImage.setHistoryAdapter(mHistoryAdapter);
922 mMasterImage.setStateAdapter(mImageStateAdapter);
923 mMasterImage.setActivity(this);
926 // //////////////////////////////////////////////////////////////////////////////
929 public void toggleHistoryPanel() {
930 final View view = findViewById(R.id.mainPanel);
931 final View viewList = findViewById(R.id.historyPanel);
933 if (mShowingImageStatePanel) {
934 findViewById(R.id.imageStatePanel).setVisibility(View.INVISIBLE);
935 mShowingImageStatePanel = false;
938 int translate = translateMainPanel(viewList);
939 if (!mShowingHistoryPanel) {
940 mShowingHistoryPanel = true;
941 if (PanelController.useAnimations()) {
942 view.animate().setDuration(200).x(translate)
943 .withLayer().withEndAction(new Runnable() {
946 viewList.setAlpha(0);
947 viewList.setVisibility(View.VISIBLE);
948 viewList.animate().setDuration(100)
949 .alpha(1.0f).start();
953 view.setX(translate);
954 viewList.setAlpha(0);
955 viewList.setVisibility(View.VISIBLE);
956 viewList.animate().setDuration(100)
957 .alpha(1.0f).start();
960 mShowingHistoryPanel = false;
961 viewList.setVisibility(View.INVISIBLE);
962 if (PanelController.useAnimations()) {
963 view.animate().setDuration(200).x(0).withLayer()
969 invalidateOptionsMenu();
972 public void dispatchNullFilterClick() {
973 mNullFxFilter.onClick(mNullFxFilter);
974 mNullBorderFilter.onClick(mNullBorderFilter);
977 void resetHistory() {
978 dispatchNullFilterClick();
979 HistoryAdapter adapter = mMasterImage.getHistory();
981 ImagePreset original = new ImagePreset(adapter.getItem(0));
982 mMasterImage.setPreset(original, true);
983 mPanelController.resetParameters();
987 // reset button in the history panel.
988 private OnClickListener createOnClickResetOperationsButton() {
989 return new View.OnClickListener() {
991 public void onClick(View v) {
998 public void onBackPressed() {
999 if (mPanelController.onBackPressed()) {
1004 public void cannotLoadImage() {
1005 CharSequence text = getString(R.string.cannot_load_image);
1006 Toast toast = Toast.makeText(this, text, Toast.LENGTH_SHORT);
1011 // //////////////////////////////////////////////////////////////////////////////
1013 public float getPixelsFromDip(float value) {
1014 Resources r = getResources();
1015 return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, value,
1016 r.getDisplayMetrics());
1020 public void onItemClick(AdapterView<?> parent, View view, int position,
1022 mMasterImage.onHistoryItemClick(position);
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)),
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);
1044 private boolean mSaveToExtraUri = false;
1045 private boolean mSaveAsWallpaper = false;
1046 private boolean mReturnAsExtra = false;
1047 private boolean mOutputted = false;
1049 public void saveImage() {
1050 if (mCropExtras != null) {
1051 if (mCropExtras.getExtraOutput() != null) {
1052 mSaveToExtraUri = true;
1055 if (mCropExtras.getSetAsWallpaper()) {
1056 mSaveAsWallpaper = true;
1059 if (mCropExtras.getReturnData()) {
1061 mReturnAsExtra = true;
1066 mImageShow.getImagePreset().mGeoData.setUseCropExtrasFlag(true);
1067 showSavingProgress(null);
1068 mImageShow.returnFilteredResult(this);
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);
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);
1092 if (mSaveAsWallpaper) {
1093 setWallpaperInBackground(filtered);
1095 if (mReturnAsExtra) {
1096 if (filtered != null) {
1097 int bmapSize = filtered.getRowBytes() * filtered.getHeight();
1099 * Max size of Binder transaction buffer is 1Mb, so constrain
1100 * Bitmap to be somewhat less than this, otherwise we get
1101 * TransactionTooLargeExceptions.
1103 if (bmapSize > MAX_BMAP_IN_INTENT) {
1104 Log.w(LOGTAG, "Bitmap too large to be returned via intent");
1106 intent.putExtra(CropExtras.KEY_DATA, filtered);
1110 setResult(RESULT_OK, intent);
1111 if (!mSaveToExtraUri) {
1116 void setWallpaperInBackground(final Bitmap bmap) {
1117 Toast.makeText(this, R.string.setting_wallpaper, Toast.LENGTH_LONG).show();
1118 BitmapTask.Callbacks<FilterShowActivity> cb = new BitmapTask.Callbacks<FilterShowActivity>() {
1120 public void onComplete(Bitmap result) {}
1123 public void onCancel() {}
1126 public Bitmap onExecute(FilterShowActivity param) {
1128 WallpaperManager.getInstance(param).setBitmap(bmap);
1129 } catch (IOException e) {
1130 Log.w(LOGTAG, "fail to set wall paper", e);
1135 (new BitmapTask<FilterShowActivity>(cb)).execute(this);
1138 public void done() {
1140 hideSavingProgress();
1145 private void setResources() {
1146 ImageFilterBorder filterBorder = (ImageFilterBorder) FiltersManager.getManager().getFilter(ImageFilterBorder.class);
1147 filterBorder.setResources(getResources());
1151 System.loadLibrary("jni_filtershow_filters");