diff options
Diffstat (limited to 'src')
99 files changed, 2693 insertions, 1300 deletions
diff --git a/src/com/android/camera/CameraActivity.java b/src/com/android/camera/CameraActivity.java index c8dadbd18..4ed6309d2 100644 --- a/src/com/android/camera/CameraActivity.java +++ b/src/com/android/camera/CameraActivity.java @@ -15,19 +15,22 @@ */ package com.android.camera; -import com.android.gallery3d.util.CameraHelper; +import com.android.gallery3d.util.IntentHelper; import android.app.Activity; import android.content.Intent; import android.os.Bundle; -/** Trampoline activity that launches the new Camera activity defined in CameraHelper. */ +/** Trampoline activity that launches the new Camera activity defined in IntentHelper. */ public class CameraActivity extends Activity { @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); - Intent intent = CameraHelper.CAMERA_LAUNCHER_INTENT; - intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK); + Intent intent = IntentHelper.getCameraIntent(CameraActivity.this); + // Since this is being launched from a homescreen shorcut, + // it's already in a new task. Start Camera activity and + // reset the task to its initial state if needed. + intent.setFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); startActivity(intent); finish(); } diff --git a/src/com/android/camera/DisableCameraReceiver.java b/src/com/android/camera/DisableCameraReceiver.java new file mode 100644 index 000000000..d51d6b9ef --- /dev/null +++ b/src/com/android/camera/DisableCameraReceiver.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.camera; + +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.hardware.Camera.CameraInfo; +import android.util.Log; + +// We want to disable camera-related activities if there is no camera. This +// receiver runs when BOOT_COMPLETED intent is received. After running once +// this receiver will be disabled, so it will not run again. +public class DisableCameraReceiver extends BroadcastReceiver { + private static final String TAG = "G:DisableCameraReceiver"; + private static final boolean CHECK_BACK_CAMERA_ONLY = true; + private static final String ACTIVITIES[] = { + "com.android.camera.CameraLauncher", + }; + + @Override + public void onReceive(Context context, Intent intent) { + // Disable camera-related activities if there is no camera. + boolean needCameraActivity = CHECK_BACK_CAMERA_ONLY + ? hasBackCamera() + : hasCamera(); + + if (!needCameraActivity) { + Log.i(TAG, "disable all camera activities"); + for (int i = 0; i < ACTIVITIES.length; i++) { + disableComponent(context, ACTIVITIES[i]); + } + } + + // Disable this receiver so it won't run again. + disableComponent(context, "com.android.camera.DisableCameraReceiver"); + } + + private boolean hasCamera() { + int n = android.hardware.Camera.getNumberOfCameras(); + Log.i(TAG, "number of camera: " + n); + return (n > 0); + } + + private boolean hasBackCamera() { + int n = android.hardware.Camera.getNumberOfCameras(); + CameraInfo info = new CameraInfo(); + for (int i = 0; i < n; i++) { + android.hardware.Camera.getCameraInfo(i, info); + if (info.facing == CameraInfo.CAMERA_FACING_BACK) { + Log.i(TAG, "back camera found: " + i); + return true; + } + } + Log.i(TAG, "no back camera"); + return false; + } + + private void disableComponent(Context context, String klass) { + ComponentName name = new ComponentName(context, klass); + PackageManager pm = context.getPackageManager(); + + // We need the DONT_KILL_APP flag, otherwise we will be killed + // immediately because we are in the same app. + pm.setComponentEnabledSetting(name, + PackageManager.COMPONENT_ENABLED_STATE_DISABLED, + PackageManager.DONT_KILL_APP); + } +} diff --git a/src/com/android/gallery3d/app/AbstractGalleryActivity.java b/src/com/android/gallery3d/app/AbstractGalleryActivity.java index 923c5b2e6..9af1fb8ba 100644 --- a/src/com/android/gallery3d/app/AbstractGalleryActivity.java +++ b/src/com/android/gallery3d/app/AbstractGalleryActivity.java @@ -32,6 +32,7 @@ import android.content.res.Configuration; import android.net.Uri; import android.os.Bundle; import android.os.IBinder; +import android.support.v4.print.PrintHelper; import android.view.Menu; import android.view.MenuItem; import android.view.Window; @@ -45,12 +46,12 @@ import com.android.gallery3d.filtershow.cache.ImageLoader; import com.android.gallery3d.ui.GLRoot; import com.android.gallery3d.ui.GLRootView; import com.android.gallery3d.util.PanoramaViewHelper; -import com.android.gallery3d.util.PrintJob; import com.android.gallery3d.util.ThreadPool; import com.android.photos.data.GalleryBitmapPool; +import java.io.FileNotFoundException; + public class AbstractGalleryActivity extends Activity implements GalleryContext { - @SuppressWarnings("unused") private static final String TAG = "AbstractGalleryActivity"; private GLRootView mGLRootView; private StateManager mStateManager; @@ -357,6 +358,11 @@ public class AbstractGalleryActivity extends Activity implements GalleryContext } else { path = uri.getLastPathSegment(); } - PrintJob.printBitmapAtUri(this, path, uri); + PrintHelper printer = new PrintHelper(this); + try { + printer.printBitmap(path, uri); + } catch (FileNotFoundException fnfe) { + Log.e(TAG, "Error printing an image", fnfe); + } } } diff --git a/src/com/android/gallery3d/app/AlbumPage.java b/src/com/android/gallery3d/app/AlbumPage.java index ad757da9c..44f24043b 100644 --- a/src/com/android/gallery3d/app/AlbumPage.java +++ b/src/com/android/gallery3d/app/AlbumPage.java @@ -316,7 +316,7 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster private void onGetContent(final MediaItem item) { DataManager dm = mActivity.getDataManager(); Activity activity = mActivity; - if (mData.getString(Gallery.EXTRA_CROP) != null) { + if (mData.getString(GalleryActivity.EXTRA_CROP) != null) { Uri uri = dm.getContentUri(item.getPath()); Intent intent = new Intent(CropActivity.CROP_ACTION, uri) .addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT) @@ -367,7 +367,7 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster mUserDistance = GalleryUtils.meterToPixel(USER_DISTANCE_METER); initializeViews(); initializeData(data); - mGetContent = data.getBoolean(Gallery.KEY_GET_CONTENT, false); + mGetContent = data.getBoolean(GalleryActivity.KEY_GET_CONTENT, false); mShowClusterMenu = data.getBoolean(KEY_SHOW_CLUSTER_MENU, false); mDetailsSource = new MyDetailsSource(); Context context = mActivity.getAndroidContext(); @@ -538,34 +538,13 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster mSlotView.invalidate(); } - private boolean canDoSlideShow() { - if (mMediaSet == null) { - return false; - } - - final int[] count = new int[]{0}; - mMediaSet.enumerateMediaItems(new MediaSet.ItemConsumer() { - @Override - public void consume(int index, MediaItem item) { - if (item.getMediaType() == MediaObject.MEDIA_TYPE_IMAGE) { - count[0]++; - } - } - }); - - if (count[0] < 2) { // you must have 2 pictures to go into slide show - return false; - } - return true; - } - @Override protected boolean onCreateActionBar(Menu menu) { GalleryActionBar actionBar = mActivity.getGalleryActionBar(); MenuInflater inflator = getSupportMenuInflater(); if (mGetContent) { inflator.inflate(R.menu.pickup, menu); - int typeBits = mData.getInt(Gallery.KEY_TYPE_BITS, + int typeBits = mData.getInt(GalleryActivity.KEY_TYPE_BITS, DataManager.INCLUDE_IMAGE); actionBar.setTitle(GalleryUtils.getSelectionModePrompt(typeBits)); } else { @@ -574,7 +553,6 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster FilterUtils.setupMenuItems(actionBar, mMediaSetPath, true); - menu.findItem(R.id.action_slideshow).setVisible(canDoSlideShow()); menu.findItem(R.id.action_group_by).setVisible(mShowClusterMenu); menu.findItem(R.id.action_camera).setVisible( MediaSetUtils.isCameraSource(mMediaSetPath) diff --git a/src/com/android/gallery3d/app/AlbumPicker.java b/src/com/android/gallery3d/app/AlbumPicker.java index 65eb77291..8c2d09a0e 100644 --- a/src/com/android/gallery3d/app/AlbumPicker.java +++ b/src/com/android/gallery3d/app/AlbumPicker.java @@ -32,7 +32,7 @@ public class AlbumPicker extends PickerActivity { Bundle extras = intent.getExtras(); Bundle data = extras == null ? new Bundle() : new Bundle(extras); - data.putBoolean(Gallery.KEY_GET_ALBUM, true); + data.putBoolean(GalleryActivity.KEY_GET_ALBUM, true); data.putString(AlbumSetPage.KEY_MEDIA_PATH, getDataManager().getTopSetPath(DataManager.INCLUDE_IMAGE)); getStateManager().startState(AlbumSetPage.class, data); diff --git a/src/com/android/gallery3d/app/AlbumSetPage.java b/src/com/android/gallery3d/app/AlbumSetPage.java index dd9d8ec41..d56b5b85d 100644 --- a/src/com/android/gallery3d/app/AlbumSetPage.java +++ b/src/com/android/gallery3d/app/AlbumSetPage.java @@ -322,8 +322,8 @@ public class AlbumSetPage extends ActivityState implements initializeViews(); initializeData(data); Context context = mActivity.getAndroidContext(); - mGetContent = data.getBoolean(Gallery.KEY_GET_CONTENT, false); - mGetAlbum = data.getBoolean(Gallery.KEY_GET_ALBUM, false); + mGetContent = data.getBoolean(GalleryActivity.KEY_GET_CONTENT, false); + mGetAlbum = data.getBoolean(GalleryActivity.KEY_GET_ALBUM, false); mTitle = data.getString(AlbumSetPage.KEY_SET_TITLE); mSubtitle = data.getString(AlbumSetPage.KEY_SET_SUBTITLE); mEyePosition = new EyePosition(context, this); @@ -534,7 +534,7 @@ public class AlbumSetPage extends ActivityState implements if (mGetContent) { inflater.inflate(R.menu.pickup, menu); int typeBits = mData.getInt( - Gallery.KEY_TYPE_BITS, DataManager.INCLUDE_IMAGE); + GalleryActivity.KEY_TYPE_BITS, DataManager.INCLUDE_IMAGE); mActionBar.setTitle(GalleryUtils.getSelectionModePrompt(typeBits)); } else if (mGetAlbum) { inflater.inflate(R.menu.pickup, menu); diff --git a/src/com/android/gallery3d/app/DialogPicker.java b/src/com/android/gallery3d/app/DialogPicker.java index 7ca86e5b4..1de3324b0 100644 --- a/src/com/android/gallery3d/app/DialogPicker.java +++ b/src/com/android/gallery3d/app/DialogPicker.java @@ -33,7 +33,7 @@ public class DialogPicker extends PickerActivity { Bundle extras = intent.getExtras(); Bundle data = extras == null ? new Bundle() : new Bundle(extras); - data.putBoolean(Gallery.KEY_GET_CONTENT, true); + data.putBoolean(GalleryActivity.KEY_GET_CONTENT, true); data.putString(AlbumSetPage.KEY_MEDIA_PATH, getDataManager().getTopSetPath(typeBits)); getStateManager().startState(AlbumSetPage.class, data); diff --git a/src/com/android/gallery3d/app/Gallery.java b/src/com/android/gallery3d/app/Gallery.java index baef56b44..a1b6d01c5 100644 --- a/src/com/android/gallery3d/app/Gallery.java +++ b/src/com/android/gallery3d/app/Gallery.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 The Android Open Source Project + * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,262 +13,25 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.android.gallery3d.app; -import android.app.Dialog; -import android.content.ContentResolver; -import android.content.DialogInterface; -import android.content.DialogInterface.OnCancelListener; +import com.android.gallery3d.util.IntentHelper; + +import android.app.Activity; import android.content.Intent; -import android.net.Uri; import android.os.Bundle; -import android.view.InputDevice; -import android.view.MotionEvent; -import android.view.View; -import android.view.Window; -import android.view.WindowManager; -import android.widget.Toast; - -import com.android.gallery3d.R; -import com.android.gallery3d.common.Utils; -import com.android.gallery3d.data.DataManager; -import com.android.gallery3d.data.MediaItem; -import com.android.gallery3d.data.MediaSet; -import com.android.gallery3d.data.Path; -import com.android.gallery3d.picasasource.PicasaSource; -import com.android.gallery3d.util.GalleryUtils; - -public final class Gallery extends AbstractGalleryActivity implements OnCancelListener { - public static final String EXTRA_SLIDESHOW = "slideshow"; - public static final String EXTRA_DREAM = "dream"; - public static final String EXTRA_CROP = "crop"; - - public static final String ACTION_REVIEW = "com.android.camera.action.REVIEW"; - public static final String KEY_GET_CONTENT = "get-content"; - public static final String KEY_GET_ALBUM = "get-album"; - public static final String KEY_TYPE_BITS = "type-bits"; - public static final String KEY_MEDIA_TYPES = "mediaTypes"; - public static final String KEY_DISMISS_KEYGUARD = "dismiss-keyguard"; - - private static final String TAG = "Gallery"; - private Dialog mVersionCheckDialog; +/** Trampoline activity that launches the Gallery activity defined in IntentHelper. */ +public class Gallery extends Activity { @Override - protected void onCreate(Bundle savedInstanceState) { + public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - requestWindowFeature(Window.FEATURE_ACTION_BAR); - requestWindowFeature(Window.FEATURE_ACTION_BAR_OVERLAY); - - if (getIntent().getBooleanExtra(KEY_DISMISS_KEYGUARD, false)) { - getWindow().addFlags( - WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD); - } - - setContentView(R.layout.main); - - if (savedInstanceState != null) { - getStateManager().restoreFromState(savedInstanceState); - } else { - initializeByIntent(); - } - } - - private void initializeByIntent() { - Intent intent = getIntent(); - String action = intent.getAction(); - - if (Intent.ACTION_GET_CONTENT.equalsIgnoreCase(action)) { - startGetContent(intent); - } else if (Intent.ACTION_PICK.equalsIgnoreCase(action)) { - // We do NOT really support the PICK intent. Handle it as - // the GET_CONTENT. However, we need to translate the type - // in the intent here. - Log.w(TAG, "action PICK is not supported"); - String type = Utils.ensureNotNull(intent.getType()); - if (type.startsWith("vnd.android.cursor.dir/")) { - if (type.endsWith("/image")) intent.setType("image/*"); - if (type.endsWith("/video")) intent.setType("video/*"); - } - startGetContent(intent); - } else if (Intent.ACTION_VIEW.equalsIgnoreCase(action) - || ACTION_REVIEW.equalsIgnoreCase(action)){ - startViewAction(intent); - } else { - startDefaultPage(); - } - } - - public void startDefaultPage() { - PicasaSource.showSignInReminder(this); - Bundle data = new Bundle(); - data.putString(AlbumSetPage.KEY_MEDIA_PATH, - getDataManager().getTopSetPath(DataManager.INCLUDE_ALL)); - getStateManager().startState(AlbumSetPage.class, data); - mVersionCheckDialog = PicasaSource.getVersionCheckDialog(this); - if (mVersionCheckDialog != null) { - mVersionCheckDialog.setOnCancelListener(this); - } - } - - private void startGetContent(Intent intent) { - Bundle data = intent.getExtras() != null - ? new Bundle(intent.getExtras()) - : new Bundle(); - data.putBoolean(KEY_GET_CONTENT, true); - int typeBits = GalleryUtils.determineTypeBits(this, intent); - data.putInt(KEY_TYPE_BITS, typeBits); - data.putString(AlbumSetPage.KEY_MEDIA_PATH, - getDataManager().getTopSetPath(typeBits)); - getStateManager().startState(AlbumSetPage.class, data); - } - - private String getContentType(Intent intent) { - String type = intent.getType(); - if (type != null) { - return GalleryUtils.MIME_TYPE_PANORAMA360.equals(type) - ? MediaItem.MIME_TYPE_JPEG : type; - } - - Uri uri = intent.getData(); - try { - return getContentResolver().getType(uri); - } catch (Throwable t) { - Log.w(TAG, "get type fail", t); - return null; - } - } - - private void startViewAction(Intent intent) { - Boolean slideshow = intent.getBooleanExtra(EXTRA_SLIDESHOW, false); - if (slideshow) { - getActionBar().hide(); - DataManager manager = getDataManager(); - Path path = manager.findPathByUri(intent.getData(), intent.getType()); - if (path == null || manager.getMediaObject(path) - instanceof MediaItem) { - path = Path.fromString( - manager.getTopSetPath(DataManager.INCLUDE_IMAGE)); - } - Bundle data = new Bundle(); - data.putString(SlideshowPage.KEY_SET_PATH, path.toString()); - data.putBoolean(SlideshowPage.KEY_RANDOM_ORDER, true); - data.putBoolean(SlideshowPage.KEY_REPEAT, true); - if (intent.getBooleanExtra(EXTRA_DREAM, false)) { - data.putBoolean(SlideshowPage.KEY_DREAM, true); - } - getStateManager().startState(SlideshowPage.class, data); - } else { - Bundle data = new Bundle(); - DataManager dm = getDataManager(); - Uri uri = intent.getData(); - String contentType = getContentType(intent); - if (contentType == null) { - Toast.makeText(this, - R.string.no_such_item, Toast.LENGTH_LONG).show(); - finish(); - return; - } - if (uri == null) { - int typeBits = GalleryUtils.determineTypeBits(this, intent); - data.putInt(KEY_TYPE_BITS, typeBits); - data.putString(AlbumSetPage.KEY_MEDIA_PATH, - getDataManager().getTopSetPath(typeBits)); - getStateManager().startState(AlbumSetPage.class, data); - } else if (contentType.startsWith( - ContentResolver.CURSOR_DIR_BASE_TYPE)) { - int mediaType = intent.getIntExtra(KEY_MEDIA_TYPES, 0); - if (mediaType != 0) { - uri = uri.buildUpon().appendQueryParameter( - KEY_MEDIA_TYPES, String.valueOf(mediaType)) - .build(); - } - Path setPath = dm.findPathByUri(uri, null); - MediaSet mediaSet = null; - if (setPath != null) { - mediaSet = (MediaSet) dm.getMediaObject(setPath); - } - if (mediaSet != null) { - if (mediaSet.isLeafAlbum()) { - data.putString(AlbumPage.KEY_MEDIA_PATH, setPath.toString()); - data.putString(AlbumPage.KEY_PARENT_MEDIA_PATH, - dm.getTopSetPath(DataManager.INCLUDE_ALL)); - getStateManager().startState(AlbumPage.class, data); - } else { - data.putString(AlbumSetPage.KEY_MEDIA_PATH, setPath.toString()); - getStateManager().startState(AlbumSetPage.class, data); - } - } else { - startDefaultPage(); - } - } else { - Path itemPath = dm.findPathByUri(uri, contentType); - Path albumPath = dm.getDefaultSetOf(itemPath); - - data.putString(PhotoPage.KEY_MEDIA_ITEM_PATH, itemPath.toString()); - - // TODO: Make the parameter "SingleItemOnly" public so other - // activities can reference it. - boolean singleItemOnly = (albumPath == null) - || intent.getBooleanExtra("SingleItemOnly", false); - if (!singleItemOnly) { - data.putString(PhotoPage.KEY_MEDIA_SET_PATH, albumPath.toString()); - // when FLAG_ACTIVITY_NEW_TASK is set, (e.g. when intent is fired - // from notification), back button should behave the same as up button - // rather than taking users back to the home screen - if (intent.getBooleanExtra(PhotoPage.KEY_TREAT_BACK_AS_UP, false) - || ((intent.getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) != 0)) { - data.putBoolean(PhotoPage.KEY_TREAT_BACK_AS_UP, true); - } - } - - getStateManager().startState(SinglePhotoPage.class, data); - } - } - } - - @Override - protected void onResume() { - Utils.assertTrue(getStateManager().getStateCount() > 0); - super.onResume(); - if (mVersionCheckDialog != null) { - mVersionCheckDialog.show(); - } - } - - @Override - protected void onPause() { - super.onPause(); - if (mVersionCheckDialog != null) { - mVersionCheckDialog.dismiss(); - } - } - - @Override - public void onCancel(DialogInterface dialog) { - if (dialog == mVersionCheckDialog) { - mVersionCheckDialog = null; - } - } - - @Override - public boolean onGenericMotionEvent(MotionEvent event) { - final boolean isTouchPad = (event.getSource() - & InputDevice.SOURCE_CLASS_POSITION) != 0; - if (isTouchPad) { - float maxX = event.getDevice().getMotionRange(MotionEvent.AXIS_X).getMax(); - float maxY = event.getDevice().getMotionRange(MotionEvent.AXIS_Y).getMax(); - View decor = getWindow().getDecorView(); - float scaleX = decor.getWidth() / maxX; - float scaleY = decor.getHeight() / maxY; - float x = event.getX() * scaleX; - //x = decor.getWidth() - x; // invert x - float y = event.getY() * scaleY; - //y = decor.getHeight() - y; // invert y - MotionEvent touchEvent = MotionEvent.obtain(event.getDownTime(), - event.getEventTime(), event.getAction(), x, y, event.getMetaState()); - return dispatchTouchEvent(touchEvent); - } - return super.onGenericMotionEvent(event); + Intent intent = IntentHelper.getGalleryIntent(Gallery.this); + // Since this is being launched from a homescreen shortcut, + // it's already in a new task. Start Gallery activity and + // reset the task to its initial state if needed. + intent.setFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); + startActivity(intent); + finish(); } } diff --git a/src/com/android/gallery3d/app/GalleryActivity.java b/src/com/android/gallery3d/app/GalleryActivity.java new file mode 100644 index 000000000..bb2a6b8f1 --- /dev/null +++ b/src/com/android/gallery3d/app/GalleryActivity.java @@ -0,0 +1,275 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.gallery3d.app; + +import android.app.Dialog; +import android.content.ContentResolver; +import android.content.DialogInterface; +import android.content.DialogInterface.OnCancelListener; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.view.InputDevice; +import android.view.MotionEvent; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; +import android.widget.Toast; + +import com.android.gallery3d.R; +import com.android.gallery3d.common.Utils; +import com.android.gallery3d.data.DataManager; +import com.android.gallery3d.data.MediaItem; +import com.android.gallery3d.data.MediaSet; +import com.android.gallery3d.data.Path; +import com.android.gallery3d.picasasource.PicasaSource; +import com.android.gallery3d.util.GalleryUtils; + +public final class GalleryActivity extends AbstractGalleryActivity implements OnCancelListener { + public static final String EXTRA_SLIDESHOW = "slideshow"; + public static final String EXTRA_DREAM = "dream"; + public static final String EXTRA_CROP = "crop"; + + public static final String ACTION_REVIEW = "com.android.camera.action.REVIEW"; + public static final String KEY_GET_CONTENT = "get-content"; + public static final String KEY_GET_ALBUM = "get-album"; + public static final String KEY_TYPE_BITS = "type-bits"; + public static final String KEY_MEDIA_TYPES = "mediaTypes"; + public static final String KEY_DISMISS_KEYGUARD = "dismiss-keyguard"; + + private static final String TAG = "GalleryActivity"; + private Dialog mVersionCheckDialog; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + requestWindowFeature(Window.FEATURE_ACTION_BAR); + requestWindowFeature(Window.FEATURE_ACTION_BAR_OVERLAY); + + if (getIntent().getBooleanExtra(KEY_DISMISS_KEYGUARD, false)) { + getWindow().addFlags( + WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD); + } + + setContentView(R.layout.main); + + if (savedInstanceState != null) { + getStateManager().restoreFromState(savedInstanceState); + } else { + initializeByIntent(); + } + } + + private void initializeByIntent() { + Intent intent = getIntent(); + String action = intent.getAction(); + + if (Intent.ACTION_GET_CONTENT.equalsIgnoreCase(action)) { + startGetContent(intent); + } else if (Intent.ACTION_PICK.equalsIgnoreCase(action)) { + // We do NOT really support the PICK intent. Handle it as + // the GET_CONTENT. However, we need to translate the type + // in the intent here. + Log.w(TAG, "action PICK is not supported"); + String type = Utils.ensureNotNull(intent.getType()); + if (type.startsWith("vnd.android.cursor.dir/")) { + if (type.endsWith("/image")) intent.setType("image/*"); + if (type.endsWith("/video")) intent.setType("video/*"); + } + startGetContent(intent); + } else if (Intent.ACTION_VIEW.equalsIgnoreCase(action) + || ACTION_REVIEW.equalsIgnoreCase(action)){ + startViewAction(intent); + } else { + startDefaultPage(); + } + } + + public void startDefaultPage() { + PicasaSource.showSignInReminder(this); + Bundle data = new Bundle(); + data.putString(AlbumSetPage.KEY_MEDIA_PATH, + getDataManager().getTopSetPath(DataManager.INCLUDE_ALL)); + getStateManager().startState(AlbumSetPage.class, data); + mVersionCheckDialog = PicasaSource.getVersionCheckDialog(this); + if (mVersionCheckDialog != null) { + mVersionCheckDialog.setOnCancelListener(this); + } + } + + private void startGetContent(Intent intent) { + Bundle data = intent.getExtras() != null + ? new Bundle(intent.getExtras()) + : new Bundle(); + data.putBoolean(KEY_GET_CONTENT, true); + int typeBits = GalleryUtils.determineTypeBits(this, intent); + data.putInt(KEY_TYPE_BITS, typeBits); + data.putString(AlbumSetPage.KEY_MEDIA_PATH, + getDataManager().getTopSetPath(typeBits)); + getStateManager().startState(AlbumSetPage.class, data); + } + + private String getContentType(Intent intent) { + String type = intent.getType(); + if (type != null) { + return GalleryUtils.MIME_TYPE_PANORAMA360.equals(type) + ? MediaItem.MIME_TYPE_JPEG : type; + } + + Uri uri = intent.getData(); + try { + return getContentResolver().getType(uri); + } catch (Throwable t) { + Log.w(TAG, "get type fail", t); + return null; + } + } + + private void startViewAction(Intent intent) { + Boolean slideshow = intent.getBooleanExtra(EXTRA_SLIDESHOW, false); + if (slideshow) { + getActionBar().hide(); + DataManager manager = getDataManager(); + Path path = manager.findPathByUri(intent.getData(), intent.getType()); + if (path == null || manager.getMediaObject(path) + instanceof MediaItem) { + path = Path.fromString( + manager.getTopSetPath(DataManager.INCLUDE_IMAGE)); + } + Bundle data = new Bundle(); + data.putString(SlideshowPage.KEY_SET_PATH, path.toString()); + data.putBoolean(SlideshowPage.KEY_RANDOM_ORDER, true); + data.putBoolean(SlideshowPage.KEY_REPEAT, true); + if (intent.getBooleanExtra(EXTRA_DREAM, false)) { + data.putBoolean(SlideshowPage.KEY_DREAM, true); + } + getStateManager().startState(SlideshowPage.class, data); + } else { + Bundle data = new Bundle(); + DataManager dm = getDataManager(); + Uri uri = intent.getData(); + String contentType = getContentType(intent); + if (contentType == null) { + Toast.makeText(this, + R.string.no_such_item, Toast.LENGTH_LONG).show(); + finish(); + return; + } + if (uri == null) { + int typeBits = GalleryUtils.determineTypeBits(this, intent); + data.putInt(KEY_TYPE_BITS, typeBits); + data.putString(AlbumSetPage.KEY_MEDIA_PATH, + getDataManager().getTopSetPath(typeBits)); + getStateManager().startState(AlbumSetPage.class, data); + } else if (contentType.startsWith( + ContentResolver.CURSOR_DIR_BASE_TYPE)) { + int mediaType = intent.getIntExtra(KEY_MEDIA_TYPES, 0); + if (mediaType != 0) { + uri = uri.buildUpon().appendQueryParameter( + KEY_MEDIA_TYPES, String.valueOf(mediaType)) + .build(); + } + Path setPath = dm.findPathByUri(uri, null); + MediaSet mediaSet = null; + if (setPath != null) { + mediaSet = (MediaSet) dm.getMediaObject(setPath); + } + if (mediaSet != null) { + if (mediaSet.isLeafAlbum()) { + data.putString(AlbumPage.KEY_MEDIA_PATH, setPath.toString()); + data.putString(AlbumPage.KEY_PARENT_MEDIA_PATH, + dm.getTopSetPath(DataManager.INCLUDE_ALL)); + getStateManager().startState(AlbumPage.class, data); + } else { + data.putString(AlbumSetPage.KEY_MEDIA_PATH, setPath.toString()); + getStateManager().startState(AlbumSetPage.class, data); + } + } else { + startDefaultPage(); + } + } else { + Path itemPath = dm.findPathByUri(uri, contentType); + Path albumPath = dm.getDefaultSetOf(itemPath); + + data.putString(PhotoPage.KEY_MEDIA_ITEM_PATH, itemPath.toString()); + data.putBoolean(PhotoPage.KEY_READONLY, true); + + // TODO: Make the parameter "SingleItemOnly" public so other + // activities can reference it. + boolean singleItemOnly = (albumPath == null) + || intent.getBooleanExtra("SingleItemOnly", false); + if (!singleItemOnly) { + data.putString(PhotoPage.KEY_MEDIA_SET_PATH, albumPath.toString()); + // when FLAG_ACTIVITY_NEW_TASK is set, (e.g. when intent is fired + // from notification), back button should behave the same as up button + // rather than taking users back to the home screen + if (intent.getBooleanExtra(PhotoPage.KEY_TREAT_BACK_AS_UP, false) + || ((intent.getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) != 0)) { + data.putBoolean(PhotoPage.KEY_TREAT_BACK_AS_UP, true); + } + } + + getStateManager().startState(SinglePhotoPage.class, data); + } + } + } + + @Override + protected void onResume() { + Utils.assertTrue(getStateManager().getStateCount() > 0); + super.onResume(); + if (mVersionCheckDialog != null) { + mVersionCheckDialog.show(); + } + } + + @Override + protected void onPause() { + super.onPause(); + if (mVersionCheckDialog != null) { + mVersionCheckDialog.dismiss(); + } + } + + @Override + public void onCancel(DialogInterface dialog) { + if (dialog == mVersionCheckDialog) { + mVersionCheckDialog = null; + } + } + + @Override + public boolean onGenericMotionEvent(MotionEvent event) { + final boolean isTouchPad = (event.getSource() + & InputDevice.SOURCE_CLASS_POSITION) != 0; + if (isTouchPad) { + float maxX = event.getDevice().getMotionRange(MotionEvent.AXIS_X).getMax(); + float maxY = event.getDevice().getMotionRange(MotionEvent.AXIS_Y).getMax(); + View decor = getWindow().getDecorView(); + float scaleX = decor.getWidth() / maxX; + float scaleY = decor.getHeight() / maxY; + float x = event.getX() * scaleX; + //x = decor.getWidth() - x; // invert x + float y = event.getY() * scaleY; + //y = decor.getHeight() - y; // invert y + MotionEvent touchEvent = MotionEvent.obtain(event.getDownTime(), + event.getEventTime(), event.getAction(), x, y, event.getMetaState()); + return dispatchTouchEvent(touchEvent); + } + return super.onGenericMotionEvent(event); + } +} diff --git a/src/com/android/gallery3d/app/MovieActivity.java b/src/com/android/gallery3d/app/MovieActivity.java index 40edbbe4d..1547f6faf 100644 --- a/src/com/android/gallery3d/app/MovieActivity.java +++ b/src/com/android/gallery3d/app/MovieActivity.java @@ -198,7 +198,7 @@ public class MovieActivity extends Activity { if (mTreatUpAsBack) { finish(); } else { - startActivity(new Intent(this, Gallery.class)); + startActivity(new Intent(this, GalleryActivity.class)); finish(); } return true; diff --git a/src/com/android/gallery3d/app/MoviePlayer.java b/src/com/android/gallery3d/app/MoviePlayer.java index ce9183483..f6bd36725 100644 --- a/src/com/android/gallery3d/app/MoviePlayer.java +++ b/src/com/android/gallery3d/app/MoviePlayer.java @@ -27,6 +27,8 @@ import android.content.Intent; import android.content.IntentFilter; import android.media.AudioManager; import android.media.MediaPlayer; +import android.media.audiofx.AudioEffect; +import android.media.audiofx.Virtualizer; import android.net.Uri; import android.os.Build; import android.os.Bundle; @@ -66,6 +68,7 @@ public class MoviePlayer implements private static final String CMDNAME = "command"; private static final String CMDPAUSE = "pause"; + private static final String VIRTUALIZE_EXTRA = "virtualize"; private static final long BLACK_TIMEOUT = 500; // If we resume the acitivty with in RESUMEABLE_TIMEOUT, we will keep playing. @@ -92,6 +95,8 @@ public class MoviePlayer implements // If the time bar is visible. private boolean mShowing; + private Virtualizer mVirtualizer; + private final Runnable mPlayingChecker = new Runnable() { @Override public void run() { @@ -127,6 +132,18 @@ public class MoviePlayer implements mVideoView.setOnErrorListener(this); mVideoView.setOnCompletionListener(this); mVideoView.setVideoURI(mUri); + + Intent ai = movieActivity.getIntent(); + boolean virtualize = ai.getBooleanExtra(VIRTUALIZE_EXTRA, false); + if (virtualize) { + int session = mVideoView.getAudioSessionId(); + if (session != 0) { + mVirtualizer = new Virtualizer(0, session); + mVirtualizer.setEnabled(true); + } else { + Log.w(TAG, "no audio session to virtualize"); + } + } mVideoView.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { @@ -280,6 +297,10 @@ public class MoviePlayer implements } public void onDestroy() { + if (mVirtualizer != null) { + mVirtualizer.release(); + mVirtualizer = null; + } mVideoView.stopPlayback(); mAudioBecomingNoisyReceiver.unregister(); } diff --git a/src/com/android/gallery3d/app/PhotoPage.java b/src/com/android/gallery3d/app/PhotoPage.java index 1dacb8763..33598887d 100644 --- a/src/com/android/gallery3d/app/PhotoPage.java +++ b/src/com/android/gallery3d/app/PhotoPage.java @@ -35,6 +35,7 @@ import android.os.Message; import android.os.SystemClock; import android.view.Menu; import android.view.MenuItem; +import android.view.View; import android.widget.RelativeLayout; import android.widget.ShareActionProvider; import android.widget.Toast; @@ -63,6 +64,7 @@ import com.android.gallery3d.picasasource.PicasaSource; import com.android.gallery3d.ui.DetailsHelper; import com.android.gallery3d.ui.DetailsHelper.CloseListener; import com.android.gallery3d.ui.DetailsHelper.DetailsSource; +import com.android.gallery3d.ui.GLRootView; import com.android.gallery3d.ui.GLView; import com.android.gallery3d.ui.MenuExecutor; import com.android.gallery3d.ui.PhotoView; @@ -110,6 +112,7 @@ public abstract class PhotoPage extends ActivityState implements public static final String KEY_RETURN_INDEX_HINT = "return-index-hint"; public static final String KEY_SHOW_WHEN_LOCKED = "show_when_locked"; public static final String KEY_IN_CAMERA_ROLL = "in_camera_roll"; + public static final String KEY_READONLY = "read-only"; public static final String KEY_ALBUMPAGE_TRANSITION = "albumpage-transition"; public static final int MSG_ALBUMPAGE_NONE = 0; @@ -149,6 +152,7 @@ public abstract class PhotoPage extends ActivityState implements private boolean mShowSpinner; private String mSetPathString; // This is the original mSetPathString before adding the camera preview item. + private boolean mReadOnlyView = false; private String mOriginalSetPathString; private AppBridge mAppBridge; private SnailItem mScreenNailItem; @@ -180,6 +184,8 @@ public abstract class PhotoPage extends ActivityState implements private final MyMenuVisibilityListener mMenuVisibilityListener = new MyMenuVisibilityListener(); + private int mLastSystemUiVis = 0; + private final PanoramaSupportCallback mUpdatePanoramaMenuItemsCallback = new PanoramaSupportCallback() { @Override public void panoramaInfoAvailable(MediaObject mediaObject, boolean isPanorama, @@ -375,6 +381,7 @@ public abstract class PhotoPage extends ActivityState implements }; mSetPathString = data.getString(KEY_MEDIA_SET_PATH); + mReadOnlyView = data.getBoolean(KEY_READONLY); mOriginalSetPathString = mSetPathString; setupNfcBeamPush(); String itemPathString = data.getString(KEY_MEDIA_ITEM_PATH); @@ -542,6 +549,19 @@ public abstract class PhotoPage extends ActivityState implements mBottomControls = new PhotoPageBottomControls(this, mActivity, galleryRoot); } } + + ((GLRootView) mActivity.getGLRoot()).setOnSystemUiVisibilityChangeListener( + new View.OnSystemUiVisibilityChangeListener() { + @Override + public void onSystemUiVisibilityChange(int visibility) { + int diff = mLastSystemUiVis ^ visibility; + mLastSystemUiVis = visibility; + if ((diff & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0 + && (visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) { + showBars(); + } + } + }); } @Override @@ -565,7 +585,7 @@ public abstract class PhotoPage extends ActivityState implements } switch(control) { case R.id.photopage_bottom_control_edit: - return mHaveImageEditor && mShowBars + return mHaveImageEditor && mShowBars && !mReadOnlyView && !mPhotoView.getFilmMode() && (mCurrentPhoto.getSupportedOperations() & MediaItem.SUPPORT_EDIT) != 0 && mCurrentPhoto.getMediaType() == MediaObject.MEDIA_TYPE_IMAGE; @@ -752,6 +772,9 @@ public abstract class PhotoPage extends ActivityState implements if (mCurrentPhoto == null) return; int supportedOperations = mCurrentPhoto.getSupportedOperations(); + if (mReadOnlyView) { + supportedOperations ^= MediaObject.SUPPORT_EDIT; + } if (mSecureAlbum != null) { supportedOperations &= MediaObject.SUPPORT_DELETE; } else { @@ -760,32 +783,16 @@ public abstract class PhotoPage extends ActivityState implements supportedOperations &= ~MediaObject.SUPPORT_EDIT; } } - MenuExecutor.updateMenuOperation(menu, supportedOperations); } private boolean canDoSlideShow() { - if (mMediaSet == null || mCurrentPhoto == null) { return false; } if (mCurrentPhoto.getMediaType() != MediaObject.MEDIA_TYPE_IMAGE) { return false; } - final int[] count = new int[]{0}; - - mMediaSet.enumerateMediaItems(new MediaSet.ItemConsumer() { - @Override - public void consume(int index, MediaItem item) { - if (item.getMediaType() == MediaObject.MEDIA_TYPE_IMAGE) { - count[0]++; - } - } - }); - - if (count[0] < 2) { // you must have 3 pictures to go into slide show - return false; - } return true; } @@ -1153,8 +1160,8 @@ public abstract class PhotoPage extends ActivityState implements } else if (goBack) { onBackPressed(); } else if (unlock) { - Intent intent = new Intent(mActivity, Gallery.class); - intent.putExtra(Gallery.KEY_DISMISS_KEYGUARD, true); + Intent intent = new Intent(mActivity, GalleryActivity.class); + intent.putExtra(GalleryActivity.KEY_DISMISS_KEYGUARD, true); mActivity.startActivity(intent); } else if (launchCamera) { launchCamera(); diff --git a/src/com/android/gallery3d/app/Wallpaper.java b/src/com/android/gallery3d/app/Wallpaper.java index b0a26c236..4887e7d2d 100644 --- a/src/com/android/gallery3d/app/Wallpaper.java +++ b/src/com/android/gallery3d/app/Wallpaper.java @@ -18,6 +18,8 @@ package com.android.gallery3d.app; import android.annotation.TargetApi; import android.app.Activity; +import android.app.WallpaperManager; +import android.content.ActivityNotFoundException; import android.content.Intent; import android.graphics.Point; import android.net.Uri; @@ -95,24 +97,38 @@ public class Wallpaper extends Activity { // fall-through } case STATE_PHOTO_PICKED: { + Intent cropAndSetWallpaperIntent; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + WallpaperManager wpm = WallpaperManager.getInstance(getApplicationContext()); + try { + cropAndSetWallpaperIntent = wpm.getCropAndSetWallpaperIntent(mPickedItem); + startActivity(cropAndSetWallpaperIntent); + finish(); + return; + } catch (ActivityNotFoundException anfe) { + // ignored; fallthru to existing crop activity + } + } + int width = getWallpaperDesiredMinimumWidth(); int height = getWallpaperDesiredMinimumHeight(); Point size = getDefaultDisplaySize(new Point()); float spotlightX = (float) size.x / width; float spotlightY = (float) size.y / height; - Intent request = new Intent(CropActivity.CROP_ACTION) - .setDataAndType(mPickedItem, IMAGE_TYPE) - .addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT) - .putExtra(CropExtras.KEY_OUTPUT_X, width) - .putExtra(CropExtras.KEY_OUTPUT_Y, height) - .putExtra(CropExtras.KEY_ASPECT_X, width) - .putExtra(CropExtras.KEY_ASPECT_Y, height) - .putExtra(CropExtras.KEY_SPOTLIGHT_X, spotlightX) - .putExtra(CropExtras.KEY_SPOTLIGHT_Y, spotlightY) - .putExtra(CropExtras.KEY_SCALE, true) - .putExtra(CropExtras.KEY_SCALE_UP_IF_NEEDED, true) - .putExtra(CropExtras.KEY_SET_AS_WALLPAPER, true); - startActivity(request); + cropAndSetWallpaperIntent = new Intent(CropActivity.CROP_ACTION) + .setClass(this, CropActivity.class) + .setDataAndType(mPickedItem, IMAGE_TYPE) + .addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT) + .putExtra(CropExtras.KEY_OUTPUT_X, width) + .putExtra(CropExtras.KEY_OUTPUT_Y, height) + .putExtra(CropExtras.KEY_ASPECT_X, width) + .putExtra(CropExtras.KEY_ASPECT_Y, height) + .putExtra(CropExtras.KEY_SPOTLIGHT_X, spotlightX) + .putExtra(CropExtras.KEY_SPOTLIGHT_Y, spotlightY) + .putExtra(CropExtras.KEY_SCALE, true) + .putExtra(CropExtras.KEY_SCALE_UP_IF_NEEDED, true) + .putExtra(CropExtras.KEY_SET_AS_WALLPAPER, true); + startActivity(cropAndSetWallpaperIntent); finish(); } } diff --git a/src/com/android/gallery3d/data/LocalImage.java b/src/com/android/gallery3d/data/LocalImage.java index 94cb05936..2b01c1e22 100644 --- a/src/com/android/gallery3d/data/LocalImage.java +++ b/src/com/android/gallery3d/data/LocalImage.java @@ -237,9 +237,9 @@ public class LocalImage extends LocalMediaItem { @Override public int getSupportedOperations() { int operation = SUPPORT_DELETE | SUPPORT_SHARE | SUPPORT_CROP - | SUPPORT_SETAS | SUPPORT_EDIT | SUPPORT_INFO; + | SUPPORT_SETAS | SUPPORT_PRINT | SUPPORT_INFO; if (BitmapUtils.isSupportedByRegionDecoder(mimeType)) { - operation |= SUPPORT_FULL_IMAGE; + operation |= SUPPORT_FULL_IMAGE | SUPPORT_EDIT; } if (BitmapUtils.isRotationSupported(mimeType)) { diff --git a/src/com/android/gallery3d/data/LocalSource.java b/src/com/android/gallery3d/data/LocalSource.java index a2e3d1443..810aef474 100644 --- a/src/com/android/gallery3d/data/LocalSource.java +++ b/src/com/android/gallery3d/data/LocalSource.java @@ -22,7 +22,7 @@ import android.content.UriMatcher; import android.net.Uri; import android.provider.MediaStore; -import com.android.gallery3d.app.Gallery; +import com.android.gallery3d.app.GalleryActivity; import com.android.gallery3d.app.GalleryApp; import com.android.gallery3d.data.MediaSet.ItemConsumer; @@ -130,7 +130,7 @@ class LocalSource extends MediaSource { private Path getAlbumPath(Uri uri, int defaultType) { int mediaType = getMediaType( - uri.getQueryParameter(Gallery.KEY_MEDIA_TYPES), + uri.getQueryParameter(GalleryActivity.KEY_MEDIA_TYPES), defaultType); String bucketId = uri.getQueryParameter(KEY_BUCKET_ID); int id = 0; diff --git a/src/com/android/gallery3d/data/MediaObject.java b/src/com/android/gallery3d/data/MediaObject.java index 270d4cf0b..530ee306e 100644 --- a/src/com/android/gallery3d/data/MediaObject.java +++ b/src/com/android/gallery3d/data/MediaObject.java @@ -41,6 +41,7 @@ public abstract class MediaObject { public static final int SUPPORT_ACTION = 1 << 14; public static final int SUPPORT_CAMERA_SHORTCUT = 1 << 15; public static final int SUPPORT_MUTE = 1 << 16; + public static final int SUPPORT_PRINT = 1 << 17; public static final int SUPPORT_ALL = 0xffffffff; // These are the bits returned from getMediaType(): diff --git a/src/com/android/gallery3d/data/UriImage.java b/src/com/android/gallery3d/data/UriImage.java index e8875b572..b3fe1de03 100644 --- a/src/com/android/gallery3d/data/UriImage.java +++ b/src/com/android/gallery3d/data/UriImage.java @@ -211,10 +211,10 @@ public class UriImage extends MediaItem { @Override public int getSupportedOperations() { - int supported = SUPPORT_EDIT | SUPPORT_SETAS; + int supported = SUPPORT_PRINT | SUPPORT_SETAS; if (isSharable()) supported |= SUPPORT_SHARE; if (BitmapUtils.isSupportedByRegionDecoder(mContentType)) { - supported |= SUPPORT_FULL_IMAGE; + supported |= SUPPORT_EDIT | SUPPORT_FULL_IMAGE; } return supported; } diff --git a/src/com/android/gallery3d/filtershow/FilterShowActivity.java b/src/com/android/gallery3d/filtershow/FilterShowActivity.java index f46a0b781..3807e1d75 100644 --- a/src/com/android/gallery3d/filtershow/FilterShowActivity.java +++ b/src/com/android/gallery3d/filtershow/FilterShowActivity.java @@ -29,7 +29,9 @@ import android.content.pm.ActivityInfo; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Bitmap; +import android.graphics.Color; import android.graphics.Matrix; +import android.graphics.Point; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.drawable.ColorDrawable; @@ -44,6 +46,7 @@ import android.support.v4.app.DialogFragment; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentTransaction; +import android.support.v4.print.PrintHelper; import android.util.DisplayMetrics; import android.util.Log; import android.util.TypedValue; @@ -57,8 +60,10 @@ import android.view.WindowManager; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.FrameLayout; +import android.widget.PopupMenu; import android.widget.ShareActionProvider; import android.widget.ShareActionProvider.OnShareTargetSelectedListener; +import android.widget.Spinner; import android.widget.Toast; import com.android.gallery3d.R; @@ -87,9 +92,11 @@ import com.android.gallery3d.filtershow.editors.EditorRotate; import com.android.gallery3d.filtershow.editors.EditorStraighten; import com.android.gallery3d.filtershow.editors.EditorTinyPlanet; import com.android.gallery3d.filtershow.editors.ImageOnlyEditor; +import com.android.gallery3d.filtershow.filters.FilterDrawRepresentation; import com.android.gallery3d.filtershow.filters.FilterMirrorRepresentation; import com.android.gallery3d.filtershow.filters.FilterRepresentation; import com.android.gallery3d.filtershow.filters.FilterRotateRepresentation; +import com.android.gallery3d.filtershow.filters.FilterStraightenRepresentation; import com.android.gallery3d.filtershow.filters.FilterUserPresetRepresentation; import com.android.gallery3d.filtershow.filters.FiltersManager; import com.android.gallery3d.filtershow.filters.ImageFilter; @@ -112,8 +119,6 @@ import com.android.gallery3d.filtershow.tools.XmpPresets.XMresults; import com.android.gallery3d.filtershow.ui.ExportDialog; import com.android.gallery3d.filtershow.ui.FramedTextButton; import com.android.gallery3d.util.GalleryUtils; -import com.android.gallery3d.util.PrintJob; -import com.android.gallery3d.util.UsageStatistics; import com.android.photos.data.GalleryBitmapPool; import java.io.File; @@ -124,7 +129,8 @@ import java.util.ArrayList; import java.util.Vector; public class FilterShowActivity extends FragmentActivity implements OnItemClickListener, - OnShareTargetSelectedListener { + OnShareTargetSelectedListener, DialogInterface.OnShowListener, + DialogInterface.OnDismissListener, PopupMenu.OnDismissListener{ private String mAction = ""; MasterImage mMasterImage = null; @@ -133,6 +139,7 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL public static final String TINY_PLANET_ACTION = "com.android.camera.action.TINY_PLANET"; public static final String LAUNCH_FULLSCREEN = "launch-fullscreen"; + public static final boolean RESET_TO_LOADED = false; private ImageShow mImageShow = null; private View mSaveButton = null; @@ -146,7 +153,6 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL private boolean mShowingTinyPlanet = false; private boolean mShowingImageStatePanel = false; private boolean mShowingVersionsPanel = false; - private boolean mShowingInformationPanel = false; private final Vector<ImageShow> mImageViews = new Vector<ImageShow>(); @@ -164,6 +170,7 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL private Uri mSelectedImageUri = null; + private ArrayList<Action> mActions = new ArrayList<Action>(); private UserPresetsManager mUserPresetsManager = null; private UserPresetsAdapter mUserPresetsAdapter = null; private CategoryAdapter mCategoryLooksAdapter = null; @@ -184,6 +191,10 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL private ProcessingService mBoundService; private boolean mIsBound = false; + private Menu mMenu; + private DialogInterface mCurrentDialog = null; + private PopupMenu mCurrentMenu = null; + private boolean mLoadingVisible = true; public ProcessingService getProcessingService() { return mBoundService; @@ -240,17 +251,21 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL } } - private void setupPipeline() { - doBindService(); + public void updateUIAfterServiceStarted() { + MasterImage.setMaster(mMasterImage); ImageFilter.setActivityForMemoryToasts(this); mUserPresetsManager = new UserPresetsManager(this); mUserPresetsAdapter = new UserPresetsAdapter(this); - } - public void updateUIAfterServiceStarted() { + setupMasterImage(); + setupMenu(); + setDefaultValues(); + fillEditors(); + getWindow().setBackgroundDrawable(new ColorDrawable(0)); + loadXML(); + fillCategories(); loadMainPanel(); - setDefaultPreset(); extractXMPData(); processIntent(); } @@ -263,19 +278,11 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL if (onlyUsePortrait) { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); } - MasterImage.setMaster(mMasterImage); clearGalleryBitmapPool(); - setupPipeline(); - - setupMasterImage(); - setDefaultValues(); - fillEditors(); - - loadXML(); - UsageStatistics.onContentViewChanged(UsageStatistics.COMPONENT_EDITOR, "Main"); - UsageStatistics.onEvent(UsageStatistics.COMPONENT_EDITOR, - UsageStatistics.CATEGORY_LIFECYCLE, UsageStatistics.LIFECYCLE_START); + doBindService(); + getWindow().setBackgroundDrawable(new ColorDrawable(Color.GRAY)); + setContentView(R.layout.filtershow_splashscreen); } public boolean isShowingImageStatePanel() { @@ -330,35 +337,12 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL } } - public void hideInformationPanel() { - FrameLayout infoLayout = (FrameLayout) findViewById(R.id.central_panel_container); - infoLayout.setVisibility(View.GONE); - Fragment fragment = getSupportFragmentManager().findFragmentByTag(InfoPanel.FRAGMENT_TAG); - if (fragment != null) { - FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); - transaction.remove(fragment); - transaction.commit(); - } - mShowingInformationPanel = false; - } - public void toggleInformationPanel() { - mShowingInformationPanel = !mShowingInformationPanel; - if (!mShowingInformationPanel) { - hideInformationPanel(); - showDefaultImageView(); - return; - } FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); transaction.setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left); - FrameLayout infoLayout = (FrameLayout) findViewById(R.id.central_panel_container); - infoLayout.setVisibility(View.VISIBLE); - mEditorPlaceHolder.hide(); - mImageShow.setVisibility(View.GONE); InfoPanel panel = new InfoPanel(); - transaction.replace(R.id.central_panel_container, panel, InfoPanel.FRAGMENT_TAG); - transaction.commit(); + panel.show(transaction, InfoPanel.FRAGMENT_TAG); } private void loadXML() { @@ -384,7 +368,7 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL setupEditors(); mEditorPlaceHolder.hide(); - mImageShow.bindAsImageLoadListener(); + mImageShow.attach(); setupStatePanel(); } @@ -403,10 +387,27 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL } private void fillVersions() { + if (mCategoryVersionsAdapter != null) { + mCategoryVersionsAdapter.clear(); + } mCategoryVersionsAdapter = new CategoryAdapter(this); mCategoryVersionsAdapter.setShowAddButton(true); } + public void registerAction(Action action) { + if (mActions.contains(action)) { + return; + } + mActions.add(action); + } + + private void loadActions() { + for (int i = 0; i < mActions.size(); i++) { + Action action = mActions.get(i); + action.setImageFrame(new Rect(0, 0, 96, 96), 0); + } + } + public void updateVersions() { mCategoryVersionsAdapter.clear(); FilterUserPresetRepresentation originalRep = new FilterUserPresetRepresentation( @@ -455,6 +456,9 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL private void fillEffects() { FiltersManager filtersManager = FiltersManager.getManager(); ArrayList<FilterRepresentation> filtersRepresentations = filtersManager.getEffects(); + if (mCategoryFiltersAdapter != null) { + mCategoryFiltersAdapter.clear(); + } mCategoryFiltersAdapter = new CategoryAdapter(this); for (FilterRepresentation representation : filtersRepresentations) { if (representation.getTextId() != 0) { @@ -467,9 +471,22 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL private void fillTools() { FiltersManager filtersManager = FiltersManager.getManager(); ArrayList<FilterRepresentation> filtersRepresentations = filtersManager.getTools(); + if (mCategoryGeometryAdapter != null) { + mCategoryGeometryAdapter.clear(); + } mCategoryGeometryAdapter = new CategoryAdapter(this); + boolean found = false; for (FilterRepresentation representation : filtersRepresentations) { mCategoryGeometryAdapter.add(new Action(this, representation)); + if (representation instanceof FilterDrawRepresentation) { + found = true; + } + } + if (!found) { + FilterRepresentation representation = new FilterDrawRepresentation(); + Action action = new Action(this, representation); + action.setIsDoubleAction(true); + mCategoryGeometryAdapter.add(action); } } @@ -525,13 +542,14 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL int curveHandleSize = (int) res.getDimension(R.dimen.crop_indicator_size); Spline.setCurveHandle(curveHandle, curveHandleSize); Spline.setCurveWidth((int) getPixelsFromDip(3)); + + mOriginalImageUri = null; } private void startLoadBitmap(Uri uri) { - final View loading = findViewById(R.id.loading); final View imageShow = findViewById(R.id.imageShow); imageShow.setVisibility(View.INVISIBLE); - loading.setVisibility(View.VISIBLE); + startLoadingIndicator(); mShowingTinyPlanet = false; mLoadBitmapTask = new LoadBitmapTask(); mLoadBitmapTask.execute(uri); @@ -549,6 +567,9 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL } } + if (mCategoryBordersAdapter != null) { + mCategoryBordersAdapter.clear(); + } mCategoryBordersAdapter = new CategoryAdapter(this); for (FilterRepresentation representation : borders) { if (representation.getTextId() != 0) { @@ -646,6 +667,18 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL FilterMirrorRepresentation r = (FilterMirrorRepresentation) representation; r.cycle(); } + if (representation.isBooleanFilter()) { + ImagePreset preset = MasterImage.getImage().getPreset(); + if (preset.getRepresentation(representation) != null) { + // remove + ImagePreset copy = new ImagePreset(preset); + copy.removeFilter(representation); + FilterRepresentation filterRepresentation = representation.copy(); + MasterImage.getImage().setPreset(copy, filterRepresentation, true); + MasterImage.getImage().setCurrentFilterRepresentation(null); + return; + } + } useFilterRepresentation(representation); // show representation @@ -654,7 +687,6 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL } mCurrentEditor = mEditorPlaceHolder.showEditor(representation.getEditorId()); loadEditorPanel(representation, mCurrentEditor); - hideInformationPanel(); } public Editor getEditor(int editorID) { @@ -670,6 +702,9 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL } public void updateCategories() { + if (mMasterImage == null) { + return; + } ImagePreset preset = mMasterImage.getPreset(); mCategoryLooksAdapter.reflectImagePreset(preset); mCategoryBordersAdapter.reflectImagePreset(preset); @@ -679,6 +714,30 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL return findViewById(id); } + public void onShowMenu(PopupMenu menu) { + mCurrentMenu = menu; + menu.setOnDismissListener(this); + } + + @Override + public void onDismiss(PopupMenu popupMenu){ + if (mCurrentMenu == null) { + return; + } + mCurrentMenu.setOnDismissListener(null); + mCurrentMenu = null; + } + + @Override + public void onShow(DialogInterface dialog) { + mCurrentDialog = dialog; + } + + @Override + public void onDismiss(DialogInterface dialogInterface) { + mCurrentDialog = null; + } + private class LoadHighresBitmapTask extends AsyncTask<Void, Void, Boolean> { @Override protected Boolean doInBackground(Void... params) { @@ -713,6 +772,22 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL } } + public boolean isLoadingVisible() { + return mLoadingVisible; + } + + public void startLoadingIndicator() { + final View loading = findViewById(R.id.loading); + mLoadingVisible = true; + loading.setVisibility(View.VISIBLE); + } + + public void stopLoadingIndicator() { + final View loading = findViewById(R.id.loading); + loading.setVisibility(View.GONE); + mLoadingVisible = false; + } + private class LoadBitmapTask extends AsyncTask<Uri, Boolean, Boolean> { int mBitmapSize; @@ -748,7 +823,8 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL } if (!result) { - if (!mOriginalImageUri.equals(mSelectedImageUri)) { + if (mOriginalImageUri != null + && !mOriginalImageUri.equals(mSelectedImageUri)) { mOriginalImageUri = mSelectedImageUri; mOriginalPreset = null; Toast.makeText(FilterShowActivity.this, @@ -764,14 +840,12 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL Log.v(LOGTAG,"RenderScript context destroyed during load"); return; } - final View loading = findViewById(R.id.loading); - loading.setVisibility(View.GONE); final View imageShow = findViewById(R.id.imageShow); imageShow.setVisibility(View.VISIBLE); + Bitmap largeBitmap = MasterImage.getImage().getOriginalBitmapLarge(); mBoundService.setOriginalBitmap(largeBitmap); - MasterImage.getImage().resetGeometryImages(true); float previewScale = (float) largeBitmap.getWidth() / (float) MasterImage.getImage().getOriginalBounds().width(); @@ -785,13 +859,20 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL mCategoryFiltersAdapter.imageLoaded(); mLoadBitmapTask = null; + MasterImage.getImage().warnListeners(); + loadActions(); + if (mOriginalPreset != null) { MasterImage.getImage().setLoadedPreset(mOriginalPreset); MasterImage.getImage().setPreset(mOriginalPreset, mOriginalPreset.getLastRepresentation(), true); mOriginalPreset = null; + } else { + setDefaultPreset(); } + MasterImage.getImage().resetGeometryImages(true); + if (mAction == TINY_PLANET_ACTION) { showRepresentation(mCategoryFiltersAdapter.getTinyPlanet()); } @@ -916,12 +997,23 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL .getActionProvider(); mShareActionProvider.setShareIntent(getDefaultShareIntent()); mShareActionProvider.setOnShareTargetSelectedListener(this); + mMenu = menu; + setupMenu(); + return true; + } - MenuItem undoItem = menu.findItem(R.id.undoButton); - MenuItem redoItem = menu.findItem(R.id.redoButton); - MenuItem resetItem = menu.findItem(R.id.resetHistoryButton); + private void setupMenu(){ + if (mMenu == null || mMasterImage == null) { + return; + } + MenuItem undoItem = mMenu.findItem(R.id.undoButton); + MenuItem redoItem = mMenu.findItem(R.id.redoButton); + MenuItem resetItem = mMenu.findItem(R.id.resetHistoryButton); + MenuItem printItem = mMenu.findItem(R.id.printButton); + if (!PrintHelper.systemSupportsPrint()) { + printItem.setVisible(false); + } mMasterImage.getHistory().setMenuItems(undoItem, redoItem, resetItem); - return true; } @Override @@ -949,8 +1041,6 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL mMasterImage.onHistoryItemClick(position); backToMain(); invalidateViews(); - UsageStatistics.onEvent(UsageStatistics.COMPONENT_EDITOR, - UsageStatistics.CATEGORY_BUTTON_PRESS, "Undo"); return true; } case R.id.redoButton: { @@ -958,21 +1048,14 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL int position = adapter.redo(); mMasterImage.onHistoryItemClick(position); invalidateViews(); - UsageStatistics.onEvent(UsageStatistics.COMPONENT_EDITOR, - UsageStatistics.CATEGORY_BUTTON_PRESS, "Redo"); return true; } case R.id.resetHistoryButton: { resetHistory(); - UsageStatistics.onEvent(UsageStatistics.COMPONENT_EDITOR, - UsageStatistics.CATEGORY_BUTTON_PRESS, "ResetHistory"); return true; } case R.id.showImageStateButton: { toggleImageStatePanel(); - UsageStatistics.onEvent(UsageStatistics.COMPONENT_EDITOR, - UsageStatistics.CATEGORY_BUTTON_PRESS, - mShowingImageStatePanel ? "ShowPanel" : "HidePanel"); return true; } case R.id.exportFlattenButton: { @@ -1001,7 +1084,8 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL public void print() { Bitmap bitmap = MasterImage.getImage().getHighresImage(); - PrintJob.printBitmap(this, "ImagePrint", bitmap); + PrintHelper printer = new PrintHelper(this); + printer.printBitmap("ImagePrint", bitmap); } public void addNewPreset() { @@ -1087,6 +1171,9 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL FiltersManager filtersManager = FiltersManager.getManager(); ArrayList<FilterRepresentation> filtersRepresentations = filtersManager.getLooks(); + if (mCategoryLooksAdapter != null) { + mCategoryLooksAdapter.clear(); + } mCategoryLooksAdapter = new CategoryAdapter(this); int verticalItemHeight = (int) getResources().getDimension(R.dimen.action_item_height); mCategoryLooksAdapter.setItemHeight(verticalItemHeight); @@ -1161,17 +1248,28 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); + setDefaultValues(); + if (mMasterImage == null) { + return; + } loadXML(); fillCategories(); loadMainPanel(); + if (mCurrentMenu != null) { + mCurrentMenu.dismiss(); + mCurrentMenu = null; + } + if (mCurrentDialog != null) { + mCurrentDialog.dismiss(); + mCurrentDialog = null; + } // mLoadBitmapTask==null implies you have looked at the intent if (!mShowingTinyPlanet && (mLoadBitmapTask == null)) { mCategoryFiltersAdapter.removeTinyPlanet(); } - final View loading = findViewById(R.id.loading); - loading.setVisibility(View.GONE); + stopLoadingIndicator(); } public void setupMasterImage() { @@ -1195,14 +1293,22 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL HistoryManager adapter = mMasterImage.getHistory(); adapter.reset(); HistoryItem historyItem = adapter.getItem(0); - ImagePreset original = new ImagePreset(historyItem.getImagePreset()); - mMasterImage.setPreset(original, historyItem.getFilterRepresentation(), true); + ImagePreset original = null; + if (RESET_TO_LOADED) { + original = new ImagePreset(historyItem.getImagePreset()); + } else { + original = new ImagePreset(); + } + FilterRepresentation rep = null; + if (historyItem != null) { + rep = historyItem.getFilterRepresentation(); + } + mMasterImage.setPreset(original, rep, true); invalidateViews(); backToMain(); } public void showDefaultImageView() { - hideInformationPanel(); mEditorPlaceHolder.hide(); mImageShow.setVisibility(View.VISIBLE); MasterImage.getImage().setCurrentFilter(null); @@ -1374,11 +1480,23 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL return super.dispatchTouchEvent(ev); } + public Point mHintTouchPoint = new Point(); + + public Point hintTouchPoint(View view) { + int location[] = new int[2]; + view.getLocationOnScreen(location); + int x = mHintTouchPoint.x - location[0]; + int y = mHintTouchPoint.y - location[1]; + return new Point(x, y); + } + public void startTouchAnimation(View target, float x, float y) { final CategorySelected hint = (CategorySelected) findViewById(R.id.categorySelectedIndicator); int location[] = new int[2]; target.getLocationOnScreen(location); + mHintTouchPoint.x = (int) (location[0] + x); + mHintTouchPoint.y = (int) (location[1] + y); int locationHint[] = new int[2]; ((View)hint.getParent()).getLocationOnScreen(locationHint); int dx = (int) (x - (hint.getWidth())/2); diff --git a/src/com/android/gallery3d/filtershow/cache/BitmapCache.java b/src/com/android/gallery3d/filtershow/cache/BitmapCache.java index 339ddf07d..cd63d309a 100644 --- a/src/com/android/gallery3d/filtershow/cache/BitmapCache.java +++ b/src/com/android/gallery3d/filtershow/cache/BitmapCache.java @@ -20,6 +20,7 @@ import android.graphics.Bitmap; import android.graphics.Canvas; import android.util.Log; import com.android.gallery3d.filtershow.pipeline.Buffer; +import com.android.gallery3d.filtershow.pipeline.CacheProcessing; import java.lang.ref.WeakReference; import java.util.ArrayList; @@ -31,6 +32,92 @@ public class BitmapCache { mBitmapCache = new HashMap<Long, ArrayList<WeakReference<Bitmap>>>(); private final int mMaxItemsPerKey = 4; + private static final boolean DEBUG = false; + private CacheProcessing mCacheProcessing; + + public final static int PREVIEW_CACHE = 1; + public final static int NEW_LOOK = 2; + public final static int ICON = 3; + public final static int FILTERS = 4; + public final static int GEOMETRY = 5; + public final static int HIGHRES = 6; + public final static int UTIL_GEOMETRY = 7; + public final static int RENDERING_REQUEST = 8; + public final static int REGION = 9; + public final static int TINY_PLANET = 10; + public final static int PREVIEW_CACHE_NO_FILTERS = 11; + public final static int PREVIEW_CACHE_NO_ROOT = 12; + public static final int PREVIEW_CACHE_NO_APPLY = 13; + public final static int TRACKING_COUNT = 14; + private int[] mTracking = new int[TRACKING_COUNT]; + + class BitmapTracking { + Bitmap bitmap; + int type; + } + + private ArrayList<BitmapTracking> mBitmapTracking = new ArrayList<BitmapTracking>(); + + private void track(Bitmap bitmap, int type) { + for (int i = 0; i < mBitmapTracking.size(); i++) { + BitmapTracking tracking = mBitmapTracking.get(i); + if (tracking.bitmap == bitmap) { + Log.e(LOGTAG, "giving a bitmap already given!!!"); + } + } + BitmapTracking tracking = new BitmapTracking(); + tracking.bitmap = bitmap; + tracking.type = type; + mBitmapTracking.add(tracking); + mTracking[tracking.type] ++; + } + + private void untrack(Bitmap bitmap) { + for (int i = 0; i < mBitmapTracking.size(); i++) { + BitmapTracking tracking = mBitmapTracking.get(i); + if (tracking.bitmap == bitmap) { + mTracking[tracking.type] --; + mBitmapTracking.remove(i); + return; + } + } + } + + public String getTrackingName(int i) { + switch (i) { + case PREVIEW_CACHE: return "PREVIEW_CACHE"; + case PREVIEW_CACHE_NO_FILTERS: return "PREVIEW_CACHE_NO_FILTERS"; + case PREVIEW_CACHE_NO_ROOT: return "PREVIEW_CACHE_NO_ROOT"; + case PREVIEW_CACHE_NO_APPLY: return "PREVIEW_CACHE_NO_APPLY"; + case NEW_LOOK: return "NEW_LOOK"; + case ICON: return "ICON"; + case FILTERS: return "FILTERS"; + case GEOMETRY: return "GEOMETRY"; + case HIGHRES: return "HIGHRES"; + case UTIL_GEOMETRY: return "UTIL_GEOMETRY"; + case RENDERING_REQUEST: return "RENDERING_REQUEST"; + case REGION: return "REGION"; + case TINY_PLANET: return "TINY_PLANET"; + } + return "UNKNOWN"; + } + + public void showBitmapCounts() { + if (!DEBUG) { + return; + } + Log.v(LOGTAG, "\n--- showBitmap --- "); + for (int i = 0; i < TRACKING_COUNT; i++) { + if (mTracking[i] != 0) { + Log.v(LOGTAG, getTrackingName(i) + " => " + mTracking[i]); + } + } + } + + public void setCacheProcessing(CacheProcessing cache) { + mCacheProcessing = cache; + } + public void cache(Buffer buffer) { if (buffer == null) { return; @@ -39,9 +126,20 @@ public class BitmapCache { cache(bitmap); } - public synchronized void cache(Bitmap bitmap) { + public synchronized boolean cache(Bitmap bitmap) { if (bitmap == null) { - return; + return true; + } + if (mCacheProcessing != null && mCacheProcessing.contains(bitmap)) { + Log.e(LOGTAG, "Trying to cache a bitmap still used in the pipeline"); + return false; + } + if (DEBUG) { + untrack(bitmap); + } + if (!bitmap.isMutable()) { + Log.e(LOGTAG, "Trying to cache a non mutable bitmap"); + return true; } Long key = calcKey(bitmap.getWidth(), bitmap.getHeight()); ArrayList<WeakReference<Bitmap>> list = mBitmapCache.get(key); @@ -66,14 +164,15 @@ public class BitmapCache { for (i = 0; i < list.size(); i++) { WeakReference<Bitmap> ref = list.get(i); if (ref.get() == bitmap) { - return; // bitmap already in the cache + return true; // bitmap already in the cache } } list.add(new WeakReference<Bitmap>(bitmap)); } + return true; } - public synchronized Bitmap getBitmap(int w, int h) { + public synchronized Bitmap getBitmap(int w, int h, int type) { Long key = calcKey(w, h); WeakReference<Bitmap> ref = null; ArrayList<WeakReference<Bitmap>> list = mBitmapCache.get(key); @@ -92,12 +191,20 @@ public class BitmapCache { || bitmap.getHeight() != h) { bitmap = Bitmap.createBitmap( w, h, Bitmap.Config.ARGB_8888); + showBitmapCounts(); + } + + if (DEBUG) { + track(bitmap, type); + if (mCacheProcessing != null && mCacheProcessing.contains(bitmap)) { + Log.e(LOGTAG, "Trying to give a bitmap used in the pipeline"); + } } return bitmap; } - public Bitmap getBitmapCopy(Bitmap source) { - Bitmap bitmap = getBitmap(source.getWidth(), source.getHeight()); + public synchronized Bitmap getBitmapCopy(Bitmap source, int type) { + Bitmap bitmap = getBitmap(source.getWidth(), source.getHeight(), type); Canvas canvas = new Canvas(bitmap); canvas.drawBitmap(source, 0, 0, null); return bitmap; diff --git a/src/com/android/gallery3d/filtershow/cache/ImageLoader.java b/src/com/android/gallery3d/filtershow/cache/ImageLoader.java index 30cd3f33c..69edd6051 100644 --- a/src/com/android/gallery3d/filtershow/cache/ImageLoader.java +++ b/src/com/android/gallery3d/filtershow/cache/ImageLoader.java @@ -65,7 +65,7 @@ public final class ImageLoader { public static final int ORI_TRANSVERSE = ExifInterface.Orientation.LEFT_BOTTOM; private static final int BITMAP_LOAD_BACKOUT_ATTEMPTS = 5; - + private static final float OVERDRAW_ZOOM = 1.2f; private ImageLoader() {} /** @@ -124,6 +124,8 @@ public final class ImageLoader { // Do nothing } catch (IllegalArgumentException e) { // Do nothing + } catch (IllegalStateException e) { + // Do nothing } finally { Utils.closeSilently(cursor); } @@ -233,7 +235,7 @@ public final class ImageLoader { * if it is a subset of the bitmap stored at uri. Otherwise returns * null. */ - public static Bitmap loadRegionBitmap(Context context, FilterEnvironment environment, + public static Bitmap loadRegionBitmap(Context context, BitmapCache cache, Uri uri, BitmapFactory.Options options, Rect bounds) { InputStream is = null; @@ -252,21 +254,15 @@ public final class ImageLoader { // return null if bounds are not entirely within the bitmap if (!r.contains(imageBounds)) { imageBounds.intersect(r); + bounds.left = imageBounds.left; + bounds.top = imageBounds.top; } - Bitmap reuse = environment.getBitmap(imageBounds.width(), imageBounds.height()); + Bitmap reuse = cache.getBitmap(imageBounds.width(), + imageBounds.height(), BitmapCache.REGION); options.inBitmap = reuse; Bitmap bitmap = decoder.decodeRegion(imageBounds, options); if (bitmap != reuse) { - environment.cache(reuse); // not reused, put back in cache - } - if (imageBounds.width() != bounds.width() || imageBounds.height() != bounds.height()) { - Bitmap temp = environment.getBitmap(bounds.width(), bounds.height()); - Canvas canvas = new Canvas(temp); - canvas.drawARGB(0, 0, 0, 0); - float dx = imageBounds.left - bounds.left; - float dy = imageBounds.top - bounds.top; - canvas.drawBitmap(bitmap, dx, dy, null); - return temp; + cache.cache(reuse); // not reused, put back in cache } return bitmap; } catch (FileNotFoundException e) { @@ -288,6 +284,7 @@ public final class ImageLoader { */ public static Rect loadBitmapBounds(Context context, Uri uri) { BitmapFactory.Options o = new BitmapFactory.Options(); + o.inJustDecodeBounds = true; loadBitmap(context, uri, o); return new Rect(0, 0, o.outWidth, o.outHeight); } @@ -400,24 +397,24 @@ public final class ImageLoader { } public static Bitmap getScaleOneImageForPreset(Context context, - FilterEnvironment environment, + BitmapCache cache, Uri uri, Rect bounds, Rect destination) { BitmapFactory.Options options = new BitmapFactory.Options(); options.inMutable = true; if (destination != null) { - if (bounds.width() > destination.width()) { + int thresholdWidth = (int) (destination.width() * OVERDRAW_ZOOM); + if (bounds.width() > thresholdWidth) { int sampleSize = 1; int w = bounds.width(); - while (w > destination.width()) { + while (w > thresholdWidth) { sampleSize *= 2; w /= sampleSize; } options.inSampleSize = sampleSize; } } - Bitmap bmp = loadRegionBitmap(context, environment, uri, options, bounds); - return bmp; + return loadRegionBitmap(context, cache, uri, options, bounds); } /** diff --git a/src/com/android/gallery3d/filtershow/category/Action.java b/src/com/android/gallery3d/filtershow/category/Action.java index 7bdc8ec90..b3a4148eb 100644 --- a/src/com/android/gallery3d/filtershow/category/Action.java +++ b/src/com/android/gallery3d/filtershow/category/Action.java @@ -24,8 +24,13 @@ import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.RectF; +import android.util.Log; import android.widget.ArrayAdapter; import android.widget.ListAdapter; + +import com.android.gallery3d.R; +import com.android.gallery3d.filtershow.FilterShowActivity; +import com.android.gallery3d.filtershow.filters.FilterDrawRepresentation; import com.android.gallery3d.filtershow.filters.FilterUserPresetRepresentation; import com.android.gallery3d.filtershow.pipeline.RenderingRequest; import com.android.gallery3d.filtershow.pipeline.RenderingRequestCaller; @@ -48,29 +53,42 @@ public class Action implements RenderingRequestCaller { private int mType = CROP_VIEW; private Bitmap mPortraitImage; private Bitmap mOverlayBitmap; - private Context mContext; + private FilterShowActivity mContext; private boolean mCanBeRemoved = false; + private int mTextSize = 32; + private boolean mIsDoubleAction = false; - public Action(Context context, FilterRepresentation representation, int type, + public Action(FilterShowActivity context, FilterRepresentation representation, int type, boolean canBeRemoved) { this(context, representation, type); mCanBeRemoved = canBeRemoved; + mTextSize = context.getResources().getDimensionPixelSize( + R.dimen.category_panel_text_size); } - public Action(Context context, FilterRepresentation representation, int type) { + public Action(FilterShowActivity context, FilterRepresentation representation, int type) { this(context, type); setRepresentation(representation); } - public Action(Context context, int type) { + public Action(FilterShowActivity context, int type) { mContext = context; setType(type); + mContext.registerAction(this); } - public Action(Context context, FilterRepresentation representation) { + public Action(FilterShowActivity context, FilterRepresentation representation) { this(context, representation, CROP_VIEW); } + public boolean isDoubleAction() { + return mIsDoubleAction; + } + + public void setIsDoubleAction(boolean value) { + mIsDoubleAction = value; + } + public boolean canBeRemoved() { return mCanBeRemoved; } @@ -100,19 +118,19 @@ public class Action implements RenderingRequestCaller { if (mImageFrame != null && mImageFrame.equals(imageFrame)) { return; } - Bitmap bitmap = MasterImage.getImage().getLargeThumbnailBitmap(); + if (getType() == Action.ADD_ACTION) { + return; + } + Bitmap temp = MasterImage.getImage().getTemporaryThumbnailBitmap(); + if (temp != null) { + mImage = temp; + } + Bitmap bitmap = MasterImage.getImage().getThumbnailBitmap(); if (bitmap != null) { mImageFrame = imageFrame; int w = mImageFrame.width(); int h = mImageFrame.height(); - if (orientation == CategoryView.VERTICAL - && mType == CROP_VIEW) { - w /= 2; - } - Bitmap bitmapCrop = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); - drawCenteredImage(bitmap, bitmapCrop, true); - - postNewIconRenderRequest(bitmapCrop); + postNewIconRenderRequest(w, h); } } @@ -132,40 +150,37 @@ public class Action implements RenderingRequestCaller { mType = type; } - private void postNewIconRenderRequest(Bitmap bitmap) { - if (bitmap != null && mRepresentation != null) { + private void postNewIconRenderRequest(int w, int h) { + if (mRepresentation != null) { ImagePreset preset = new ImagePreset(); preset.addFilter(mRepresentation); - RenderingRequest.post(mContext, bitmap, - preset, RenderingRequest.ICON_RENDERING, this); + RenderingRequest.postIconRequest(mContext, w, h, preset, this); } } private void drawCenteredImage(Bitmap source, Bitmap destination, boolean scale) { - RectF image = new RectF(0, 0, source.getWidth(), source.getHeight()); - int border = 0; - if (!scale) { - border = destination.getWidth() - destination.getHeight(); - if (border < 0) { - border = 0; - } - } - RectF frame = new RectF(border, 0, - destination.getWidth() - border, - destination.getHeight()); + int minSide = Math.min(destination.getWidth(), destination.getHeight()); Matrix m = new Matrix(); - m.setRectToRect(frame, image, Matrix.ScaleToFit.CENTER); - image.set(frame); - m.mapRect(image); - m.setRectToRect(image, frame, Matrix.ScaleToFit.FILL); + float scaleFactor = minSide / (float) Math.min(source.getWidth(), source.getHeight()); + + float dx = (destination.getWidth() - source.getWidth() * scaleFactor) / 2.0f; + float dy = (destination.getHeight() - source.getHeight() * scaleFactor) / 2.0f; + if (mImageFrame.height() > mImageFrame.width()) { + // if portrait + dy -= mTextSize; + } + m.setScale(scaleFactor, scaleFactor); + m.postTranslate(dx, dy); Canvas canvas = new Canvas(destination); canvas.drawBitmap(source, m, new Paint(Paint.FILTER_BITMAP_FLAG)); } @Override public void available(RenderingRequest request) { + clearBitmap(); mImage = request.getBitmap(); if (mImage == null) { + mImageFrame = null; return; } if (mRepresentation.getOverlayId() != 0 && mOverlayBitmap == null) { @@ -204,4 +219,12 @@ public class Action implements RenderingRequestCaller { public void setOverlayBitmap(Bitmap overlayBitmap) { mOverlayBitmap = overlayBitmap; } + + public void clearBitmap() { + if (mImage != null + && mImage != MasterImage.getImage().getTemporaryThumbnailBitmap()) { + MasterImage.getImage().getBitmapCache().cache(mImage); + } + mImage = null; + } } diff --git a/src/com/android/gallery3d/filtershow/category/CategoryAdapter.java b/src/com/android/gallery3d/filtershow/category/CategoryAdapter.java index 51ae07fc2..09f02dd37 100644 --- a/src/com/android/gallery3d/filtershow/category/CategoryAdapter.java +++ b/src/com/android/gallery3d/filtershow/category/CategoryAdapter.java @@ -49,6 +49,15 @@ public class CategoryAdapter extends ArrayAdapter<Action> { this(context, 0); } + @Override + public void clear() { + for (int i = 0; i < getCount(); i++) { + Action action = getItem(i); + action.clearBitmap(); + } + super.clear(); + } + public void setItemHeight(int height) { mItemHeight = height; } diff --git a/src/com/android/gallery3d/filtershow/category/CategoryPanel.java b/src/com/android/gallery3d/filtershow/category/CategoryPanel.java index d1b7d1858..fb51bf5ad 100644 --- a/src/com/android/gallery3d/filtershow/category/CategoryPanel.java +++ b/src/com/android/gallery3d/filtershow/category/CategoryPanel.java @@ -54,29 +54,39 @@ public class CategoryPanel extends Fragment implements View.OnClickListener { switch (adapter) { case MainPanel.LOOKS: { mAdapter = activity.getCategoryLooksAdapter(); - mAdapter.initializeSelection(MainPanel.LOOKS); + if (mAdapter != null) { + mAdapter.initializeSelection(MainPanel.LOOKS); + } activity.updateCategories(); break; } case MainPanel.BORDERS: { mAdapter = activity.getCategoryBordersAdapter(); - mAdapter.initializeSelection(MainPanel.BORDERS); + if (mAdapter != null) { + mAdapter.initializeSelection(MainPanel.BORDERS); + } activity.updateCategories(); break; } case MainPanel.GEOMETRY: { mAdapter = activity.getCategoryGeometryAdapter(); - mAdapter.initializeSelection(MainPanel.GEOMETRY); + if (mAdapter != null) { + mAdapter.initializeSelection(MainPanel.GEOMETRY); + } break; } case MainPanel.FILTERS: { mAdapter = activity.getCategoryFiltersAdapter(); - mAdapter.initializeSelection(MainPanel.FILTERS); + if (mAdapter != null) { + mAdapter.initializeSelection(MainPanel.FILTERS); + } break; } case MainPanel.VERSIONS: { mAdapter = activity.getCategoryVersionsAdapter(); - mAdapter.initializeSelection(MainPanel.VERSIONS); + if (mAdapter != null) { + mAdapter.initializeSelection(MainPanel.VERSIONS); + } break; } } @@ -104,10 +114,12 @@ public class CategoryPanel extends Fragment implements View.OnClickListener { View panelView = main.findViewById(R.id.listItems); if (panelView instanceof CategoryTrack) { CategoryTrack panel = (CategoryTrack) panelView; - mAdapter.setOrientation(CategoryView.HORIZONTAL); - panel.setAdapter(mAdapter); - mAdapter.setContainer(panel); - } else { + if (mAdapter != null) { + mAdapter.setOrientation(CategoryView.HORIZONTAL); + panel.setAdapter(mAdapter); + mAdapter.setContainer(panel); + } + } else if (mAdapter != null) { ListView panel = (ListView) main.findViewById(R.id.listItems); panel.setAdapter(mAdapter); mAdapter.setContainer(panel); diff --git a/src/com/android/gallery3d/filtershow/category/CategorySelected.java b/src/com/android/gallery3d/filtershow/category/CategorySelected.java index 1a6135bb8..42058c0db 100644 --- a/src/com/android/gallery3d/filtershow/category/CategorySelected.java +++ b/src/com/android/gallery3d/filtershow/category/CategorySelected.java @@ -7,21 +7,25 @@ import android.graphics.Paint; import android.util.AttributeSet; import android.view.View; +import com.android.gallery3d.R; + public class CategorySelected extends View { - Paint mPaint = new Paint(); + private Paint mPaint = new Paint(); + private int mMargin = 20; public CategorySelected(Context context, AttributeSet attrs) { super(context, attrs); + mMargin = getResources().getDimensionPixelSize(R.dimen.touch_circle_size); } public void onDraw(Canvas canvas) { mPaint.reset(); - int margin = 20; - mPaint.setStrokeWidth(margin); + mPaint.setStrokeWidth(mMargin); mPaint.setAntiAlias(true); mPaint.setStyle(Paint.Style.STROKE); - mPaint.setColor(Color.GRAY); - canvas.drawCircle(getWidth()/2, getHeight()/2, getWidth()/2 - margin, mPaint); + mPaint.setColor(Color.argb(128, 128, 128, 128)); + canvas.drawCircle(getWidth()/2, getHeight()/2, + getWidth()/2 - mMargin, mPaint); } } diff --git a/src/com/android/gallery3d/filtershow/category/CategoryView.java b/src/com/android/gallery3d/filtershow/category/CategoryView.java index c613c2174..1570517ea 100644 --- a/src/com/android/gallery3d/filtershow/category/CategoryView.java +++ b/src/com/android/gallery3d/filtershow/category/CategoryView.java @@ -49,6 +49,8 @@ public class CategoryView extends IconView private int mSelectionColor = Color.WHITE; private int mSpacerColor = Color.WHITE; private boolean mCanBeRemoved = false; + private long mDoubleActionLast = 0; + private long mDoubleTapDelay = 250; public CategoryView(Context context) { super(context); @@ -109,9 +111,11 @@ public class CategoryView extends IconView drawSpacer(canvas); return; } - if (mAction.getImage() == null) { - mAction.setImageFrame(new Rect(0, 0, getWidth(), getHeight()), getOrientation()); - } else { + if (mAction.isDoubleAction()) { + return; + } + mAction.setImageFrame(new Rect(0, 0, getWidth(), getHeight()), getOrientation()); + if (mAction.getImage() != null) { setBitmap(mAction.getImage()); } } @@ -146,7 +150,15 @@ public class CategoryView extends IconView if (mAction.getType() == Action.ADD_ACTION) { activity.addNewPreset(); } else if (mAction.getType() != Action.SPACER) { - activity.showRepresentation(mAction.getRepresentation()); + if (mAction.isDoubleAction()) { + long current = System.currentTimeMillis() - mDoubleActionLast; + if (current < mDoubleTapDelay) { + activity.showRepresentation(mAction.getRepresentation()); + } + mDoubleActionLast = System.currentTimeMillis(); + } else { + activity.showRepresentation(mAction.getRepresentation()); + } mAdapter.setSelected(this); } } diff --git a/src/com/android/gallery3d/filtershow/category/IconView.java b/src/com/android/gallery3d/filtershow/category/IconView.java index 0443823c9..cba2d794f 100644 --- a/src/com/android/gallery3d/filtershow/category/IconView.java +++ b/src/com/android/gallery3d/filtershow/category/IconView.java @@ -193,6 +193,7 @@ public class IconView extends View { public void onDraw(Canvas canvas) { mPaint.reset(); mPaint.setAntiAlias(true); + mPaint.setFilterBitmap(true); canvas.drawColor(mBackgroundColor); computeBitmapBounds(); computeTextPosition(getText()); diff --git a/src/com/android/gallery3d/filtershow/colorpicker/ColorCompareView.java b/src/com/android/gallery3d/filtershow/colorpicker/ColorCompareView.java new file mode 100644 index 000000000..15996713a --- /dev/null +++ b/src/com/android/gallery3d/filtershow/colorpicker/ColorCompareView.java @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.gallery3d.filtershow.colorpicker; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.BitmapShader; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.Shader; +import android.util.AttributeSet; +import android.util.DisplayMetrics; +import android.view.MotionEvent; +import android.view.View; + +import com.android.gallery3d.R; + +import java.util.ArrayList; + +public class ColorCompareView extends View implements ColorListener { + + private float mRadius; + private float mWidth; + private Paint mBarPaint1; + private Paint mOrigBarPaint1; + private Paint mCheckPaint; + + private float mHeight; + + private int mBgcolor = 0; + + private float mBorder; + + private float[] mHSVO = new float[4]; + private float[] mOrigHSVO = new float[4]; + private Path mRegion; + private Path mOrigRegion; + + public final static float BORDER_SIZE = 0; + private int mCheckDim = 8; + + public ColorCompareView(Context ctx, AttributeSet attrs) { + super(ctx, attrs); + DisplayMetrics metrics = ctx.getResources().getDisplayMetrics(); + float mDpToPix = metrics.density; + mBorder = BORDER_SIZE * mDpToPix; + mBarPaint1 = new Paint(); + mOrigBarPaint1 = new Paint(); + Resources res = ctx.getResources(); + mCheckDim = res.getDimensionPixelSize(R.dimen.draw_color_check_dim); + mBarPaint1.setStyle(Paint.Style.FILL); + mOrigBarPaint1.setStyle(Paint.Style.FILL); + + makeCheckPaint(); + } + + private void makeCheckPaint() { + int imgdim = mCheckDim * 2; + int[] colors = new int[imgdim * imgdim]; + for (int i = 0; i < colors.length; i++) { + int y = i / (imgdim * mCheckDim); + int x = (i / mCheckDim) % 2; + colors[i] = (x == y) ? 0xFFAAAAAA : 0xFF444444; + } + Bitmap bitmap = Bitmap.createBitmap(colors, imgdim, imgdim, Bitmap.Config.ARGB_8888); + BitmapShader bs = new BitmapShader(bitmap, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT); + mCheckPaint = new Paint(); + mCheckPaint.setShader(bs); + } + + public boolean onDown(MotionEvent e) { + return true; + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + if (event.getAction() != MotionEvent.ACTION_UP) { + return true; + } + float x = event.getX(); + float y = event.getY(); + if (x> mWidth-2*mHeight) { + resetToOriginal(); + } + return true; + } + + public void resetToOriginal(){ + System.arraycopy(mOrigHSVO, 0, mHSVO, 0, mOrigHSVO.length); + updatePaint(); + notifyColorListeners(mHSVO); + invalidate(); + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + mWidth = w; + mHeight = h; + updatePaint(); + } + + private void updatePaint() { + int color = Color.HSVToColor((int) (mHSVO[3] * 255), mHSVO); + mBarPaint1.setColor(color); + int origColor = Color.HSVToColor((int) (mOrigHSVO[3] * 255), mOrigHSVO); + mOrigBarPaint1.setColor(origColor); + mOrigRegion = new Path(); + mOrigRegion.moveTo(mWidth, 0); + mOrigRegion.lineTo(mWidth, mHeight); + mOrigRegion.lineTo(mWidth - mHeight * 2, mHeight); + mOrigRegion.lineTo(mWidth - mHeight, 0); + + mRegion = new Path(); + mRegion.moveTo(0, 0); + mRegion.lineTo(mWidth - mHeight, 0); + mRegion.lineTo(mWidth - mHeight * 2, mHeight); + mRegion.lineTo(0, mHeight); + + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + canvas.drawColor(mBgcolor); + canvas.drawRect(mBorder, 0, mWidth, mHeight, mCheckPaint); + canvas.drawPath(mRegion, mBarPaint1); + canvas.drawPath(mOrigRegion, mOrigBarPaint1); + } + + public void setOrigColor(float[] hsv) { + System.arraycopy(hsv, 0, mOrigHSVO, 0, mOrigHSVO.length); + int color2 = Color.HSVToColor((int) (mOrigHSVO[3] * 255), mOrigHSVO); + mOrigBarPaint1.setColor(color2); + updatePaint(); + } + + @Override + public void setColor(float[] hsv) { + System.arraycopy(hsv, 0, mHSVO, 0, mHSVO.length); + updatePaint(); + invalidate(); + } + + ArrayList<ColorListener> mColorListeners = new ArrayList<ColorListener>(); + + public void notifyColorListeners(float[] hsvo) { + for (ColorListener l : mColorListeners) { + l.setColor(hsvo); + } + } + + public void addColorListener(ColorListener l) { + mColorListeners.add(l); + } + + public void removeColorListener(ColorListener l) { + mColorListeners.remove(l); + } +} + diff --git a/src/com/android/gallery3d/filtershow/colorpicker/ColorGridDialog.java b/src/com/android/gallery3d/filtershow/colorpicker/ColorGridDialog.java index dd4df7dc8..028599478 100644 --- a/src/com/android/gallery3d/filtershow/colorpicker/ColorGridDialog.java +++ b/src/com/android/gallery3d/filtershow/colorpicker/ColorGridDialog.java @@ -92,6 +92,9 @@ public class ColorGridDialog extends Dialog { c |= alpha << 24; mCallback.setColor(c); } + @Override + public void addColorListener(ColorListener l) { + } }; ColorPickerDialog cpd = new ColorPickerDialog(this.getContext(), cl); cpd.show(); diff --git a/src/com/android/gallery3d/filtershow/colorpicker/ColorHueView.java b/src/com/android/gallery3d/filtershow/colorpicker/ColorHueView.java index 713ab112a..498f5a4b6 100644 --- a/src/com/android/gallery3d/filtershow/colorpicker/ColorHueView.java +++ b/src/com/android/gallery3d/filtershow/colorpicker/ColorHueView.java @@ -81,8 +81,8 @@ public class ColorHueView extends View implements ColorListener { mLinePaint2.setColor(mSliderColor); mLinePaint2.setStrokeWidth(4); - mBitmap = Bitmap.createBitmap(256, 7, Bitmap.Config.ARGB_8888); - mTmpBuff = new int[256 * 7]; + mBitmap = Bitmap.createBitmap(256, 2, Bitmap.Config.ARGB_8888); + mTmpBuff = new int[mBitmap.getWidth() * mBitmap.getHeight()]; mPaint.setAntiAlias(true); mPaint.setFilterBitmap(true); fillBitmap(); @@ -96,20 +96,13 @@ public class ColorHueView extends View implements ColorListener { for (int x = 0; x < w; x++) { float hue = 360 * (x) / (float) w; - - int color = Color.HSVToColor((int)(mHSVO[3]*255),mHSVO); - mTmpBuff[x + w * 2] = color; - mTmpBuff[x + w * 3] = color; - mTmpBuff[x + w * 4] = color; - mTmpHSV[0] = hue; mTmpHSV[1] = 1; mTmpHSV[2] = 1; - color = Color.HSVToColor(mTmpHSV); + int color = Color.HSVToColor(mTmpHSV); mTmpBuff[x] = color; mTmpBuff[x + w] = color; - mTmpBuff[x + w * 5] = color; - mTmpBuff[x + w * 6] = color; + } mBitmap.setPixels(mTmpBuff, 0, w, 0, 0, w, h); @@ -192,10 +185,12 @@ public class ColorHueView extends View implements ColorListener { } private void makeCheckPaint(){ - int[] colors = new int[16 * 16]; + int block = 16; + int checkdim = block*2; + int[] colors = new int[checkdim * checkdim]; for (int i = 0; i < colors.length; i++) { - int y = i / (16 * 8); - int x = (i / 8) % 2; + int y = i / (checkdim * block); + int x = (i / block) % 2; colors[i] = (x == y) ? 0xFFAAAAAA : 0xFF444444; } Bitmap bitmap = Bitmap.createBitmap(colors, 16, 16, Bitmap.Config.ARGB_8888); diff --git a/src/com/android/gallery3d/filtershow/colorpicker/ColorListener.java b/src/com/android/gallery3d/filtershow/colorpicker/ColorListener.java index 5127dad26..22dd4245a 100644 --- a/src/com/android/gallery3d/filtershow/colorpicker/ColorListener.java +++ b/src/com/android/gallery3d/filtershow/colorpicker/ColorListener.java @@ -18,4 +18,5 @@ package com.android.gallery3d.filtershow.colorpicker; public interface ColorListener { void setColor(float[] hsvo); + public void addColorListener(ColorListener l); } diff --git a/src/com/android/gallery3d/filtershow/colorpicker/ColorOpacityView.java b/src/com/android/gallery3d/filtershow/colorpicker/ColorOpacityView.java index de4b2f911..ec15b5b09 100644 --- a/src/com/android/gallery3d/filtershow/colorpicker/ColorOpacityView.java +++ b/src/com/android/gallery3d/filtershow/colorpicker/ColorOpacityView.java @@ -17,6 +17,7 @@ package com.android.gallery3d.filtershow.colorpicker; import android.content.Context; +import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapShader; import android.graphics.Canvas; @@ -56,7 +57,7 @@ public class ColorOpacityView extends View implements ColorListener { private float mDotY = mBorder; private final static float DOT_SIZE = ColorHueView.DOT_SIZE; public final static float BORDER_SIZE = 20;; - + private int mCheckDim = 8; public ColorOpacityView(Context ctx, AttributeSet attrs) { super(ctx, attrs); DisplayMetrics metrics = ctx.getResources().getDisplayMetrics(); @@ -68,8 +69,10 @@ public class ColorOpacityView extends View implements ColorListener { mDotPaint = new Paint(); mDotPaint.setStyle(Paint.Style.FILL); - mDotPaint.setColor(ctx.getResources().getColor(R.color.slider_dot_color)); - mSliderColor = ctx.getResources().getColor(R.color.slider_line_color); + Resources res = ctx.getResources(); + mCheckDim = res.getDimensionPixelSize(R.dimen.draw_color_check_dim); + mDotPaint.setColor(res.getColor(R.color.slider_dot_color)); + mSliderColor = res.getColor(R.color.slider_line_color); mBarPaint1.setStyle(Paint.Style.FILL); @@ -83,13 +86,14 @@ public class ColorOpacityView extends View implements ColorListener { } private void makeCheckPaint(){ - int[] colors = new int[16 * 16]; + int imgdim = mCheckDim*2; + int[] colors = new int[imgdim * imgdim]; for (int i = 0; i < colors.length; i++) { - int y = i / (16 * 8); - int x = (i / 8) % 2; + int y = i / (imgdim * mCheckDim); + int x = (i / mCheckDim) % 2; colors[i] = (x == y) ? 0xFFAAAAAA : 0xFF444444; } - Bitmap bitmap = Bitmap.createBitmap(colors, 16, 16, Bitmap.Config.ARGB_8888); + Bitmap bitmap = Bitmap.createBitmap(colors, imgdim, imgdim, Bitmap.Config.ARGB_8888); BitmapShader bs = new BitmapShader(bitmap, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT); mCheckPaint = new Paint(); mCheckPaint.setShader(bs); diff --git a/src/com/android/gallery3d/filtershow/colorpicker/ColorPickerDialog.java b/src/com/android/gallery3d/filtershow/colorpicker/ColorPickerDialog.java index 952709546..ff36f5aa8 100644 --- a/src/com/android/gallery3d/filtershow/colorpicker/ColorPickerDialog.java +++ b/src/com/android/gallery3d/filtershow/colorpicker/ColorPickerDialog.java @@ -18,22 +18,29 @@ package com.android.gallery3d.filtershow.colorpicker; import android.app.Dialog; import android.content.Context; +import android.content.res.Configuration; import android.graphics.Color; import android.graphics.drawable.GradientDrawable; import android.util.DisplayMetrics; import android.view.View; +import android.view.ViewGroup; +import android.view.Window; import android.view.WindowManager; import android.widget.Button; +import android.widget.ImageButton; import android.widget.ToggleButton; import com.android.gallery3d.R; +import com.android.gallery3d.filtershow.FilterShowActivity; +import com.android.photos.views.GalleryThumbnailView; public class ColorPickerDialog extends Dialog { ToggleButton mSelectedButton; - GradientDrawable mSelectRect; ColorHueView mColorHueView; ColorSVRectView mColorSVRectView; ColorOpacityView mColorOpacityView; + ColorCompareView mColorCompareView; + float[] mHSVO = new float[4]; // hue=0..360, sat & val opacity = 0...1 public ColorPickerDialog(Context context, final ColorListener cl) { @@ -44,52 +51,61 @@ public class ColorPickerDialog extends Dialog { int height = metrics.heightPixels*8/10; int width = metrics.widthPixels*8/10; getWindow().setLayout(width, height); + requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.filtershow_color_picker); mColorHueView = (ColorHueView) findViewById(R.id.ColorHueView); mColorSVRectView = (ColorSVRectView) findViewById(R.id.colorRectView); mColorOpacityView = (ColorOpacityView) findViewById(R.id.colorOpacityView); + mColorCompareView = (ColorCompareView) findViewById(R.id.btnSelect); + float[] hsvo = new float[] { 123, .9f, 1, 1 }; - mSelectRect = (GradientDrawable) getContext() - .getResources().getDrawable(R.drawable.filtershow_color_picker_roundrect); - Button selButton = (Button) findViewById(R.id.btnSelect); - selButton.setCompoundDrawablesWithIntrinsicBounds(null, null, mSelectRect, null); - Button sel = (Button) findViewById(R.id.btnSelect); + ImageButton apply = (ImageButton) findViewById(R.id.applyColorPick); + ImageButton cancel = (ImageButton) findViewById(R.id.cancelColorPick); - sel.setOnClickListener(new View.OnClickListener() { + apply.setOnClickListener(new View.OnClickListener() { @Override - public void onClick(View v) { + public void onClick(View view) { + cl.setColor(mHSVO); + ColorPickerDialog.this.dismiss(); + } + }); + cancel.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { ColorPickerDialog.this.dismiss(); - if (cl != null) { - cl.setColor(mHSVO); - } } }); + ColorListener [] c = {mColorCompareView,mColorSVRectView,mColorOpacityView,mColorHueView}; + for (int i = 0; i < c.length; i++) { + c[i].setColor(hsvo); + for (int j = 0; j < c.length; j++) { + if (i==j) { + continue; + } + c[i].addColorListener(c[j]); + } + } - mColorSVRectView.setColor(hsvo); - mColorOpacityView.setColor(hsvo); - mColorHueView.setColor(hsvo); - mColorHueView.addColorListener(mColorSVRectView); - mColorSVRectView.addColorListener(mColorHueView); - mColorHueView.addColorListener(mColorOpacityView); - mColorSVRectView.addColorListener(mColorOpacityView); - mColorOpacityView.addColorListener(mColorSVRectView); - mColorOpacityView.addColorListener(mColorHueView); ColorListener colorListener = new ColorListener(){ - @Override public void setColor(float[] hsvo) { System.arraycopy(hsvo, 0, mHSVO, 0, mHSVO.length); int color = Color.HSVToColor(hsvo); - mSelectRect.setColor(color); setButtonColor(mSelectedButton, hsvo); } + + @Override + public void addColorListener(ColorListener l) { + } }; - mColorOpacityView.addColorListener(colorListener); - mColorHueView.addColorListener(colorListener); - mColorSVRectView.addColorListener(colorListener); + for (int i = 0; i < c.length; i++) { + c[i].addColorListener(colorListener); + } + setOnShowListener((FilterShowActivity) context); + setOnDismissListener((FilterShowActivity) context); } void toggleClick(ToggleButton v, int[] buttons, boolean isChecked) { @@ -116,11 +132,15 @@ public class ColorPickerDialog extends Dialog { csv.setColor(hsv); } + public void setOrigColor(float[] hsvo) { + mColorCompareView.setOrigColor(hsvo); + } public void setColor(float[] hsvo) { mColorOpacityView.setColor(hsvo); mColorHueView.setColor(hsvo); mColorSVRectView.setColor(hsvo); + mColorCompareView.setColor(hsvo); } private void setButtonColor(ToggleButton button, float[] hsv) { diff --git a/src/com/android/gallery3d/filtershow/colorpicker/ColorSVRectView.java b/src/com/android/gallery3d/filtershow/colorpicker/ColorSVRectView.java index b529b433f..fb8b4fcb4 100644 --- a/src/com/android/gallery3d/filtershow/colorpicker/ColorSVRectView.java +++ b/src/com/android/gallery3d/filtershow/colorpicker/ColorSVRectView.java @@ -86,6 +86,11 @@ public class ColorSVRectView extends View implements ColorListener { fillBitmap(); } + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, widthMeasureSpec); + } + void fillBitmap() { int w = mBitmap.getWidth(); int h = mBitmap.getHeight(); diff --git a/src/com/android/gallery3d/filtershow/controller/ColorChooser.java b/src/com/android/gallery3d/filtershow/controller/ColorChooser.java index 7fcffd7d7..f9f29bccc 100644 --- a/src/com/android/gallery3d/filtershow/controller/ColorChooser.java +++ b/src/com/android/gallery3d/filtershow/controller/ColorChooser.java @@ -164,10 +164,14 @@ public class ColorChooser implements Control { public void setColor(float[] hsvo) { changeSelectedColor(hsvo); } + @Override + public void addColorListener(ColorListener l) { + } }; ColorPickerDialog cpd = new ColorPickerDialog(mContext, cl); float[] c = (float[]) mButton[mSelectedButton].getTag(); cpd.setColor(Arrays.copyOf(c, 4)); + cpd.setOrigColor(Arrays.copyOf(c, 4)); cpd.show(); } } diff --git a/src/com/android/gallery3d/filtershow/controller/SliderBrightness.java b/src/com/android/gallery3d/filtershow/controller/SliderBrightness.java index 6dc86882d..2929d6891 100644 --- a/src/com/android/gallery3d/filtershow/controller/SliderBrightness.java +++ b/src/com/android/gallery3d/filtershow/controller/SliderBrightness.java @@ -52,6 +52,9 @@ public class SliderBrightness implements Control { mParameter.setValue((int)(255* hsvo[3])); mEditor.commitLocalRepresentation(); } + @Override + public void addColorListener(ColorListener l) { + } }); } diff --git a/src/com/android/gallery3d/filtershow/controller/SliderHue.java b/src/com/android/gallery3d/filtershow/controller/SliderHue.java index a550afd79..1820ce234 100644 --- a/src/com/android/gallery3d/filtershow/controller/SliderHue.java +++ b/src/com/android/gallery3d/filtershow/controller/SliderHue.java @@ -63,6 +63,9 @@ public class SliderHue implements Control { mParameter.setValue((int)(360* hsvo[3])); mEditor.commitLocalRepresentation(); } + @Override + public void addColorListener(ColorListener l) { + } }); } diff --git a/src/com/android/gallery3d/filtershow/controller/SliderOpacity.java b/src/com/android/gallery3d/filtershow/controller/SliderOpacity.java index cd21e9b76..2a34aad2f 100644 --- a/src/com/android/gallery3d/filtershow/controller/SliderOpacity.java +++ b/src/com/android/gallery3d/filtershow/controller/SliderOpacity.java @@ -53,6 +53,9 @@ public class SliderOpacity implements Control { mParameter.setValue((int) (255 * hsvo[3])); mEditor.commitLocalRepresentation(); } + @Override + public void addColorListener(ColorListener l) { + } }); } diff --git a/src/com/android/gallery3d/filtershow/controller/SliderSaturation.java b/src/com/android/gallery3d/filtershow/controller/SliderSaturation.java index 1f2b3fbd8..6f3ae6e4f 100644 --- a/src/com/android/gallery3d/filtershow/controller/SliderSaturation.java +++ b/src/com/android/gallery3d/filtershow/controller/SliderSaturation.java @@ -54,6 +54,9 @@ public class SliderSaturation implements Control { mParameter.setValue((int) (255 * hsvo[3])); mEditor.commitLocalRepresentation(); } + @Override + public void addColorListener(ColorListener l) { + } }); } diff --git a/src/com/android/gallery3d/filtershow/crop/CropDrawingUtils.java b/src/com/android/gallery3d/filtershow/crop/CropDrawingUtils.java index b0d324cbb..df0f14fe0 100644 --- a/src/com/android/gallery3d/filtershow/crop/CropDrawingUtils.java +++ b/src/com/android/gallery3d/filtershow/crop/CropDrawingUtils.java @@ -54,6 +54,24 @@ public abstract class CropDrawingUtils { canvas.drawRect(bounds, p); } + public static void drawShade(Canvas canvas, RectF bounds) { + int w = canvas.getWidth(); + int h = canvas.getHeight(); + Paint p = new Paint(); + p.setStyle(Paint.Style.FILL); + p.setColor(Color.BLACK & 0x88000000); + + RectF r = new RectF(); + r.set(0,0,w,bounds.top); + canvas.drawRect(r, p); + r.set(0,bounds.top,bounds.left,h); + canvas.drawRect(r, p); + r.set(bounds.left,bounds.bottom,w,h); + canvas.drawRect(r, p); + r.set(bounds.right,bounds.top,w,bounds.bottom); + canvas.drawRect(r, p); + } + public static void drawIndicator(Canvas canvas, Drawable indicator, int indicatorSize, float centerX, float centerY) { int left = (int) centerX - indicatorSize / 2; diff --git a/src/com/android/gallery3d/filtershow/data/UserPresetsManager.java b/src/com/android/gallery3d/filtershow/data/UserPresetsManager.java index f36509dad..6232a2d15 100644 --- a/src/com/android/gallery3d/filtershow/data/UserPresetsManager.java +++ b/src/com/android/gallery3d/filtershow/data/UserPresetsManager.java @@ -89,7 +89,7 @@ public class UserPresetsManager implements Handler.Callback { public void save(ImagePreset preset, String name) { Message msg = mProcessingHandler.obtainMessage(SAVE); SaveOperation op = new SaveOperation(); - op.json = preset.getJsonString(mActivity.getString(R.string.saved)); + op.json = preset.getJsonString(ImagePreset.JASON_SAVED); op.name = name; msg.obj = op; mProcessingHandler.sendMessage(msg); diff --git a/src/com/android/gallery3d/filtershow/editors/Editor.java b/src/com/android/gallery3d/filtershow/editors/Editor.java index 5f8e8f6f6..e3eec390b 100644 --- a/src/com/android/gallery3d/filtershow/editors/Editor.java +++ b/src/com/android/gallery3d/filtershow/editors/Editor.java @@ -285,7 +285,7 @@ public class Editor implements OnSeekBarChangeListener, SwapButton.SwapButtonLis protected void setMenuIcon(boolean on) { mEditTitle.setCompoundDrawablesRelativeWithIntrinsicBounds( - 0, 0, on ? R.drawable.filtershow_menu_marker : 0, 0); + 0, 0, on ? R.drawable.filtershow_menu_marker_rtl : 0, 0); } protected void createMenu(int[] strId, View button) { diff --git a/src/com/android/gallery3d/filtershow/editors/EditorChanSat.java b/src/com/android/gallery3d/filtershow/editors/EditorChanSat.java index e806a5aae..abf0a690f 100644 --- a/src/com/android/gallery3d/filtershow/editors/EditorChanSat.java +++ b/src/com/android/gallery3d/filtershow/editors/EditorChanSat.java @@ -30,6 +30,7 @@ import android.widget.SeekBar.OnSeekBarChangeListener; import android.widget.TextView; import com.android.gallery3d.R; +import com.android.gallery3d.filtershow.FilterShowActivity; import com.android.gallery3d.filtershow.controller.BasicParameterStyle; import com.android.gallery3d.filtershow.controller.BitmapCaller; import com.android.gallery3d.filtershow.controller.FilterView; @@ -115,6 +116,7 @@ public class EditorChanSat extends ParametricEditor implements OnSeekBarChangeLi @Override public void onClick(View arg0) { popupMenu.show(); + ((FilterShowActivity)mContext).onShowMenu(popupMenu); } }); mButton.setListener(this); diff --git a/src/com/android/gallery3d/filtershow/editors/EditorColorBorder.java b/src/com/android/gallery3d/filtershow/editors/EditorColorBorder.java index 8cdad7eda..98659df38 100644 --- a/src/com/android/gallery3d/filtershow/editors/EditorColorBorder.java +++ b/src/com/android/gallery3d/filtershow/editors/EditorColorBorder.java @@ -33,6 +33,7 @@ import android.widget.PopupMenu; import android.widget.SeekBar; import com.android.gallery3d.R; +import com.android.gallery3d.filtershow.FilterShowActivity; import com.android.gallery3d.filtershow.controller.BitmapCaller; import com.android.gallery3d.filtershow.controller.ColorChooser; import com.android.gallery3d.filtershow.controller.FilterView; @@ -45,7 +46,6 @@ public class EditorColorBorder extends ParametricEditor { private static final String LOGTAG = "EditorColorBorder"; public static final int ID = R.id.editorColorBorder; - int[] mBasColors = { FilterColorBorderRepresentation.DEFAULT_MENU_COLOR1, FilterColorBorderRepresentation.DEFAULT_MENU_COLOR2, @@ -138,6 +138,7 @@ public class EditorColorBorder extends ParametricEditor { } }); popupMenu.show(); + ((FilterShowActivity)mContext).onShowMenu(popupMenu); } protected void selectMenuItem(MenuItem item) { @@ -167,7 +168,9 @@ public class EditorColorBorder extends ParametricEditor { ColorChooser c = (ColorChooser) mControl; mBasColors = c.getColorSet(); } - control(rep.getCurrentParam(), mEditControl); + if (mEditControl != null) { + control(rep.getCurrentParam(), mEditControl); + } if (mControl instanceof ColorChooser) { ColorChooser c = (ColorChooser) mControl; c.setColorSet(mBasColors); diff --git a/src/com/android/gallery3d/filtershow/editors/EditorColorBorderTabletUI.java b/src/com/android/gallery3d/filtershow/editors/EditorColorBorderTabletUI.java index 518c56af0..9f1a11b58 100644 --- a/src/com/android/gallery3d/filtershow/editors/EditorColorBorderTabletUI.java +++ b/src/com/android/gallery3d/filtershow/editors/EditorColorBorderTabletUI.java @@ -29,6 +29,7 @@ import android.widget.SeekBar; import android.widget.TextView; import com.android.gallery3d.R; +import com.android.gallery3d.filtershow.colorpicker.ColorCompareView; import com.android.gallery3d.filtershow.colorpicker.ColorHueView; import com.android.gallery3d.filtershow.colorpicker.ColorListener; import com.android.gallery3d.filtershow.colorpicker.ColorOpacityView; @@ -48,6 +49,7 @@ public class EditorColorBorderTabletUI { private ColorHueView mHueView; private ColorSVRectView mSatValView; private ColorOpacityView mOpacityView; + private ColorCompareView mColorCompareView; private int[] mBasColors; private int mSelected; @@ -98,23 +100,13 @@ public class EditorColorBorderTabletUI { mCBCornerSizeSeekBar = (SeekBar) lp.findViewById(R.id.colorBorderCornerSizeSeekBar); mCBCornerSizeValue = (TextView) lp.findViewById(R.id.colorBorderCornerValue); mCBSizeSeekBar = (SeekBar) lp.findViewById(R.id.colorBorderSizeSeekBar); + mCBSizeValue = (TextView) lp.findViewById(R.id.colorBorderSizeValue); - setupClearButton(lp); setupCBSizeSeekBar(lp); setupCBCornerSizeSeekBar(lp); setupColor(lp, res); } - private void setupClearButton(LinearLayout lp) { - Button clearButton = (Button) lp.findViewById(R.id.clearButton); - clearButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - mEditorDraw.clearFrame(); - } - }); - } - private void setupCBSizeSeekBar(LinearLayout lp) { mCBSizeSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override @@ -200,18 +192,32 @@ public class EditorColorBorderTabletUI { mHueView.setColor(hsvo); mSatValView.setColor(hsvo); mOpacityView.setColor(hsvo); + mColorCompareView.setOrigColor(hsvo); + } }); } mHueView = (ColorHueView) lp.findViewById(R.id.ColorHueView); mSatValView = (ColorSVRectView) lp.findViewById(R.id.colorRectView); mOpacityView = (ColorOpacityView) lp.findViewById(R.id.colorOpacityView); - mHueView.addColorListener(mSatValView); - mSatValView.addColorListener(mHueView); - mHueView.addColorListener(mOpacityView); - mSatValView.addColorListener(mOpacityView); - mOpacityView.addColorListener(mSatValView); - mOpacityView.addColorListener(mHueView); + mColorCompareView = (ColorCompareView) lp.findViewById(R.id.btnSelect); + + float[] hsvo = new float[4]; + Color.colorToHSV(mBasColors[0], hsvo); + hsvo[3] = (0xFF & (mBasColors[0] >> 24)) / (float) 255; + mColorCompareView.setOrigColor(hsvo); + + ColorListener[] colorViews = {mHueView, mSatValView, mOpacityView, mColorCompareView}; + for (int i = 0; i < colorViews.length; i++) { + colorViews[i].setColor(hsvo); + for (int j = 0; j < colorViews.length; j++) { + if (i == j) { + continue; + } + colorViews[i].addColorListener(colorViews[j]); + } + } + ColorListener colorListener = new ColorListener() { @Override public void setColor(float[] hsvo) { @@ -228,10 +234,14 @@ public class EditorColorBorderTabletUI { pram.setValue(color); mEditorDraw.commitLocalRepresentation(); } + @Override + public void addColorListener(ColorListener l) { + } }; - mHueView.addColorListener(colorListener); - mSatValView.addColorListener(colorListener); - mOpacityView.addColorListener(colorListener); + + for (int i = 0; i < colorViews.length; i++) { + colorViews[i].addColorListener(colorListener); + } } private void resetBorders() { diff --git a/src/com/android/gallery3d/filtershow/editors/EditorCrop.java b/src/com/android/gallery3d/filtershow/editors/EditorCrop.java index 511d4ff87..6b19d3c2f 100644 --- a/src/com/android/gallery3d/filtershow/editors/EditorCrop.java +++ b/src/com/android/gallery3d/filtershow/editors/EditorCrop.java @@ -28,6 +28,7 @@ import android.widget.LinearLayout; import android.widget.PopupMenu; import com.android.gallery3d.R; +import com.android.gallery3d.filtershow.FilterShowActivity; import com.android.gallery3d.filtershow.filters.FilterCropRepresentation; import com.android.gallery3d.filtershow.filters.FilterRepresentation; import com.android.gallery3d.filtershow.imageshow.ImageCrop; @@ -140,6 +141,13 @@ public class EditorCrop extends Editor implements EditorInfo { } }); popupMenu.show(); + ((FilterShowActivity)mContext).onShowMenu(popupMenu); + } + + @Override + public void setUtilityPanelUI(View actionButton, View editControl) { + super.setUtilityPanelUI(actionButton,editControl); + setMenuIcon(true); } @Override diff --git a/src/com/android/gallery3d/filtershow/editors/EditorDraw.java b/src/com/android/gallery3d/filtershow/editors/EditorDraw.java index abd81c523..58bde1260 100644 --- a/src/com/android/gallery3d/filtershow/editors/EditorDraw.java +++ b/src/com/android/gallery3d/filtershow/editors/EditorDraw.java @@ -24,6 +24,7 @@ import android.graphics.BitmapFactory; import android.graphics.Color; import android.graphics.drawable.GradientDrawable; import android.view.LayoutInflater; +import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; @@ -37,6 +38,7 @@ import android.widget.PopupMenu; import android.widget.SeekBar; import com.android.gallery3d.R; +import com.android.gallery3d.filtershow.FilterShowActivity; import com.android.gallery3d.filtershow.colorpicker.ColorHueView; import com.android.gallery3d.filtershow.colorpicker.ColorListener; import com.android.gallery3d.filtershow.colorpicker.ColorOpacityView; @@ -76,6 +78,7 @@ public class EditorDraw extends ParametricEditor implements FilterView { private EditorDrawTabletUI mTabletUI; private String mParameterString; private int mSelectedColorButton; + private String mDrawString = null; public EditorDraw() { super(ID); @@ -84,9 +87,16 @@ public class EditorDraw extends ParametricEditor implements FilterView { @Override public String calculateUserMessage(Context context, String effectName, Object parameterValue) { FilterDrawRepresentation rep = getDrawRep(); + if (mDrawString != null) { + mImageDraw.displayDrawLook(); + return mDrawString; + } if (rep == null) { return ""; } + if (!ParametricEditor.useCompact(mContext)) { + + } if (mParameterString == null) { mParameterString = ""; } @@ -122,7 +132,7 @@ public class EditorDraw extends ParametricEditor implements FilterView { drawRep.getParam(FilterDrawRepresentation.PARAM_STYLE).setFilterView(this); drawRep.setPramMode(FilterDrawRepresentation.PARAM_COLOR); - mParameterString = mContext.getString(R.string.draw_hue); + mParameterString = mContext.getString(R.string.draw_color); control(drawRep.getCurrentParam(), mEditControl); } } @@ -130,18 +140,16 @@ public class EditorDraw extends ParametricEditor implements FilterView { @Override public void openUtilityPanel(final LinearLayout accessoryViewList) { Button view = (Button) accessoryViewList.findViewById(R.id.applyEffect); - if (useCompact(mContext)) { - view.setText(mContext.getString(R.string.draw_hue)); - view.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View arg0) { - showPopupMenu(accessoryViewList); - } - }); - } else { - view.setText(mContext.getString(R.string.imageDraw)); - } + view.setText(mContext.getString(R.string.draw_color)); + view.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View arg0) { + showPopupMenu(accessoryViewList); + } + }); + } @Override @@ -157,16 +165,35 @@ public class EditorDraw extends ParametricEditor implements FilterView { } final PopupMenu popupMenu = new PopupMenu(mImageShow.getActivity(), button); popupMenu.getMenuInflater().inflate(R.menu.filtershow_menu_draw, popupMenu.getMenu()); - popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { - - @Override - public boolean onMenuItemClick(MenuItem item) { - selectMenuItem(item); - return true; + if (!ParametricEditor.useCompact(mContext)) { + Menu menu = popupMenu.getMenu(); + int count = menu.size(); + for (int i = 0; i < count; i++) { + MenuItem item = menu.getItem(i); + if (item.getItemId() != R.id.draw_menu_clear) { + item.setVisible(false); + } } - }); - popupMenu.show(); + popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { + + @Override + public boolean onMenuItemClick(MenuItem item) { + clearDrawing(); + return true; + } + }); + } else { + popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { + @Override + public boolean onMenuItemClick(MenuItem item) { + selectMenuItem(item); + return true; + } + }); + } + popupMenu.show(); + ((FilterShowActivity)mContext).onShowMenu(popupMenu); } protected void selectMenuItem(MenuItem item) { @@ -192,6 +219,7 @@ public class EditorDraw extends ParametricEditor implements FilterView { } if (item.getItemId() != R.id.draw_menu_clear) { mParameterString = item.getTitle().toString(); + updateText(); } if (mControl instanceof ColorChooser) { ColorChooser c = (ColorChooser) mControl; @@ -218,6 +246,7 @@ public class EditorDraw extends ParametricEditor implements FilterView { super.setUtilityPanelUI(actionButton, editControl); return; } + mSeekBar = (SeekBar) editControl.findViewById(R.id.primarySeekBar); if (mSeekBar != null) { mSeekBar.setVisibility(View.GONE); @@ -228,7 +257,8 @@ public class EditorDraw extends ParametricEditor implements FilterView { R.layout.filtershow_draw_ui, (ViewGroup) editControl, true); mTabletUI = new EditorDrawTabletUI(this, mContext, lp); - setMenuIcon(false); + mDrawString = mContext.getResources().getString(R.string.imageDraw).toUpperCase(); + setMenuIcon(true); } diff --git a/src/com/android/gallery3d/filtershow/editors/EditorDrawTabletUI.java b/src/com/android/gallery3d/filtershow/editors/EditorDrawTabletUI.java index 01fd9ed34..83d89c9a5 100644 --- a/src/com/android/gallery3d/filtershow/editors/EditorDrawTabletUI.java +++ b/src/com/android/gallery3d/filtershow/editors/EditorDrawTabletUI.java @@ -32,6 +32,7 @@ import android.widget.SeekBar; import android.widget.TextView; import com.android.gallery3d.R; +import com.android.gallery3d.filtershow.colorpicker.ColorCompareView; import com.android.gallery3d.filtershow.colorpicker.ColorHueView; import com.android.gallery3d.filtershow.colorpicker.ColorListener; import com.android.gallery3d.filtershow.colorpicker.ColorOpacityView; @@ -55,6 +56,8 @@ public class EditorDrawTabletUI { private ColorHueView mHueView; private ColorSVRectView mSatValView; private ColorOpacityView mOpacityView; + private ColorCompareView mColorCompareView; + private TextView mDrawSizeValue; private int[] mBasColors; private int mSelected; @@ -72,8 +75,9 @@ public class EditorDrawTabletUI { mRep = rep; BasicParameterInt size; size = (BasicParameterInt) mRep.getParam(FilterDrawRepresentation.PARAM_SIZE); - mdrawSizeSeekBar.setProgress(size.getDefaultValue()); mdrawSizeSeekBar.setMax(size.getMaximum() - size.getMinimum()); + mdrawSizeSeekBar.setProgress(size.getValue()); + ParameterColor color; color = (ParameterColor) mRep.getParam(FilterDrawRepresentation.PARAM_COLOR); color.setValue(mBasColors[mSelectedColorButton]); @@ -91,7 +95,7 @@ public class EditorDrawTabletUI { LinearLayout buttonContainer = (LinearLayout) lp.findViewById(R.id.listStyles); mdrawSizeSeekBar = (SeekBar) lp.findViewById(R.id.drawSizeSeekBar); - TextView drawSizeValue = (TextView) lp.findViewById(R.id.drawSizeValue); + mDrawSizeValue = (TextView) lp.findViewById(R.id.drawSizeValue); Button clearButton = (Button) lp.findViewById(R.id.clearButton); clearButton.setOnClickListener(new View.OnClickListener() { @@ -117,6 +121,8 @@ public class EditorDrawTabletUI { size = (BasicParameterInt) mRep.getParam(FilterDrawRepresentation.PARAM_SIZE); size.setValue(progress + size.getMinimum()); mEditorDraw.commitLocalRepresentation(); + int val = progress + size.getMinimum(); + mDrawSizeValue.setText(((val>0)?"+":"")+val); } }); @@ -183,7 +189,7 @@ public class EditorDrawTabletUI { public void onClick(View arg0) { mSelectedColorButton = buttonNo; - float[] hsvo = Arrays.copyOf((float[]) mColorButton[buttonNo].getTag(),4); + float[] hsvo = Arrays.copyOf((float[]) mColorButton[buttonNo].getTag(), 4); resetBorders(); if (mRep == null) { return; @@ -195,18 +201,33 @@ public class EditorDrawTabletUI { mHueView.setColor(hsvo); mSatValView.setColor(hsvo); mOpacityView.setColor(hsvo); + mColorCompareView.setColor(hsvo); + mColorCompareView.setOrigColor(hsvo); } }); } + mHueView = (ColorHueView) lp.findViewById(R.id.ColorHueView); mSatValView = (ColorSVRectView) lp.findViewById(R.id.colorRectView); mOpacityView = (ColorOpacityView) lp.findViewById(R.id.colorOpacityView); - mHueView.addColorListener(mSatValView); - mSatValView.addColorListener(mHueView); - mHueView.addColorListener(mOpacityView); - mSatValView.addColorListener(mOpacityView); - mOpacityView.addColorListener(mSatValView); - mOpacityView.addColorListener(mHueView); + mColorCompareView = (ColorCompareView) lp.findViewById(R.id.btnSelect); + + float[] hsvo = new float[4]; + Color.colorToHSV(mBasColors[0], hsvo); + hsvo[3] = (0xFF & (mBasColors[0] >> 24)) / (float) 255; + + mColorCompareView.setOrigColor(hsvo); + ColorListener[] colorViews = {mHueView, mSatValView, mOpacityView, mColorCompareView}; + for (int i = 0; i < colorViews.length; i++) { + colorViews[i].setColor(hsvo); + + for (int j = 0; j < colorViews.length; j++) { + if (i == j) { + continue; + } + colorViews[i].addColorListener(colorViews[j]); + } + } ColorListener colorListener = new ColorListener() { @Override @@ -214,7 +235,7 @@ public class EditorDrawTabletUI { int color = Color.HSVToColor((int) (hsvo[3] * 255), hsvo); Button b = mColorButton[mSelectedColorButton]; float[] f = (float[]) b.getTag(); - System.arraycopy(hsvo,0,f,0,4); + System.arraycopy(hsvo, 0, f, 0, 4); mBasColors[mSelectedColorButton] = color; GradientDrawable sd = ((GradientDrawable) b.getBackground()); sd.setColor(color); @@ -224,10 +245,16 @@ public class EditorDrawTabletUI { pram.setValue(color); mEditorDraw.commitLocalRepresentation(); } + + @Override + public void addColorListener(ColorListener l) { + } }; - mHueView.addColorListener(colorListener); - mSatValView.addColorListener(colorListener); - mOpacityView.addColorListener(colorListener); + + for (int i = 0; i < colorViews.length; i++) { + colorViews[i].addColorListener(colorListener); + } + } public void resetStyle() { diff --git a/src/com/android/gallery3d/filtershow/editors/EditorGrad.java b/src/com/android/gallery3d/filtershow/editors/EditorGrad.java index 4be435f8c..059121634 100644 --- a/src/com/android/gallery3d/filtershow/editors/EditorGrad.java +++ b/src/com/android/gallery3d/filtershow/editors/EditorGrad.java @@ -31,6 +31,7 @@ import android.widget.TextView; import android.widget.ToggleButton; import com.android.gallery3d.R; +import com.android.gallery3d.filtershow.FilterShowActivity; import com.android.gallery3d.filtershow.controller.Control; import com.android.gallery3d.filtershow.controller.FilterView; import com.android.gallery3d.filtershow.controller.Parameter; @@ -191,13 +192,13 @@ public class EditorGrad extends ParametricEditor public ParamAdapter(int seekId, int textId, LinearLayout layout, int mode) { mSlider = (SeekBar) layout.findViewById(seekId); mTextView = (TextView) layout.findViewById(textId); - mSlider.setOnSeekBarChangeListener(this); mSlider.setMax(mMax - mMin); mMode = mode; FilterGradRepresentation rep = getGradRepresentation(); if (rep != null){ updateValues(rep); } + mSlider.setOnSeekBarChangeListener(this); } public void updateValues(FilterGradRepresentation rep) { @@ -254,6 +255,7 @@ public class EditorGrad extends ParametricEditor setUpPopupMenu(button); } mPopupMenu.show(); + ((FilterShowActivity)mContext).onShowMenu(mPopupMenu); } private void setUpPopupMenu(Button button) { @@ -428,5 +430,4 @@ public class EditorGrad extends ParametricEditor public void copyFrom(Parameter src) { } - } diff --git a/src/com/android/gallery3d/filtershow/editors/EditorVignette.java b/src/com/android/gallery3d/filtershow/editors/EditorVignette.java index 3a94dce6c..630a1a9da 100644 --- a/src/com/android/gallery3d/filtershow/editors/EditorVignette.java +++ b/src/com/android/gallery3d/filtershow/editors/EditorVignette.java @@ -29,6 +29,7 @@ import android.widget.SeekBar; import android.widget.TextView; import com.android.gallery3d.R; +import com.android.gallery3d.filtershow.FilterShowActivity; import com.android.gallery3d.filtershow.controller.BasicParameterInt; import com.android.gallery3d.filtershow.controller.Parameter; import com.android.gallery3d.filtershow.filters.FilterVignetteRepresentation; @@ -173,6 +174,7 @@ public class EditorVignette extends ParametricEditor { @Override public void onClick(View arg0) { popupMenu.show(); + ((FilterShowActivity)mContext).onShowMenu(popupMenu); } }); mButton.setListener(this); diff --git a/src/com/android/gallery3d/filtershow/filters/BaseFiltersManager.java b/src/com/android/gallery3d/filtershow/filters/BaseFiltersManager.java index 7a5ec56f1..64b497461 100644 --- a/src/com/android/gallery3d/filtershow/filters/BaseFiltersManager.java +++ b/src/com/android/gallery3d/filtershow/filters/BaseFiltersManager.java @@ -17,6 +17,7 @@ package com.android.gallery3d.filtershow.filters; import android.content.Context; import android.content.res.Resources; +import android.graphics.Color; import android.util.Log; import com.android.gallery3d.R; @@ -35,6 +36,7 @@ public abstract class BaseFiltersManager implements FiltersManagerInterface { protected ArrayList<FilterRepresentation> mBorders = new ArrayList<FilterRepresentation>(); protected ArrayList<FilterRepresentation> mTools = new ArrayList<FilterRepresentation>(); protected ArrayList<FilterRepresentation> mEffects = new ArrayList<FilterRepresentation>(); + private static int mImageBorderSize = 4; // in percent protected void init() { mFilters = new HashMap<Class, ImageFilter>(); @@ -158,6 +160,73 @@ public abstract class BaseFiltersManager implements FiltersManagerInterface { public void addBorders(Context context) { + // Do not localize + String[] serializationNames = { + "FRAME_4X5", + "FRAME_BRUSH", + "FRAME_GRUNGE", + "FRAME_SUMI_E", + "FRAME_TAPE", + "FRAME_BLACK", + "FRAME_BLACK_ROUNDED", + "FRAME_WHITE", + "FRAME_WHITE_ROUNDED", + "FRAME_CREAM", + "FRAME_CREAM_ROUNDED" + }; + + // The "no border" implementation + int i = 0; + FilterRepresentation rep = new FilterImageBorderRepresentation(0); + mBorders.add(rep); + + // Regular borders + ArrayList <FilterRepresentation> borderList = new ArrayList<FilterRepresentation>(); + + + rep = new FilterImageBorderRepresentation(R.drawable.filtershow_border_4x5); + borderList.add(rep); + + rep = new FilterImageBorderRepresentation(R.drawable.filtershow_border_brush); + borderList.add(rep); + + rep = new FilterImageBorderRepresentation(R.drawable.filtershow_border_grunge); + borderList.add(rep); + + rep = new FilterImageBorderRepresentation(R.drawable.filtershow_border_sumi_e); + borderList.add(rep); + + rep = new FilterImageBorderRepresentation(R.drawable.filtershow_border_tape); + borderList.add(rep); + + rep = new FilterColorBorderRepresentation(Color.BLACK, mImageBorderSize, 0); + borderList.add(rep); + + rep = new FilterColorBorderRepresentation(Color.BLACK, mImageBorderSize, + mImageBorderSize); + borderList.add(rep); + + rep = new FilterColorBorderRepresentation(Color.WHITE, mImageBorderSize, 0); + borderList.add(rep); + + rep = new FilterColorBorderRepresentation(Color.WHITE, mImageBorderSize, + mImageBorderSize); + borderList.add(rep); + + int creamColor = Color.argb(255, 237, 237, 227); + rep = new FilterColorBorderRepresentation(creamColor, mImageBorderSize, 0); + borderList.add(rep); + + rep = new FilterColorBorderRepresentation(creamColor, mImageBorderSize, + mImageBorderSize); + borderList.add(rep); + + for (FilterRepresentation filter : borderList) { + filter.setSerializationName(serializationNames[i++]); + addRepresentation(filter); + mBorders.add(filter); + } + } public void addLooks(Context context) { @@ -274,6 +343,17 @@ public abstract class BaseFiltersManager implements FiltersManagerInterface { mTools.add(getRepresentation(ImageFilterDraw.class)); } + public void removeRepresentation(ArrayList<FilterRepresentation> list, + FilterRepresentation representation) { + for (int i = 0; i < list.size(); i++) { + FilterRepresentation r = list.get(i); + if (r.getFilterClass() == representation.getFilterClass()) { + list.remove(i); + break; + } + } + } + public void setFilterResources(Resources resources) { ImageFilterBorder filterBorder = (ImageFilterBorder) getFilter(ImageFilterBorder.class); filterBorder.setResources(resources); diff --git a/src/com/android/gallery3d/filtershow/filters/FilterColorBorderRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterColorBorderRepresentation.java index 4f625d7b4..516292749 100644 --- a/src/com/android/gallery3d/filtershow/filters/FilterColorBorderRepresentation.java +++ b/src/com/android/gallery3d/filtershow/filters/FilterColorBorderRepresentation.java @@ -126,7 +126,10 @@ public class FilterColorBorderRepresentation extends FilterRepresentation { @Override public int getTextId() { - return R.string.borders; + if (super.getTextId() == 0) { + return R.string.borders; + } + return super.getTextId(); } public int getColor() { diff --git a/src/com/android/gallery3d/filtershow/filters/FilterCropRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterCropRepresentation.java index ec4b57385..ba697d87f 100644 --- a/src/com/android/gallery3d/filtershow/filters/FilterCropRepresentation.java +++ b/src/com/android/gallery3d/filtershow/filters/FilterCropRepresentation.java @@ -35,7 +35,7 @@ public class FilterCropRepresentation extends FilterRepresentation { RectF mCrop = getNil(); public FilterCropRepresentation(RectF crop) { - super(FilterCropRepresentation.class.getSimpleName()); + super(SERIALIZATION_NAME); setSerializationName(SERIALIZATION_NAME); setShowParameterValue(true); setFilterClass(FilterCropRepresentation.class); @@ -48,6 +48,7 @@ public class FilterCropRepresentation extends FilterRepresentation { public FilterCropRepresentation(FilterCropRepresentation m) { this(m.mCrop); + setName(m.getName()); } public FilterCropRepresentation() { diff --git a/src/com/android/gallery3d/filtershow/filters/FilterDrawRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterDrawRepresentation.java index f3245739f..48d3d9077 100644 --- a/src/com/android/gallery3d/filtershow/filters/FilterDrawRepresentation.java +++ b/src/com/android/gallery3d/filtershow/filters/FilterDrawRepresentation.java @@ -45,7 +45,7 @@ public class FilterDrawRepresentation extends FilterRepresentation { public static final int PARAM_SIZE = 0; public static final int PARAM_STYLE = 1; public static final int PARAM_COLOR = 2; - private BasicParameterInt mParamSize = new BasicParameterInt(PARAM_SIZE, 20, 2, 300); + private BasicParameterInt mParamSize = new BasicParameterInt(PARAM_SIZE, 30, 2, 300); private BasicParameterStyle mParamStyle = new BasicParameterStyle(PARAM_STYLE, 5); public static int DEFAULT_MENU_COLOR1 = Color.RED & 0x80FFFFFF; public static int DEFAULT_MENU_COLOR2 = Color.GREEN & 0x80FFFFFF; @@ -144,7 +144,7 @@ public class FilterDrawRepresentation extends FilterRepresentation { switch (mParamMode) { case PARAM_COLOR: val = ((ParameterColor) mAllParam[mParamMode]).getValue(); - return ((val > 0) ? " +" : " ") + colorHexString(val); + return ""; case PARAM_SIZE: val = ((BasicParameterInt) mAllParam[mParamMode]).getValue(); return ((val > 0) ? " +" : " ") + val; diff --git a/src/com/android/gallery3d/filtershow/filters/FilterGradRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterGradRepresentation.java index 354fa5925..a3a7e9555 100644 --- a/src/com/android/gallery3d/filtershow/filters/FilterGradRepresentation.java +++ b/src/com/android/gallery3d/filtershow/filters/FilterGradRepresentation.java @@ -114,7 +114,7 @@ public class FilterGradRepresentation extends FilterRepresentation p.yPos1 = 100; p.xPos2 = -1; p.yPos2 = 100; - p.brightness = 40; + p.brightness = -50; p.contrast = 0; p.saturation = 0; mBands.add(0, p); diff --git a/src/com/android/gallery3d/filtershow/filters/FilterMirrorRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterMirrorRepresentation.java index 84caa9e75..c2814432d 100644 --- a/src/com/android/gallery3d/filtershow/filters/FilterMirrorRepresentation.java +++ b/src/com/android/gallery3d/filtershow/filters/FilterMirrorRepresentation.java @@ -66,7 +66,7 @@ public class FilterMirrorRepresentation extends FilterRepresentation { } public FilterMirrorRepresentation(Mirror mirror) { - super(FilterMirrorRepresentation.class.getSimpleName()); + super(SERIALIZATION_NAME); setSerializationName(SERIALIZATION_NAME); setShowParameterValue(false); setFilterClass(FilterMirrorRepresentation.class); @@ -79,6 +79,7 @@ public class FilterMirrorRepresentation extends FilterRepresentation { public FilterMirrorRepresentation(FilterMirrorRepresentation m) { this(m.getMirror()); + setName(m.getName()); } public FilterMirrorRepresentation() { diff --git a/src/com/android/gallery3d/filtershow/filters/FilterRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterRepresentation.java index cc7ec881e..0fb157d7b 100644 --- a/src/com/android/gallery3d/filtershow/filters/FilterRepresentation.java +++ b/src/com/android/gallery3d/filtershow/filters/FilterRepresentation.java @@ -38,6 +38,7 @@ public class FilterRepresentation { private int mOverlayId = 0; private boolean mOverlayOnly = false; private boolean mShowParameterValue = true; + private boolean mIsBooleanFilter = false; private String mSerializationName; public static final byte TYPE_BORDER = 1; public static final byte TYPE_FX = 2; @@ -69,7 +70,7 @@ public class FilterRepresentation { representation.setOverlayOnly(getOverlayOnly()); representation.setShowParameterValue(showParameterValue()); representation.mSerializationName = mSerializationName; - + representation.setIsBooleanFilter(isBooleanFilter()); } public boolean equals(FilterRepresentation representation) { @@ -87,12 +88,21 @@ public class FilterRepresentation { && representation.mButtonId == mButtonId && representation.mOverlayId == mOverlayId && representation.mOverlayOnly == mOverlayOnly - && representation.mShowParameterValue == mShowParameterValue) { + && representation.mShowParameterValue == mShowParameterValue + && representation.mIsBooleanFilter == mIsBooleanFilter) { return true; } return false; } + public boolean isBooleanFilter() { + return mIsBooleanFilter; + } + + public void setIsBooleanFilter(boolean value) { + mIsBooleanFilter = value; + } + @Override public String toString() { return mName; @@ -261,7 +271,8 @@ public class FilterRepresentation { } public boolean canMergeWith(FilterRepresentation representation) { - if (representation.getFilterType() == FilterRepresentation.TYPE_GEOMETRY) { + if (getFilterType() == FilterRepresentation.TYPE_GEOMETRY + && representation.getFilterType() == FilterRepresentation.TYPE_GEOMETRY) { return true; } return false; diff --git a/src/com/android/gallery3d/filtershow/filters/FilterRotateRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterRotateRepresentation.java index d7e0b581b..4299dd396 100644 --- a/src/com/android/gallery3d/filtershow/filters/FilterRotateRepresentation.java +++ b/src/com/android/gallery3d/filtershow/filters/FilterRotateRepresentation.java @@ -62,7 +62,7 @@ public class FilterRotateRepresentation extends FilterRepresentation { } public FilterRotateRepresentation(Rotation rotation) { - super(FilterRotateRepresentation.class.getSimpleName()); + super(SERIALIZATION_NAME); setSerializationName(SERIALIZATION_NAME); setShowParameterValue(false); setFilterClass(FilterRotateRepresentation.class); @@ -75,6 +75,7 @@ public class FilterRotateRepresentation extends FilterRepresentation { public FilterRotateRepresentation(FilterRotateRepresentation r) { this(r.getRotation()); + setName(r.getName()); } public FilterRotateRepresentation() { diff --git a/src/com/android/gallery3d/filtershow/filters/FilterStraightenRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterStraightenRepresentation.java index 4769b36ba..1ba80e8b4 100644 --- a/src/com/android/gallery3d/filtershow/filters/FilterStraightenRepresentation.java +++ b/src/com/android/gallery3d/filtershow/filters/FilterStraightenRepresentation.java @@ -35,7 +35,7 @@ public class FilterStraightenRepresentation extends FilterRepresentation { float mStraighten; public FilterStraightenRepresentation(float straighten) { - super(FilterStraightenRepresentation.class.getSimpleName()); + super(SERIALIZATION_NAME); setSerializationName(SERIALIZATION_NAME); setShowParameterValue(true); setFilterClass(FilterStraightenRepresentation.class); @@ -48,6 +48,7 @@ public class FilterStraightenRepresentation extends FilterRepresentation { public FilterStraightenRepresentation(FilterStraightenRepresentation s) { this(s.getStraighten()); + setName(s.getName()); } public FilterStraightenRepresentation() { diff --git a/src/com/android/gallery3d/filtershow/filters/FilterVignetteRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterVignetteRepresentation.java index 2e362f8b5..d316adeed 100644 --- a/src/com/android/gallery3d/filtershow/filters/FilterVignetteRepresentation.java +++ b/src/com/android/gallery3d/filtershow/filters/FilterVignetteRepresentation.java @@ -43,7 +43,7 @@ public class FilterVignetteRepresentation extends FilterRepresentation implement private static int MAX = 100; private static int MAXFALLOF = 200; - private BasicParameterInt mParamVignette = new BasicParameterInt(MODE_VIGNETTE, 0, MIN, MAX); + private BasicParameterInt mParamVignette = new BasicParameterInt(MODE_VIGNETTE, 50, MIN, MAX); private BasicParameterInt mParamExposure = new BasicParameterInt(MODE_EXPOSURE, 0, MIN, MAX); private BasicParameterInt mParamSaturation = new BasicParameterInt(MODE_SATURATION, 0, MIN, MAX); private BasicParameterInt mParamContrast = new BasicParameterInt(MODE_CONTRAST, 0, MIN, MAX); diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterNegative.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterNegative.java index 98497596b..9a1a84030 100644 --- a/src/com/android/gallery3d/filtershow/filters/ImageFilterNegative.java +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterNegative.java @@ -19,6 +19,7 @@ public class ImageFilterNegative extends ImageFilter { representation.setShowParameterValue(false); representation.setEditorId(ImageOnlyEditor.ID); representation.setSupportsPartialRendering(true); + representation.setIsBooleanFilter(true); return representation; } diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterTinyPlanet.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterTinyPlanet.java index 77250bd7a..6cc49705f 100644 --- a/src/com/android/gallery3d/filtershow/filters/ImageFilterTinyPlanet.java +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterTinyPlanet.java @@ -23,6 +23,7 @@ import android.graphics.RectF; import com.adobe.xmp.XMPException; import com.adobe.xmp.XMPMeta; import com.android.gallery3d.app.Log; +import com.android.gallery3d.filtershow.cache.BitmapCache; import com.android.gallery3d.filtershow.cache.ImageLoader; import com.android.gallery3d.filtershow.imageshow.MasterImage; import com.android.gallery3d.filtershow.pipeline.ImagePreset; @@ -92,7 +93,8 @@ public class ImageFilterTinyPlanet extends SimpleImageFilter { } while (mBitmapOut == null) { try { - mBitmapOut = getEnvironment().getBitmap(outputSize, outputSize); + mBitmapOut = getEnvironment().getBitmap(outputSize, + outputSize, BitmapCache.TINY_PLANET); } catch (java.lang.OutOfMemoryError e) { System.gc(); outputSize /= 2; diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterVignette.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterVignette.java index 0ab5016cd..49ac5959c 100644 --- a/src/com/android/gallery3d/filtershow/filters/ImageFilterVignette.java +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterVignette.java @@ -19,8 +19,10 @@ package com.android.gallery3d.filtershow.filters; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Canvas; +import android.graphics.Matrix; import android.graphics.Rect; import com.android.gallery3d.R; +import com.android.gallery3d.filtershow.imageshow.MasterImage; import com.android.gallery3d.filtershow.pipeline.FilterEnvironment; import android.support.v8.renderscript.Allocation; import android.support.v8.renderscript.Element; @@ -91,16 +93,23 @@ public class ImageFilterVignette extends ImageFilterRS { float r = calcRadius(cx, cy, w, h); float rx = r; float ry = r; - if (mParameters.isCenterSet()) { - - cx = mParameters.getCenterX() * w; - cy = mParameters.getCenterY() * h; - rx = mParameters.getRadiusX() * w; - ry = mParameters.getRadiusY() * h; + float[]c = new float[2]; + if (mParameters.isCenterSet()) { + Matrix m = getOriginalToScreenMatrix(w, h); + Rect bounds = MasterImage.getImage().getOriginalBounds(); + c[0] = bounds.right * mParameters.getCenterX(); + c[1] = bounds.bottom * mParameters.getCenterY(); + m.mapPoints(c); + cx = c[0]; + cy = c[1]; + c[0] = bounds.right * mParameters.getRadiusX(); + c[1] = bounds.bottom * mParameters.getRadiusY(); + m.mapVectors(c); + rx = c[0]; + ry = c[1]; } - mScript.set_inputWidth(w); mScript.set_inputHeight(h); int v = mParameters.getValue(MODE_VIGNETTE); @@ -115,7 +124,6 @@ public class ImageFilterVignette extends ImageFilterRS { mScript.set_strength(mParameters.getValue(MODE_FALLOFF)/10.f); mScript.invoke_setupVignetteParams(); mScript.forEach_vignette(getInPixelsAllocation(), getOutPixelsAllocation()); - } @Override diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterWBalance.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterWBalance.java index 6bb88ec21..7aa19a4a9 100644 --- a/src/com/android/gallery3d/filtershow/filters/ImageFilterWBalance.java +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterWBalance.java @@ -38,6 +38,7 @@ public class ImageFilterWBalance extends ImageFilter { representation.setShowParameterValue(false); representation.setEditorId(ImageOnlyEditor.ID); representation.setSupportsPartialRendering(true); + representation.setIsBooleanFilter(true); return representation; } diff --git a/src/com/android/gallery3d/filtershow/history/HistoryManager.java b/src/com/android/gallery3d/filtershow/history/HistoryManager.java index 755e2ea58..569b299cc 100644 --- a/src/com/android/gallery3d/filtershow/history/HistoryManager.java +++ b/src/com/android/gallery3d/filtershow/history/HistoryManager.java @@ -42,6 +42,9 @@ public class HistoryManager { } public HistoryItem getItem(int position) { + if (position > mHistoryItems.size() - 1) { + return null; + } return mHistoryItems.elementAt(position); } @@ -58,7 +61,7 @@ public class HistoryManager { } public boolean canReset() { - if (getCount() <= 1) { + if (getCount() <= 0) { return false; } return true; @@ -108,9 +111,7 @@ public class HistoryManager { if (getCount() == 0) { return; } - HistoryItem first = getItem(getCount() - 1); clear(); - addHistoryItem(first); updateMenuItems(); } diff --git a/src/com/android/gallery3d/filtershow/imageshow/EclipseControl.java b/src/com/android/gallery3d/filtershow/imageshow/EclipseControl.java index 4c0c24d8c..b94e52e48 100644 --- a/src/com/android/gallery3d/filtershow/imageshow/EclipseControl.java +++ b/src/com/android/gallery3d/filtershow/imageshow/EclipseControl.java @@ -108,36 +108,26 @@ public class EclipseControl { return (!mImageBounds.contains((int) x1, (int) y1)); } - public void actionDown2(float x, float y, int iw, int ih, Oval oval) { + public void actionDown(float x, float y, Oval oval) { float[] point = new float[]{ x, y}; mScrToImg.mapPoints(point); mDownX = point[0]; mDownY = point[1]; - mDownCenterX = oval.getCenterX() * iw; - mDownCenterY = oval.getCenterY() * ih; - mDownRadiusX = oval.getRadiusX() * iw; - mDownRadiusY = oval.getRadiusY() * ih; + mDownCenterX = oval.getCenterX(); + mDownCenterY = oval.getCenterY(); + mDownRadiusX = oval.getRadiusX(); + mDownRadiusY = oval.getRadiusY(); } - public void actionDown(float x, float y, Oval oval) { - actionDown2(x, y, 1, 1, oval); - } public void actionMove(int handle, float x, float y, Oval oval) { - actionMove2(handle, x, y, 1, 1, oval); - } - - public void actionMove2(int handle, float x, float y, int w, int h, Oval oval) { float[] point = new float[]{ x, y}; mScrToImg.mapPoints(point); x = point[0]; y = point[1]; - if (w == 0) { - w = 1; - h = 1; - } + // Test if the matrix is swapping x and y point[0] = 0; point[1] = 1; @@ -152,7 +142,7 @@ public class EclipseControl { if (centerIsOutside(x - ctrdx, y - ctrdy)) { break; } - oval.setCenter((x - ctrdx) / w, (y - ctrdy) / h); + oval.setCenter((x - ctrdx), (y - ctrdy)); // setRepresentation(mVignetteRep); break; case HAN_NORTH: @@ -160,10 +150,10 @@ public class EclipseControl { case HAN_SOUTH: if (swapxy) { float raddx = mDownRadiusY - Math.abs(mDownX - mDownCenterY); - oval.setRadiusY(Math.abs(x - oval.getCenterY() * h + sign * raddx)/h); + oval.setRadiusY(Math.abs(x - oval.getCenterY() + sign * raddx)); } else { float raddy = mDownRadiusY - Math.abs(mDownY - mDownCenterY); - oval.setRadiusY(Math.abs(y - oval.getCenterY() * h + sign * raddy)/h); + oval.setRadiusY(Math.abs(y - oval.getCenterY() + sign * raddy)); } break; case HAN_EAST: @@ -171,10 +161,10 @@ public class EclipseControl { case HAN_WEST: if (swapxy) { float raddy = mDownRadiusX - Math.abs(mDownY - mDownCenterX); - oval.setRadiusX(Math.abs(y - oval.getCenterX() * w + sign * raddy)/w); + oval.setRadiusX(Math.abs(y - oval.getCenterX() + sign * raddy)); } else { float raddx = mDownRadiusX - Math.abs(mDownX - mDownCenterX); - oval.setRadiusX(Math.abs(x - oval.getCenterX() * w - sign * raddx)/w); + oval.setRadiusX(Math.abs(x - oval.getCenterX() - sign * raddx)); } break; case HAN_SE: @@ -186,13 +176,13 @@ public class EclipseControl { float ctr_dx = mDownX - mDownCenterX; float ctr_dy = mDownY - mDownCenterY; float downRad = Math.abs(ctr_dx) + Math.abs(ctr_dy) - dr; - float rx = oval.getRadiusX() * w; - float ry = oval.getRadiusY() * h; + float rx = oval.getRadiusX(); + float ry = oval.getRadiusY(); float r = (Math.abs(rx) + Math.abs(ry)) * sin45; - float dx = x - oval.getCenterX() * w; - float dy = y - oval.getCenterY() * h; + float dx = x - oval.getCenterX(); + float dy = y - oval.getCenterY(); float nr = Math.abs(Math.abs(dx) + Math.abs(dy) - downRad); - oval.setRadius((rx * nr / r) / w, (ry * nr / r) / h); + oval.setRadius((rx * nr / r), (ry * nr / r)); break; } diff --git a/src/com/android/gallery3d/filtershow/imageshow/GeometryMathUtils.java b/src/com/android/gallery3d/filtershow/imageshow/GeometryMathUtils.java index e3cd56db7..dada7dcb2 100644 --- a/src/com/android/gallery3d/filtershow/imageshow/GeometryMathUtils.java +++ b/src/com/android/gallery3d/filtershow/imageshow/GeometryMathUtils.java @@ -22,6 +22,7 @@ import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.RectF; +import android.util.Log; import com.android.gallery3d.filtershow.cache.BitmapCache; import com.android.gallery3d.filtershow.cache.ImageLoader; @@ -38,6 +39,9 @@ import java.util.Collection; import java.util.Iterator; public final class GeometryMathUtils { + private static final String TAG = "GeometryMathUtils"; + public static final float SHOW_SCALE = .9f; + private GeometryMathUtils() {}; // Holder class for Geometry data. @@ -313,7 +317,8 @@ public final class GeometryMathUtils { Matrix m = getCropSelectionToScreenMatrix(null, holder, width, height, frame.width(), frame.height()); BitmapCache bitmapCache = MasterImage.getImage().getBitmapCache(); - Bitmap temp = bitmapCache.getBitmap(frame.width(), frame.height()); + Bitmap temp = bitmapCache.getBitmap(frame.width(), + frame.height(), BitmapCache.UTIL_GEOMETRY); Canvas canvas = new Canvas(temp); Paint paint = new Paint(); paint.setAntiAlias(true); @@ -434,7 +439,15 @@ public final class GeometryMathUtils { public static Matrix getFullGeometryToScreenMatrix(GeometryHolder holder, int bitmapWidth, int bitmapHeight, int viewWidth, int viewHeight) { - float scale = GeometryMathUtils.scale(bitmapWidth, bitmapHeight, viewWidth, viewHeight); + int bh = bitmapHeight; + int bw = bitmapWidth; + if (GeometryMathUtils.needsDimensionSwap(holder.rotation)) { + bh = bitmapWidth; + bw = bitmapHeight; + } + float scale = GeometryMathUtils.scale(bw, bh, viewWidth, viewHeight); + scale *= SHOW_SCALE; + float s = Math.min(viewWidth / (float) bitmapWidth, viewHeight / (float) bitmapHeight); Matrix m = getFullGeometryMatrix(holder, bitmapWidth, bitmapHeight); m.postScale(scale, scale); m.postTranslate(viewWidth / 2f, viewHeight / 2f); diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageCrop.java b/src/com/android/gallery3d/filtershow/imageshow/ImageCrop.java index e027d01e8..4b0399128 100644 --- a/src/com/android/gallery3d/filtershow/imageshow/ImageCrop.java +++ b/src/com/android/gallery3d/filtershow/imageshow/ImageCrop.java @@ -282,6 +282,22 @@ public class ImageCrop extends ImageShow { // Scale min side and tolerance by display matrix scale factor mCropObj.setMinInnerSideSize(mDisplayMatrixInverse.mapRadius(mMinSideSize)); mCropObj.setTouchTolerance(mDisplayMatrixInverse.mapRadius(mTouchTolerance)); + // drive Crop engine to clamp to crop bounds + int[] sides = {CropObject.MOVE_TOP, + CropObject.MOVE_BOTTOM, + CropObject.MOVE_LEFT, + CropObject.MOVE_RIGHT}; + int delta = Math.min(canvas.getWidth(), canvas.getHeight()) / 4; + int[] dy = {delta, -delta, 0, 0}; + int[] dx = {0, 0, delta, -delta}; + + for (int i = 0; i < sides.length; i++) { + mCropObj.selectEdge(sides[i]); + + mCropObj.moveCurrentSelection(dx[i], dy[i]); + mCropObj.moveCurrentSelection(-dx[i], -dy[i]); + } + mCropObj.selectEdge(CropObject.MOVE_NONE); } // Draw actual bitmap mPaint.reset(); @@ -297,6 +313,7 @@ public class ImageCrop extends ImageShow { if (mDisplayCropMatrix.mapRect(mScreenCropBounds)) { // Draw crop rect and markers CropDrawingUtils.drawCropRect(canvas, mScreenCropBounds); + CropDrawingUtils.drawShade(canvas, mScreenCropBounds); CropDrawingUtils.drawRuleOfThird(canvas, mScreenCropBounds); CropDrawingUtils.drawIndicators(canvas, mCropIndicator, mIndicatorSize, mScreenCropBounds, mCropObj.isFixedAspect(), diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageCurves.java b/src/com/android/gallery3d/filtershow/imageshow/ImageCurves.java index 82c4b2fc7..0d20322d6 100644 --- a/src/com/android/gallery3d/filtershow/imageshow/ImageCurves.java +++ b/src/com/android/gallery3d/filtershow/imageshow/ImageCurves.java @@ -34,6 +34,7 @@ import android.widget.LinearLayout; import android.widget.PopupMenu; import com.android.gallery3d.R; +import com.android.gallery3d.filtershow.FilterShowActivity; import com.android.gallery3d.filtershow.editors.Editor; import com.android.gallery3d.filtershow.editors.EditorCurves; import com.android.gallery3d.filtershow.filters.FilterCurvesRepresentation; @@ -116,6 +117,7 @@ public class ImageCurves extends ImageShow { }); Editor.hackFixStrings(popupMenu.getMenu()); popupMenu.show(); + ((FilterShowActivity)getContext()).onShowMenu(popupMenu); } @Override diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageDraw.java b/src/com/android/gallery3d/filtershow/imageshow/ImageDraw.java index 0fdac1c09..795a24781 100644 --- a/src/com/android/gallery3d/filtershow/imageshow/ImageDraw.java +++ b/src/com/android/gallery3d/filtershow/imageshow/ImageDraw.java @@ -244,20 +244,11 @@ public class ImageDraw extends ImageShow { byte type = mTmpStrokData.mType; float radius = mTmpStrokData.mRadius; mFRep.fillStrokeParameters(mTmpStrokData); - if (type != mTmpStrokData.mType || radius != mTmpStrokData.mRadius) { - mBitmap = getBrush(mEditorDraw.getBrushIcon(mTmpStrokData.mType)); - float size = mRotateToScreen.mapRadius(mTmpStrokData.mRadius) * 2; - mBitmap = createScaledBitmap(mBitmap, (int) size, (int) size, true); - } - if (color == mTmpStrokData.mColor - && type == mTmpStrokData.mType - && radius == mTmpStrokData.mRadius) { - return; + if (radius != mTmpStrokData.mRadius) { + mTimeout = DISPLAY_TIME + System.currentTimeMillis(); + scheduleWakeup(DISPLAY_TIME); } - - mTimeout = DISPLAY_TIME + System.currentTimeMillis(); - scheduleWakeup(DISPLAY_TIME); } public void drawLook(Canvas canvas) { @@ -269,28 +260,22 @@ public class ImageDraw extends ImageShow { int centerx = cw / 2; int centery = ch / 2; - mFRep.fillStrokeParameters(mTmpStrokData); +// mFRep.fillStrokeParameters(mTmpStrokData); mIconPaint.setAntiAlias(true); - mIconPaint.setColor(mTmpStrokData.mColor); - - mIconPaint.setColorFilter(new PorterDuffColorFilter(mTmpStrokData.mColor, - PorterDuff.Mode.MULTIPLY)); + mIconPaint.setStyle(Paint.Style.STROKE); float rad = mRotateToScreen.mapRadius(mTmpStrokData.mRadius); + RectF rec = new RectF(); - rec.set(centerx - mDisplayBorder - rad, - centery - mDisplayBorder - rad, - centerx + mDisplayBorder + rad, - centery + mDisplayBorder + rad); - mShadow.setBounds((int) (mBorderShadowSize + rec.left), - (int) (mBorderShadowSize + rec.top), - (int) (mBorderShadowSize + rec.right), - (int) (mBorderShadowSize + rec.bottom)); - mShadow.draw(canvas); - canvas.drawRoundRect(rec, mDisplayRound, mDisplayRound, mCheckerdPaint); - canvas.drawRoundRect(rec, mDisplayRound, mDisplayRound, mBorderPaint); - canvas.drawBitmap(mBitmap, - centerx - mBitmap.getWidth() / 2, - centery - mBitmap.getHeight() / 2, mIconPaint); + rec.set(centerx - rad, + centery - rad, + centerx + rad, + centery + rad); + mIconPaint.setColor(Color.BLACK); + mIconPaint.setStrokeWidth(5); + canvas.drawArc(rec, 0, 360, true, mIconPaint); + mIconPaint.setColor(Color.WHITE); + mIconPaint.setStrokeWidth(3); + canvas.drawArc(rec, 0, 360, true, mIconPaint); } @Override diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java b/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java index 77eaf4dc7..7089e6036 100644 --- a/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java +++ b/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java @@ -16,6 +16,8 @@ package com.android.gallery3d.filtershow.imageshow; +import android.animation.Animator; +import android.animation.ValueAnimator; import android.content.Context; import android.content.res.Resources; import android.graphics.Bitmap; @@ -27,9 +29,12 @@ import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Point; import android.graphics.Rect; +import android.graphics.RectF; import android.graphics.Shader; import android.graphics.drawable.NinePatchDrawable; +import android.support.v4.widget.EdgeEffectCompat; import android.util.AttributeSet; +import android.util.Log; import android.view.GestureDetector; import android.view.GestureDetector.OnDoubleTapListener; import android.view.GestureDetector.OnGestureListener; @@ -48,7 +53,6 @@ import com.android.gallery3d.filtershow.tools.SaveImage; import java.io.File; import java.util.ArrayList; -import java.util.Collection; public class ImageShow extends View implements OnGestureListener, ScaleGestureDetector.OnScaleGestureListener, @@ -91,6 +95,21 @@ public class ImageShow extends View implements OnGestureListener, Point mOriginalTranslation = new Point(); float mOriginalScale; float mStartFocusX, mStartFocusY; + + private EdgeEffectCompat mEdgeEffect = null; + private static final int EDGE_LEFT = 1; + private static final int EDGE_TOP = 2; + private static final int EDGE_RIGHT = 3; + private static final int EDGE_BOTTOM = 4; + private int mCurrentEdgeEffect = 0; + private int mEdgeSize = 100; + + private static final int mAnimationSnapDelay = 200; + private static final int mAnimationZoomDelay = 400; + private ValueAnimator mAnimatorScale = null; + private ValueAnimator mAnimatorTranslateX = null; + private ValueAnimator mAnimatorTranslateY = null; + private enum InteractionMode { NONE, SCALE, @@ -163,11 +182,14 @@ public class ImageShow extends View implements OnGestureListener, Bitmap mask = BitmapFactory.decodeResource(res, R.drawable.spot_mask); sMask = convertToAlphaMask(mask); } + mEdgeEffect = new EdgeEffectCompat(context); + mEdgeSize = res.getDimensionPixelSize(R.dimen.edge_glow_size); } public void attach() { MasterImage.getImage().addObserver(this); bindAsImageLoadListener(); + MasterImage.getImage().resetGeometryImages(false); } public void detach() { @@ -231,55 +253,84 @@ public class ImageShow extends View implements OnGestureListener, @Override public void onDraw(Canvas canvas) { + mPaint.reset(); + mPaint.setAntiAlias(true); + mPaint.setFilterBitmap(true); MasterImage.getImage().setImageShowSize( getWidth() - 2*mShadowMargin, getHeight() - 2*mShadowMargin); - float cx = canvas.getWidth()/2.0f; - float cy = canvas.getHeight()/2.0f; - float scaleFactor = MasterImage.getImage().getScaleFactor(); - Point translation = MasterImage.getImage().getTranslation(); + MasterImage img = MasterImage.getImage(); + // Hide the loading indicator as needed + if (mActivity.isLoadingVisible() && getFilteredImage() != null) { + if ((img.getLoadedPreset() == null) + || (img.getLoadedPreset() != null + && img.getLoadedPreset().equals(img.getCurrentPreset()))) { + mActivity.stopLoadingIndicator(); + } else if (img.getLoadedPreset() != null) { + return; + } + mActivity.stopLoadingIndicator(); + } canvas.save(); mShadowDrawn = false; - canvas.save(); - // TODO: center scale on gesture - canvas.scale(scaleFactor, scaleFactor, cx, cy); - canvas.translate(translation.x, translation.y); Bitmap highresPreview = MasterImage.getImage().getHighresImage(); + Bitmap fullHighres = MasterImage.getImage().getPartialImage(); boolean isDoingNewLookAnimation = MasterImage.getImage().onGoingNewLookAnimation(); - if (!isDoingNewLookAnimation && highresPreview != null) { - drawImage(canvas, highresPreview, true); + if (highresPreview == null || isDoingNewLookAnimation) { + drawImageAndAnimate(canvas, getFilteredImage()); } else { - drawImage(canvas, getFilteredImage(), true); + drawImageAndAnimate(canvas, highresPreview); } + + drawHighresImage(canvas, fullHighres); + drawCompareImage(canvas, getGeometryOnlyImage()); + canvas.restore(); - Bitmap partialPreview = MasterImage.getImage().getPartialImage(); - if (!isDoingNewLookAnimation && partialPreview != null) { + if (!mEdgeEffect.isFinished()) { canvas.save(); - Rect originalBounds = MasterImage.getImage().getOriginalBounds(); - Collection<FilterRepresentation> geo = MasterImage.getImage().getPreset() - .getGeometryFilters(); - - Matrix compensation = GeometryMathUtils.getPartialToScreenMatrix(geo, - originalBounds, getWidth(), getHeight(), - partialPreview.getWidth(), partialPreview.getHeight()); - canvas.drawBitmap(partialPreview, compensation, null); + float dx = (getHeight() - getWidth()) / 2f; + if (getWidth() > getHeight()) { + dx = - (getWidth() - getHeight()) / 2f; + } + if (mCurrentEdgeEffect == EDGE_BOTTOM) { + canvas.rotate(180, getWidth()/2, getHeight()/2); + } else if (mCurrentEdgeEffect == EDGE_RIGHT) { + canvas.rotate(90, getWidth()/2, getHeight()/2); + canvas.translate(0, dx); + } else if (mCurrentEdgeEffect == EDGE_LEFT) { + canvas.rotate(270, getWidth()/2, getHeight()/2); + canvas.translate(0, dx); + } + if (mCurrentEdgeEffect != 0) { + mEdgeEffect.draw(canvas); + } canvas.restore(); + invalidate(); + } else { + mCurrentEdgeEffect = 0; } + } - canvas.save(); - canvas.scale(scaleFactor, scaleFactor, cx, cy); - canvas.translate(translation.x, translation.y); - drawPartialImage(canvas, getGeometryOnlyImage()); - canvas.restore(); - - canvas.restore(); + private void drawHighresImage(Canvas canvas, Bitmap fullHighres) { + Matrix originalToScreen = MasterImage.getImage().originalImageToScreen(); + if (fullHighres != null && originalToScreen != null) { + Matrix screenToOriginal = new Matrix(); + originalToScreen.invert(screenToOriginal); + Rect rBounds = new Rect(); + rBounds.set(MasterImage.getImage().getPartialBounds()); + if (fullHighres != null) { + originalToScreen.preTranslate(rBounds.left, rBounds.top); + canvas.clipRect(mImageBounds); + canvas.drawBitmap(fullHighres, originalToScreen, mPaint); + } + } } public void resetImageCaches(ImageShow caller) { @@ -298,52 +349,82 @@ public class ImageShow extends View implements OnGestureListener, return MasterImage.getImage().getFilteredImage(); } - public void drawImage(Canvas canvas, Bitmap image, boolean updateBounds) { + public void drawImageAndAnimate(Canvas canvas, + Bitmap image) { if (image == null) { return; } + MasterImage master = MasterImage.getImage(); + Matrix m = master.computeImageToScreen(image, 0, false); + if (m == null) { + return; + } - Rect d = computeImageBounds(image.getWidth(), image.getHeight()); + canvas.save(); - if (updateBounds) { - mImageBounds = d; + RectF d = new RectF(0, 0, image.getWidth(), image.getHeight()); + m.mapRect(d); + d.roundOut(mImageBounds); + + boolean showAnimatedImage = master.onGoingNewLookAnimation(); + if (!showAnimatedImage && mDidStartAnimation) { + // animation ended, but do we have the correct image to show? + if (master.getPreset().equals(master.getCurrentPreset())) { + // we do, let's stop showing the animated image + mDidStartAnimation = false; + MasterImage.getImage().resetAnimBitmap(); + } else { + showAnimatedImage = true; + } + } else if (showAnimatedImage) { + mDidStartAnimation = true; } - float centerX = mShadowMargin + (getWidth() - 2 * mShadowMargin) / 2; - float centerY = mShadowMargin + (getHeight() - 2 * mShadowMargin) / 2; + if (showAnimatedImage) { + canvas.save(); + + // Animation uses the image before the change + Bitmap previousImage = master.getPreviousImage(); + Matrix mp = master.computeImageToScreen(previousImage, 0, false); + RectF dp = new RectF(0, 0, previousImage.getWidth(), previousImage.getHeight()); + mp.mapRect(dp); + Rect previousBounds = new Rect(); + dp.roundOut(previousBounds); + float centerX = dp.centerX(); + float centerY = dp.centerY(); + boolean needsToDrawImage = true; - MasterImage master = MasterImage.getImage(); - canvas.save(); - if (master.onGoingNewLookAnimation() - || mDidStartAnimation) { - mDidStartAnimation = true; if (master.getCurrentLookAnimation() - == MasterImage.CIRCLE_ANIMATION - && MasterImage.getImage().getPreviousImage() != null) { + == MasterImage.CIRCLE_ANIMATION) { float maskScale = MasterImage.getImage().getMaskScale(); - if (maskScale > 0.0f) { + if (maskScale >= 0.0f) { float maskW = sMask.getWidth() / 2.0f; float maskH = sMask.getHeight() / 2.0f; - float x = centerX - maskW * maskScale; - float y = centerY - maskH * maskScale; + Point point = mActivity.hintTouchPoint(this); + float maxMaskScale = 2 * Math.max(getWidth(), getHeight()) + / Math.min(maskW, maskH); + maskScale = maskScale * maxMaskScale; + float x = point.x - maskW * maskScale; + float y = point.y - maskH * maskScale; // Prepare the shader mShaderMatrix.reset(); mShaderMatrix.setScale(1.0f / maskScale, 1.0f / maskScale); - mShaderMatrix.preTranslate(-x + d.left, -y + d.top); - float scaleImageX = d.width() / (float) image.getWidth(); - float scaleImageY = d.height() / (float) image.getHeight(); + mShaderMatrix.preTranslate(-x + mImageBounds.left, -y + mImageBounds.top); + float scaleImageX = mImageBounds.width() / (float) image.getWidth(); + float scaleImageY = mImageBounds.height() / (float) image.getHeight(); mShaderMatrix.preScale(scaleImageX, scaleImageY); mMaskPaint.reset(); mMaskPaint.setShader(createShader(image)); mMaskPaint.getShader().setLocalMatrix(mShaderMatrix); - drawImage(canvas, MasterImage.getImage().getPreviousImage()); + drawShadow(canvas, mImageBounds); // as needed + canvas.drawBitmap(previousImage, m, mPaint); + canvas.clipRect(mImageBounds); canvas.translate(x, y); canvas.scale(maskScale, maskScale); canvas.drawBitmap(sMask, 0, 0, mMaskPaint); - } else { - drawImage(canvas, image); + needsToDrawImage = false; } } else if (master.getCurrentLookAnimation() == MasterImage.ROTATE_ANIMATION) { @@ -356,7 +437,6 @@ public class ImageShow extends View implements OnGestureListener, + (finalScale * master.getAnimFraction()); canvas.rotate(master.getAnimRotationValue(), centerX, centerY); canvas.scale(finalScale, finalScale, centerX, centerY); - drawImage(canvas, master.getPreviousImage()); } else if (master.getCurrentLookAnimation() == MasterImage.MIRROR_ANIMATION) { if (master.getCurrentFilterRepresentation() @@ -392,33 +472,22 @@ public class ImageShow extends View implements OnGestureListener, } } } - drawImage(canvas, master.getPreviousImage()); } + + if (needsToDrawImage) { + drawShadow(canvas, previousBounds); // as needed + canvas.drawBitmap(previousImage, mp, mPaint); + } + + canvas.restore(); } else { - drawImage(canvas, image); + drawShadow(canvas, mImageBounds); // as needed + canvas.drawBitmap(image, m, mPaint); } - if (!master.onGoingNewLookAnimation() - && mDidStartAnimation - && !master.getPreviousPreset().equals(master.getCurrentPreset())) { - mDidStartAnimation = false; - MasterImage.getImage().resetAnimBitmap(); - } canvas.restore(); } - private void drawImage(Canvas canvas, Bitmap image) { - Rect d = computeImageBounds(image.getWidth(), image.getHeight()); - float scaleImageX = d.width() / (float) image.getWidth(); - float scaleImageY = d.height() / (float) image.getHeight(); - Matrix imageMatrix = new Matrix(); - imageMatrix.postScale(scaleImageX, scaleImageY); - imageMatrix.postTranslate(d.left, d.top); - drawShadow(canvas, d); - canvas.clipRect(d); - canvas.drawBitmap(image, imageMatrix, mPaint); - } - private Rect computeImageBounds(int imageWidth, int imageHeight) { float scale = GeometryMathUtils.scale(imageWidth, imageHeight, getWidth(), getHeight()); @@ -443,8 +512,9 @@ public class ImageShow extends View implements OnGestureListener, } } - public void drawPartialImage(Canvas canvas, Bitmap image) { - boolean showsOriginal = MasterImage.getImage().showsOriginal(); + public void drawCompareImage(Canvas canvas, Bitmap image) { + MasterImage master = MasterImage.getImage(); + boolean showsOriginal = master.showsOriginal(); if (!showsOriginal && !mTouchShowOriginal) return; canvas.save(); @@ -472,8 +542,20 @@ public class ImageShow extends View implements OnGestureListener, Rect d = new Rect(mImageBounds.left, mImageBounds.top, mImageBounds.left + px, mImageBounds.top + py); + if (mShowOriginalDirection == UNVEIL_HORIZONTAL) { + if (mTouchDown.x - mTouch.x > 0) { + d.set(mImageBounds.left + px, mImageBounds.top, + mImageBounds.right, mImageBounds.top + py); + } + } else { + if (mTouchDown.y - mTouch.y > 0) { + d.set(mImageBounds.left, mImageBounds.top + py, + mImageBounds.left + px, mImageBounds.bottom); + } + } canvas.clipRect(d); - drawImage(canvas, image, false); + Matrix m = master.computeImageToScreen(image, 0, false); + canvas.drawBitmap(image, m, mPaint); Paint paint = new Paint(); paint.setColor(Color.BLACK); paint.setStrokeWidth(3); @@ -566,7 +648,6 @@ public class ImageShow extends View implements OnGestureListener, Point translation = MasterImage.getImage().getTranslation(); translation.x = (int) (originalTranslation.x + translateX); translation.y = (int) (originalTranslation.y + translateY); - constrainTranslation(translation, scaleFactor); MasterImage.getImage().setTranslation(translation); mTouchShowOriginal = false; } else if (enableComparison() && !mOriginalDisabled @@ -577,7 +658,9 @@ public class ImageShow extends View implements OnGestureListener, } } - if (action == MotionEvent.ACTION_UP) { + if (action == MotionEvent.ACTION_UP + || action == MotionEvent.ACTION_CANCEL + || action == MotionEvent.ACTION_OUTSIDE) { mInteractionMode = InteractionMode.NONE; mTouchShowOriginal = false; mTouchDown.x = 0; @@ -589,10 +672,67 @@ public class ImageShow extends View implements OnGestureListener, MasterImage.getImage().resetTranslation(); } } + + float scaleFactor = MasterImage.getImage().getScaleFactor(); + Point translation = MasterImage.getImage().getTranslation(); + constrainTranslation(translation, scaleFactor); + MasterImage.getImage().setTranslation(translation); + invalidate(); return true; } + private void startAnimTranslation(int fromX, int toX, + int fromY, int toY, int delay) { + if (fromX == toX && fromY == toY) { + return; + } + if (mAnimatorTranslateX != null) { + mAnimatorTranslateX.cancel(); + } + if (mAnimatorTranslateY != null) { + mAnimatorTranslateY.cancel(); + } + mAnimatorTranslateX = ValueAnimator.ofInt(fromX, toX); + mAnimatorTranslateY = ValueAnimator.ofInt(fromY, toY); + mAnimatorTranslateX.setDuration(delay); + mAnimatorTranslateY.setDuration(delay); + mAnimatorTranslateX.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + Point translation = MasterImage.getImage().getTranslation(); + translation.x = (Integer) animation.getAnimatedValue(); + MasterImage.getImage().setTranslation(translation); + invalidate(); + } + }); + mAnimatorTranslateY.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + Point translation = MasterImage.getImage().getTranslation(); + translation.y = (Integer) animation.getAnimatedValue(); + MasterImage.getImage().setTranslation(translation); + invalidate(); + } + }); + mAnimatorTranslateX.start(); + mAnimatorTranslateY.start(); + } + + private void applyTranslationConstraints() { + float scaleFactor = MasterImage.getImage().getScaleFactor(); + Point translation = MasterImage.getImage().getTranslation(); + int x = translation.x; + int y = translation.y; + constrainTranslation(translation, scaleFactor); + + if (x != translation.x || y != translation.y) { + startAnimTranslation(x, translation.x, + y, translation.y, + mAnimationSnapDelay); + } + } + protected boolean enableComparison() { return true; } @@ -601,34 +741,130 @@ public class ImageShow extends View implements OnGestureListener, public boolean onDoubleTap(MotionEvent arg0) { mZoomIn = !mZoomIn; float scale = 1.0f; + final float x = arg0.getX(); + final float y = arg0.getY(); if (mZoomIn) { scale = MasterImage.getImage().getMaxScaleFactor(); } if (scale != MasterImage.getImage().getScaleFactor()) { - MasterImage.getImage().setScaleFactor(scale); - float translateX = (getWidth() / 2 - arg0.getX()); - float translateY = (getHeight() / 2 - arg0.getY()); + if (mAnimatorScale != null) { + mAnimatorScale.cancel(); + } + mAnimatorScale = ValueAnimator.ofFloat( + MasterImage.getImage().getScaleFactor(), + scale + ); + float translateX = (getWidth() / 2 - x); + float translateY = (getHeight() / 2 - y); Point translation = MasterImage.getImage().getTranslation(); - translation.x = (int) (mOriginalTranslation.x + translateX); - translation.y = (int) (mOriginalTranslation.y + translateY); + int startTranslateX = translation.x; + int startTranslateY = translation.y; + if (scale != 1.0f) { + translation.x = (int) (mOriginalTranslation.x + translateX); + translation.y = (int) (mOriginalTranslation.y + translateY); + } else { + translation.x = 0; + translation.y = 0; + } constrainTranslation(translation, scale); - MasterImage.getImage().setTranslation(translation); - invalidate(); + + startAnimTranslation(startTranslateX, translation.x, + startTranslateY, translation.y, + mAnimationZoomDelay); + mAnimatorScale.setDuration(mAnimationZoomDelay); + mAnimatorScale.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + MasterImage.getImage().setScaleFactor((Float) animation.getAnimatedValue()); + invalidate(); + } + }); + mAnimatorScale.addListener(new Animator.AnimatorListener() { + @Override + public void onAnimationStart(Animator animation) { + } + + @Override + public void onAnimationEnd(Animator animation) { + applyTranslationConstraints(); + MasterImage.getImage().needsUpdatePartialPreview(); + invalidate(); + } + + @Override + public void onAnimationCancel(Animator animation) { + + } + + @Override + public void onAnimationRepeat(Animator animation) { + + } + }); + mAnimatorScale.start(); } return true; } private void constrainTranslation(Point translation, float scale) { - float maxTranslationX = getWidth() / scale; - float maxTranslationY = getHeight() / scale; - if (Math.abs(translation.x) > maxTranslationX) { - translation.x = (int) (Math.signum(translation.x) * - maxTranslationX); - if (Math.abs(translation.y) > maxTranslationY) { - translation.y = (int) (Math.signum(translation.y) * - maxTranslationY); + int currentEdgeEffect = 0; + if (scale <= 1) { + mCurrentEdgeEffect = 0; + mEdgeEffect.finish(); + return; + } + + Matrix originalToScreen = MasterImage.getImage().originalImageToScreen(); + Rect originalBounds = MasterImage.getImage().getOriginalBounds(); + RectF screenPos = new RectF(originalBounds); + originalToScreen.mapRect(screenPos); + + boolean rightConstraint = screenPos.right < getWidth() - mShadowMargin; + boolean leftConstraint = screenPos.left > mShadowMargin; + boolean topConstraint = screenPos.top > mShadowMargin; + boolean bottomConstraint = screenPos.bottom < getHeight() - mShadowMargin; + + if (screenPos.width() > getWidth()) { + if (rightConstraint && !leftConstraint) { + float tx = screenPos.right - translation.x * scale; + translation.x = (int) ((getWidth() - mShadowMargin - tx) / scale); + currentEdgeEffect = EDGE_RIGHT; + } else if (leftConstraint && !rightConstraint) { + float tx = screenPos.left - translation.x * scale; + translation.x = (int) ((mShadowMargin - tx) / scale); + currentEdgeEffect = EDGE_LEFT; + } + } else { + float tx = screenPos.right - translation.x * scale; + float dx = (getWidth() - 2 * mShadowMargin - screenPos.width()) / 2f; + translation.x = (int) ((getWidth() - mShadowMargin - tx - dx) / scale); + } + + if (screenPos.height() > getHeight()) { + if (bottomConstraint && !topConstraint) { + float ty = screenPos.bottom - translation.y * scale; + translation.y = (int) ((getHeight() - mShadowMargin - ty) / scale); + currentEdgeEffect = EDGE_BOTTOM; + } else if (topConstraint && !bottomConstraint) { + float ty = screenPos.top - translation.y * scale; + translation.y = (int) ((mShadowMargin - ty) / scale); + currentEdgeEffect = EDGE_TOP; } + } else { + float ty = screenPos.bottom - translation.y * scale; + float dy = (getHeight()- 2 * mShadowMargin - screenPos.height()) / 2f; + translation.y = (int) ((getHeight() - mShadowMargin - ty - dy) / scale); + } + if (mCurrentEdgeEffect != currentEdgeEffect) { + if (mCurrentEdgeEffect == 0 || currentEdgeEffect != 0) { + mCurrentEdgeEffect = currentEdgeEffect; + mEdgeEffect.finish(); + } + mEdgeEffect.setSize(getWidth(), mEdgeSize); + } + if (currentEdgeEffect != 0) { + mEdgeEffect.onPull(mEdgeSize); } } @@ -692,8 +928,8 @@ public class ImageShow extends View implements OnGestureListener, if (scaleFactor > MasterImage.getImage().getMaxScaleFactor()) { scaleFactor = MasterImage.getImage().getMaxScaleFactor(); } - if (scaleFactor < 0.5) { - scaleFactor = 0.5f; + if (scaleFactor < 1.0f) { + scaleFactor = 1.0f; } MasterImage.getImage().setScaleFactor(scaleFactor); scaleFactor = img.getScaleFactor(); @@ -704,9 +940,7 @@ public class ImageShow extends View implements OnGestureListener, Point translation = MasterImage.getImage().getTranslation(); translation.x = (int) (mOriginalTranslation.x + translateX); translation.y = (int) (mOriginalTranslation.y + translateY); - constrainTranslation(translation, scaleFactor); MasterImage.getImage().setTranslation(translation); - invalidate(); return true; } diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageStraighten.java b/src/com/android/gallery3d/filtershow/imageshow/ImageStraighten.java index a85f58de0..4742f2ecf 100644 --- a/src/com/android/gallery3d/filtershow/imageshow/ImageStraighten.java +++ b/src/com/android/gallery3d/filtershow/imageshow/ImageStraighten.java @@ -16,6 +16,7 @@ package com.android.gallery3d.filtershow.imageshow; +import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; @@ -28,6 +29,7 @@ import android.graphics.RectF; import android.util.AttributeSet; import android.view.MotionEvent; +import com.android.gallery3d.filtershow.crop.CropDrawingUtils; import com.android.gallery3d.filtershow.editors.EditorStraighten; import com.android.gallery3d.filtershow.filters.FilterCropRepresentation; import com.android.gallery3d.filtershow.filters.FilterRepresentation; @@ -43,6 +45,7 @@ public class ImageStraighten extends ImageShow { private float mBaseAngle = 0; private float mAngle = 0; private float mInitialAngle = 0; + private static final int NBLINES = 16; private boolean mFirstDrawSinceUp = false; private EditorStraighten mEditorStraighten; private FilterStraightenRepresentation mLocalRep = new FilterStraightenRepresentation(); @@ -54,6 +57,11 @@ public class ImageStraighten extends ImageShow { NONE, MOVE } private MODES mState = MODES.NONE; + private ValueAnimator mAnimator = null; + private int mDefaultGridAlpha = 60; + private float mGridAlpha = 1f; + private int mOnStartAnimDelay = 1000; + private int mAnimDelay = 500; private static final float MAX_STRAIGHTEN_ANGLE = FilterStraightenRepresentation.MAX_STRAIGHTEN_ANGLE; private static final float MIN_STRAIGHTEN_ANGLE @@ -73,6 +81,27 @@ public class ImageStraighten extends ImageShow { super(context, attrs); } + @Override + public void attach() { + super.attach(); + mGridAlpha = 1f; + hidesGrid(mOnStartAnimDelay); + } + + private void hidesGrid(int delay) { + mAnimator = ValueAnimator.ofFloat(1, 0); + mAnimator.setStartDelay(delay); + mAnimator.setDuration(mAnimDelay); + mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + mGridAlpha = ((Float) animation.getAnimatedValue()); + invalidate(); + } + }); + mAnimator.start(); + } + public void setFilterStraightenRepresentation(FilterStraightenRepresentation rep) { mLocalRep = (rep == null) ? new FilterStraightenRepresentation() : rep; mInitialAngle = mBaseAngle = mAngle = mLocalRep.getStraighten(); @@ -110,6 +139,7 @@ public class ImageStraighten extends ImageShow { mCurrentY = y; computeValue(); mFirstDrawSinceUp = true; + hidesGrid(0); } break; case (MotionEvent.ACTION_MOVE): @@ -175,12 +205,25 @@ public class ImageStraighten extends ImageShow { private void updateCurrentCrop(Matrix m, GeometryHolder h, RectF tmp, int imageWidth, int imageHeight, int viewWidth, int viewHeight) { + tmp.set(0, 0, imageHeight, imageWidth); + m.mapRect(tmp); + float top = tmp.top; + float bottom = tmp.bottom; + float left = tmp.left; + float right = tmp.right; + m.mapRect(tmp); + int iw,ih; if (GeometryMathUtils.needsDimensionSwap(h.rotation)) { tmp.set(0, 0, imageHeight, imageWidth); + iw = imageHeight; + ih = imageWidth; } else { tmp.set(0, 0, imageWidth, imageHeight); + iw = imageWidth; + ih = imageHeight; } - float scale = GeometryMathUtils.scale(imageWidth, imageHeight, viewWidth, viewHeight); + float scale = GeometryMathUtils.scale(iw, ih, viewWidth, viewHeight); + scale *= GeometryMathUtils.SHOW_SCALE; GeometryMathUtils.scaleRect(tmp, scale); getUntranslatedStraightenCropBounds(tmp, mAngle); tmp.offset(viewWidth / 2f - tmp.centerX(), viewHeight / 2f - tmp.centerY()); @@ -229,19 +272,23 @@ public class ImageStraighten extends ImageShow { mLocalRep.setStraighten(mAngle); mFirstDrawSinceUp = false; } - + CropDrawingUtils.drawShade(canvas, mDrawRect); // Draw the grid - if (mState == MODES.MOVE) { + if (mState == MODES.MOVE || mGridAlpha > 0) { canvas.save(); canvas.clipRect(mDrawRect); - int n = 16; - float step = viewWidth / n; + + float step = Math.max(viewWidth, viewHeight) / NBLINES; float p = 0; - for (int i = 1; i < n; i++) { + for (int i = 1; i < NBLINES; i++) { p = i * step; - mPaint.setAlpha(60); + int alpha = (int) (mDefaultGridAlpha * mGridAlpha); + if (alpha == 0 && mState == MODES.MOVE) { + alpha = mDefaultGridAlpha; + } + mPaint.setAlpha(alpha); canvas.drawLine(p, 0, p, viewHeight, mPaint); - canvas.drawLine(0, p, viewHeight, p, mPaint); + canvas.drawLine(0, p, viewWidth, p, mPaint); } canvas.restore(); } @@ -250,6 +297,8 @@ public class ImageStraighten extends ImageShow { mPaint.setStyle(Style.STROKE); mPaint.setStrokeWidth(3); mDrawPath.reset(); + + mDrawPath.addRect(mDrawRect, Path.Direction.CW); canvas.drawPath(mDrawPath, mPaint); } diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageVignette.java b/src/com/android/gallery3d/filtershow/imageshow/ImageVignette.java index 389fe3f41..957128749 100644 --- a/src/com/android/gallery3d/filtershow/imageshow/ImageVignette.java +++ b/src/com/android/gallery3d/filtershow/imageshow/ImageVignette.java @@ -20,7 +20,6 @@ import android.content.Context; import android.graphics.Canvas; import android.graphics.Matrix; import android.util.AttributeSet; -import android.util.Log; import android.view.MotionEvent; import com.android.gallery3d.filtershow.editors.EditorVignette; @@ -31,7 +30,7 @@ public class ImageVignette extends ImageShow { private FilterVignetteRepresentation mVignetteRep; private EditorVignette mEditorVignette; - + private OvalSpaceAdapter mScreenOval = new OvalSpaceAdapter(); private int mActiveHandle = -1; EclipseControl mElipse; @@ -46,6 +45,97 @@ public class ImageVignette extends ImageShow { mElipse = new EclipseControl(context); } + static class OvalSpaceAdapter implements Oval { + private Oval mOval; + Matrix mToScr; + Matrix mToImage; + int mImgWidth; + int mImgHeight; + float[] mTmp = new float[2]; + float mTmpRadiusX; + float mTmpRadiusY; + + public void setImageOval(Oval oval) { + mOval = oval; + } + + public void setTransform(Matrix toScr, Matrix toImage, int imgWidth, int imgHeight) { + mToScr = toScr; + mToImage = toImage; + mImgWidth = imgWidth; + mImgHeight = imgHeight; + mTmpRadiusX = getRadiusX(); + mTmpRadiusY = getRadiusY(); + } + + @Override + public void setCenter(float x, float y) { + mTmp[0] = x; + mTmp[1] = y; + mToImage.mapPoints(mTmp); + mOval.setCenter(mTmp[0] / mImgWidth, mTmp[1] / mImgHeight); + } + + @Override + public void setRadius(float w, float h) { + mTmp[0] = mTmpRadiusX = w; + mTmp[1] = mTmpRadiusY = h; + mToImage.mapVectors(mTmp); + mOval.setRadius(mTmp[0] / mImgWidth, mTmp[1] / mImgHeight); + } + + @Override + public float getCenterX() { + mTmp[0] = mOval.getCenterX() * mImgWidth; + mTmp[1] = mOval.getCenterY() * mImgHeight; + mToScr.mapPoints(mTmp); + + return mTmp[0]; + } + + @Override + public float getCenterY() { + mTmp[0] = mOval.getCenterX() * mImgWidth; + mTmp[1] = mOval.getCenterY() * mImgHeight; + mToScr.mapPoints(mTmp); + return mTmp[1]; + } + + @Override + public float getRadiusX() { + mTmp[0] = mOval.getRadiusX() * mImgWidth; + mTmp[1] = mOval.getRadiusY() * mImgHeight; + mToScr.mapVectors(mTmp); + return Math.abs(mTmp[0]); + } + + @Override + public float getRadiusY() { + mTmp[0] = mOval.getRadiusX() * mImgWidth; + mTmp[1] = mOval.getRadiusY() * mImgHeight; + mToScr.mapVectors(mTmp); + return Math.abs(mTmp[1]); + } + + @Override + public void setRadiusY(float y) { + mTmp[0] = mTmpRadiusX; + mTmp[1] = mTmpRadiusY = y; + mToImage.mapVectors(mTmp); + mOval.setRadiusX(mTmp[0] / mImgWidth); + mOval.setRadiusY(mTmp[1] / mImgHeight); + } + + @Override + public void setRadiusX(float x) { + mTmp[0] = mTmpRadiusX = x; + mTmp[1] = mTmpRadiusY; + mToImage.mapVectors(mTmp); + mOval.setRadiusX(mTmp[0] / mImgWidth); + mOval.setRadiusY(mTmp[1] / mImgHeight); + } + } + @Override public boolean onTouchEvent(MotionEvent event) { int w = MasterImage.getImage().getOriginalBounds().width(); @@ -73,17 +163,18 @@ public class ImageVignette extends ImageShow { float x = event.getX(); float y = event.getY(); - mElipse.setScrImageInfo(getScreenToImageMatrix(true), + mElipse.setScrImageInfo(new Matrix(), MasterImage.getImage().getOriginalBounds()); boolean didComputeEllipses = false; switch (mask) { case (MotionEvent.ACTION_DOWN): - mElipse.actionDown2(x, y, w, h, mVignetteRep); + mElipse.actionDown(x, y, mScreenOval); break; case (MotionEvent.ACTION_UP): case (MotionEvent.ACTION_MOVE): - mElipse.actionMove2(mActiveHandle, x, y, w, h, mVignetteRep); + + mElipse.actionMove(mActiveHandle, x, y, mScreenOval); setRepresentation(mVignetteRep); didComputeEllipses = true; break; @@ -97,6 +188,7 @@ public class ImageVignette extends ImageShow { public void setRepresentation(FilterVignetteRepresentation vignetteRep) { mVignetteRep = vignetteRep; + mScreenOval.setImageOval(mVignetteRep); computeEllipses(); } @@ -109,32 +201,11 @@ public class ImageVignette extends ImageShow { Matrix toImg = getScreenToImageMatrix(false); Matrix toScr = new Matrix(); toImg.invert(toScr); + mScreenOval.setTransform(toScr, toImg, (int) w, (int) h); - float[] c = new float[] { - mVignetteRep.getCenterX() * w, mVignetteRep.getCenterY() * h}; - if (Float.isNaN(c[0])) { - float cx = w / 2; - float cy = h / 2; - float rx = Math.min(cx, cy) * .8f; - float ry = rx; - mVignetteRep.setCenter(cx / w, cy / h); - mVignetteRep.setRadius(rx / w, ry / h); - - c[0] = cx; - c[1] = cy; - toScr.mapPoints(c); - if (getWidth() != 0) { - mElipse.setCenter(c[0], c[1]); - mElipse.setRadius(c[0] * 0.8f, c[1] * 0.8f); - } - } else { - - toScr.mapPoints(c); + mElipse.setCenter(mScreenOval.getCenterX(), mScreenOval.getCenterY()); + mElipse.setRadius(mScreenOval.getRadiusX(), mScreenOval.getRadiusY()); - mElipse.setCenter(c[0], c[1]); - mElipse.setRadius(toScr.mapRadius(mVignetteRep.getRadiusX() * w), - toScr.mapRadius(mVignetteRep.getRadiusY() * h)); - } mEditorVignette.commitLocalRepresentation(); } @@ -144,7 +215,7 @@ public class ImageVignette extends ImageShow { @Override public void onSizeChanged(int w, int h, int oldw, int oldh) { - super.onSizeChanged(w, h, oldw, oldh); + super.onSizeChanged(w, h, oldw, oldh); computeEllipses(); } @@ -159,12 +230,9 @@ public class ImageVignette extends ImageShow { Matrix toImg = getScreenToImageMatrix(false); Matrix toScr = new Matrix(); toImg.invert(toScr); - float[] c = new float[] { - mVignetteRep.getCenterX() * w, mVignetteRep.getCenterY() * h }; - toScr.mapPoints(c); - mElipse.setCenter(c[0], c[1]); - mElipse.setRadius(toScr.mapRadius(mVignetteRep.getRadiusX() * w), - toScr.mapRadius(mVignetteRep.getRadiusY() * h)); + mScreenOval.setTransform(toScr, toImg, (int) w, (int) h); + mElipse.setCenter(mScreenOval.getCenterX(), mScreenOval.getCenterY()); + mElipse.setRadius(mScreenOval.getRadiusX(), mScreenOval.getRadiusY()); mElipse.draw(canvas); } diff --git a/src/com/android/gallery3d/filtershow/imageshow/MasterImage.java b/src/com/android/gallery3d/filtershow/imageshow/MasterImage.java index c562e4a88..3513ded12 100644 --- a/src/com/android/gallery3d/filtershow/imageshow/MasterImage.java +++ b/src/com/android/gallery3d/filtershow/imageshow/MasterImage.java @@ -19,6 +19,7 @@ package com.android.gallery3d.filtershow.imageshow; import android.animation.Animator; import android.animation.ValueAnimator; import android.graphics.Bitmap; +import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Point; import android.graphics.Rect; @@ -70,6 +71,7 @@ public class MasterImage implements RenderingRequestCaller { private Bitmap mOriginalBitmapSmall = null; private Bitmap mOriginalBitmapLarge = null; private Bitmap mOriginalBitmapHighres = null; + private Bitmap mTemporaryThumbnail = null; private int mOrientation; private Rect mOriginalBounds; private final Vector<ImageShow> mLoadListeners = new Vector<ImageShow>(); @@ -81,7 +83,8 @@ public class MasterImage implements RenderingRequestCaller { private Bitmap mPartialBitmap = null; private Bitmap mHighresBitmap = null; private Bitmap mPreviousImage = null; - private ImagePreset mPreviousPreset = null; + private int mShadowMargin = 15; // not scaled, fixed in the asset + private Rect mPartialBounds = new Rect(); private ValueAnimator mAnimator = null; private float mMaskScale = 1; @@ -347,6 +350,10 @@ public class MasterImage implements RenderingRequestCaller { return mPartialBitmap; } + public Rect getPartialBounds() { + return mPartialBounds; + } + public Bitmap getHighresImage() { if (mHighresBitmap == null) { return getFilteredImage(); @@ -358,10 +365,6 @@ public class MasterImage implements RenderingRequestCaller { return mPreviousImage; } - public ImagePreset getPreviousPreset() { - return mPreviousPreset; - } - public ImagePreset getCurrentPreset() { return getPreviewBuffer().getConsumer().getPreset(); } @@ -406,7 +409,6 @@ public class MasterImage implements RenderingRequestCaller { } public void onNewLook(FilterRepresentation newRepresentation) { - getBitmapCache().cache(mPreviousImage); if (getFilteredImage() == null) { return; } @@ -416,13 +418,13 @@ public class MasterImage implements RenderingRequestCaller { mCurrentAnimRotationStartValue += 90; } } else { - mPreviousImage = getBitmapCache().getBitmapCopy(getFilteredImage()); + resetAnimBitmap(); + mPreviousImage = mBitmapCache.getBitmapCopy(getFilteredImage(), BitmapCache.NEW_LOOK); } - mPreviousPreset = getPreviewBuffer().getConsumer().getPreset(); if (newRepresentation instanceof FilterUserPresetRepresentation) { mCurrentLookAnimation = CIRCLE_ANIMATION; - mAnimator = ValueAnimator.ofFloat(0, 20); - mAnimator.setDuration(500); + mAnimator = ValueAnimator.ofFloat(0, 1); + mAnimator.setDuration(650); } if (newRepresentation instanceof FilterRotateRepresentation) { mCurrentLookAnimation = ROTATE_ANIMATION; @@ -457,6 +459,7 @@ public class MasterImage implements RenderingRequestCaller { mOnGoingNewLookAnimation = false; mCurrentAnimRotationStartValue = 0; mAnimator = null; + notifyObservers(); } @Override @@ -480,6 +483,9 @@ public class MasterImage implements RenderingRequestCaller { } public void resetGeometryImages(boolean force) { + if (mPreset == null) { + return; + } ImagePreset newPresetGeometryOnly = new ImagePreset(mPreset); newPresetGeometryOnly.setDoApplyFilters(false); newPresetGeometryOnly.setDoApplyGeometry(true); @@ -514,7 +520,6 @@ public class MasterImage implements RenderingRequestCaller { public void invalidateFiltersOnly() { mFiltersOnlyPreset = null; - resetGeometryImages(false); invalidatePreview(); } @@ -535,6 +540,10 @@ public class MasterImage implements RenderingRequestCaller { } public void invalidatePreview() { + if (mPreset == null) { + return; + } + mPreviewPreset.enqueuePreset(mPreset); mPreviewBuffer.invalidate(); invalidatePartialPreview(); @@ -547,11 +556,66 @@ public class MasterImage implements RenderingRequestCaller { public void setImageShowSize(int w, int h) { if (mImageShowSize.x != w || mImageShowSize.y != h) { mImageShowSize.set(w, h); + float maxWidth = mOriginalBounds.width() / (float) w; + float maxHeight = mOriginalBounds.height() / (float) h; + mMaxScaleFactor = Math.max(3.f, Math.max(maxWidth, maxHeight)); needsUpdatePartialPreview(); needsUpdateHighResPreview(); } } + public Matrix originalImageToScreen() { + return computeImageToScreen(null, 0, true); + } + + public Matrix computeImageToScreen(Bitmap bitmapToDraw, + float rotate, + boolean applyGeometry) { + if (getOriginalBounds() == null + || mImageShowSize.x == 0 + || mImageShowSize.y == 0) { + return null; + } + + Matrix m = null; + float scale = 1f; + float translateX = 0; + float translateY = 0; + + if (applyGeometry) { + GeometryMathUtils.GeometryHolder holder = GeometryMathUtils.unpackGeometry( + mPreset.getGeometryFilters()); + m = GeometryMathUtils.getCropSelectionToScreenMatrix(null, holder, + getOriginalBounds().width(), getOriginalBounds().height(), + mImageShowSize.x, mImageShowSize.y); + } else if (bitmapToDraw != null) { + m = new Matrix(); + RectF size = new RectF(0, 0, + bitmapToDraw.getWidth(), + bitmapToDraw.getHeight()); + scale = mImageShowSize.x / size.width(); + if (size.width() < size.height()) { + scale = mImageShowSize.y / size.height(); + } + translateX = (mImageShowSize.x - (size.width() * scale)) / 2.0f; + translateY = (mImageShowSize.y - (size.height() * scale)) / 2.0f; + } else { + return null; + } + + Point translation = getTranslation(); + m.postScale(scale, scale); + m.postRotate(rotate, mImageShowSize.x / 2.0f, mImageShowSize.y / 2.0f); + m.postTranslate(translateX, translateY); + m.postTranslate(mShadowMargin, mShadowMargin); + m.postScale(getScaleFactor(), getScaleFactor(), + mImageShowSize.x / 2.0f, + mImageShowSize.y / 2.0f); + m.postTranslate(translation.x * getScaleFactor(), + translation.y * getScaleFactor()); + return m; + } + private Matrix getImageToScreenMatrix(boolean reflectRotation) { if (getOriginalBounds() == null || mImageShowSize.x == 0 || mImageShowSize.y == 0) { return new Matrix(); @@ -600,14 +664,21 @@ public class MasterImage implements RenderingRequestCaller { invalidatePartialPreview(); return; } - Matrix m = getScreenToImageMatrix(true); - RectF r = new RectF(0, 0, mImageShowSize.x, mImageShowSize.y); - RectF dest = new RectF(); - m.mapRect(dest, r); - Rect bounds = new Rect(); - dest.roundOut(bounds); + Matrix originalToScreen = MasterImage.getImage().originalImageToScreen(); + if (originalToScreen == null) { + return; + } + Matrix screenToOriginal = new Matrix(); + originalToScreen.invert(screenToOriginal); + RectF bounds = new RectF(0, 0, + mImageShowSize.x + 2 * mShadowMargin, + mImageShowSize.y + 2 * mShadowMargin); + screenToOriginal.mapRect(bounds); + Rect rBounds = new Rect(); + bounds.roundOut(rBounds); + mActivity.getProcessingService().postFullresRenderingRequest(mPreset, - getScaleFactor(), bounds, + getScaleFactor(), rBounds, new Rect(0, 0, mImageShowSize.x, mImageShowSize.y), this); invalidatePartialPreview(); } @@ -634,6 +705,7 @@ public class MasterImage implements RenderingRequestCaller { && request.getScaleFactor() == getScaleFactor()) { mBitmapCache.cache(mPartialBitmap); mPartialBitmap = request.getBitmap(); + mPartialBounds.set(request.getBounds()); notifyObservers(); needsCheckModification = true; } @@ -700,6 +772,16 @@ public class MasterImage implements RenderingRequestCaller { needsUpdatePartialPreview(); } + public Bitmap getTemporaryThumbnailBitmap() { + if (mTemporaryThumbnail == null + && getOriginalBitmapSmall() != null) { + mTemporaryThumbnail = getOriginalBitmapSmall().copy(Bitmap.Config.ARGB_8888, true); + Canvas canvas = new Canvas(mTemporaryThumbnail); + canvas.drawARGB(200, 80, 80, 80); + } + return mTemporaryThumbnail; + } + public Bitmap getThumbnailBitmap() { return getOriginalBitmapSmall(); } diff --git a/src/com/android/gallery3d/filtershow/info/HistogramView.java b/src/com/android/gallery3d/filtershow/info/HistogramView.java index ad56fe47a..99cf235bf 100644 --- a/src/com/android/gallery3d/filtershow/info/HistogramView.java +++ b/src/com/android/gallery3d/filtershow/info/HistogramView.java @@ -27,15 +27,15 @@ import android.graphics.PorterDuffXfermode; import android.os.AsyncTask; import android.util.AttributeSet; import android.view.View; -import com.android.gallery3d.filtershow.imageshow.Spline; public class HistogramView extends View { private Bitmap mBitmap; - int[] redHistogram = new int[256]; - int[] greenHistogram = new int[256]; - int[] blueHistogram = new int[256]; - Path gHistoPath = new Path(); + private Paint mPaint = new Paint(); + private int[] redHistogram = new int[256]; + private int[] greenHistogram = new int[256]; + private int[] blueHistogram = new int[256]; + private Path mHistoPath = new Path(); class ComputeHistogramTask extends AsyncTask<Bitmap, Void, int[]> { @Override @@ -85,28 +85,29 @@ public class HistogramView extends View { max = histogram[i]; } } - float w = getWidth() - Spline.curveHandleSize(); - float h = getHeight() - Spline.curveHandleSize() / 2.0f; - float dx = Spline.curveHandleSize() / 2.0f; + float w = getWidth(); // - Spline.curveHandleSize(); + float h = getHeight(); // - Spline.curveHandleSize() / 2.0f; + float dx = 0; // Spline.curveHandleSize() / 2.0f; float wl = w / histogram.length; float wh = h / max; - Paint paint = new Paint(); - paint.setARGB(100, 255, 255, 255); - paint.setStrokeWidth((int) Math.ceil(wl)); + + mPaint.reset(); + mPaint.setAntiAlias(true); + mPaint.setARGB(100, 255, 255, 255); + mPaint.setStrokeWidth((int) Math.ceil(wl)); // Draw grid - paint.setStyle(Paint.Style.STROKE); - canvas.drawRect(dx, 0, dx + w, h, paint); - canvas.drawLine(dx + w / 3, 0, dx + w / 3, h, paint); - canvas.drawLine(dx + 2 * w / 3, 0, dx + 2 * w / 3, h, paint); - paint.setStyle(Paint.Style.FILL_AND_STROKE); + mPaint.setStyle(Paint.Style.STROKE); + canvas.drawRect(dx, 0, dx + w, h, mPaint); + canvas.drawLine(dx + w / 3, 0, dx + w / 3, h, mPaint); + canvas.drawLine(dx + 2 * w / 3, 0, dx + 2 * w / 3, h, mPaint); - Paint paint2 = new Paint(); - paint2.setColor(color); - paint2.setStrokeWidth(6); - paint2.setXfermode(new PorterDuffXfermode(mode)); - gHistoPath.reset(); - gHistoPath.moveTo(dx, h); + mPaint.setStyle(Paint.Style.FILL); + mPaint.setColor(color); + mPaint.setStrokeWidth(6); + mPaint.setXfermode(new PorterDuffXfermode(mode)); + mHistoPath.reset(); + mHistoPath.moveTo(dx, h); boolean firstPointEncountered = false; float prev = 0; float last = 0; @@ -116,22 +117,22 @@ public class HistogramView extends View { if (l != 0) { float v = h - (l + prev) / 2.0f; if (!firstPointEncountered) { - gHistoPath.lineTo(x, h); + mHistoPath.lineTo(x, h); firstPointEncountered = true; } - gHistoPath.lineTo(x, v); + mHistoPath.lineTo(x, v); prev = l; last = x; } } - gHistoPath.lineTo(last, h); - gHistoPath.lineTo(w, h); - gHistoPath.close(); - canvas.drawPath(gHistoPath, paint2); - paint2.setStrokeWidth(2); - paint2.setStyle(Paint.Style.STROKE); - paint2.setARGB(255, 200, 200, 200); - canvas.drawPath(gHistoPath, paint2); + mHistoPath.lineTo(last, h); + mHistoPath.lineTo(w, h); + mHistoPath.close(); + canvas.drawPath(mHistoPath, mPaint); + mPaint.setStrokeWidth(2); + mPaint.setStyle(Paint.Style.STROKE); + mPaint.setARGB(255, 200, 200, 200); + canvas.drawPath(mHistoPath, mPaint); } public void onDraw(Canvas canvas) { diff --git a/src/com/android/gallery3d/filtershow/info/InfoPanel.java b/src/com/android/gallery3d/filtershow/info/InfoPanel.java index 39102f186..3a6657849 100644 --- a/src/com/android/gallery3d/filtershow/info/InfoPanel.java +++ b/src/com/android/gallery3d/filtershow/info/InfoPanel.java @@ -20,11 +20,12 @@ import android.graphics.Bitmap; import android.graphics.Rect; import android.net.Uri; import android.os.Bundle; -import android.support.v4.app.Fragment; +import android.support.v4.app.DialogFragment; import android.text.Html; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.view.Window; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.LinearLayout; @@ -32,13 +33,12 @@ import android.widget.TextView; import com.android.gallery3d.R; import com.android.gallery3d.exif.ExifInterface; import com.android.gallery3d.exif.ExifTag; -import com.android.gallery3d.filtershow.FilterShowActivity; import com.android.gallery3d.filtershow.cache.ImageLoader; import com.android.gallery3d.filtershow.imageshow.MasterImage; import java.util.List; -public class InfoPanel extends Fragment { +public class InfoPanel extends DialogFragment { public static final String FRAGMENT_TAG = "InfoPanel"; private static final String LOGTAG = FRAGMENT_TAG; private LinearLayout mMainView; @@ -46,7 +46,6 @@ public class InfoPanel extends Fragment { private TextView mImageName; private TextView mImageSize; private TextView mExifData; - private ImageButton mHideButton; private String createStringFromIfFound(ExifTag exifTag, int tag, int str) { String exifString = ""; @@ -63,6 +62,9 @@ public class InfoPanel extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + if (getDialog() != null) { + getDialog().getWindow().requestFeature(Window.FEATURE_NO_TITLE); + } mMainView = (LinearLayout) inflater.inflate( R.layout.filtershow_info_panel, null, false); @@ -74,19 +76,11 @@ public class InfoPanel extends Fragment { mImageName = (TextView) mMainView.findViewById(R.id.imageName); mImageSize = (TextView) mMainView.findViewById(R.id.imageSize); mExifData = (TextView) mMainView.findViewById(R.id.exifData); - mHideButton =(ImageButton) mMainView.findViewById(R.id.cancelInfo); + TextView exifLabel = (TextView) mMainView.findViewById(R.id.exifLabel); HistogramView histogramView = (HistogramView) mMainView.findViewById(R.id.histogramView); - histogramView.setBitmap(bitmap); - mHideButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - FilterShowActivity activity = (FilterShowActivity)getActivity(); - activity.toggleInformationPanel(); - } - }); Uri uri = MasterImage.getImage().getUri(); String path = ImageLoader.getLocalPathFromUri(getActivity(), uri); Uri localUri = null; @@ -102,6 +96,7 @@ public class InfoPanel extends Fragment { List<ExifTag> exif = MasterImage.getImage().getEXIF(); String exifString = ""; + boolean hasExifData = false; if (exif != null) { for (ExifTag tag : exif) { exifString += createStringFromIfFound(tag, @@ -131,9 +126,15 @@ public class InfoPanel extends Fragment { exifString += createStringFromIfFound(tag, ExifInterface.TAG_COPYRIGHT, R.string.filtershow_exif_copyright); + hasExifData = true; } } - mExifData.setText(Html.fromHtml(exifString)); + if (hasExifData) { + exifLabel.setVisibility(View.VISIBLE); + mExifData.setText(Html.fromHtml(exifString)); + } else { + exifLabel.setVisibility(View.GONE); + } return mMainView; } } diff --git a/src/com/android/gallery3d/filtershow/pipeline/Buffer.java b/src/com/android/gallery3d/filtershow/pipeline/Buffer.java index 7b51a75d7..c378eb994 100644 --- a/src/com/android/gallery3d/filtershow/pipeline/Buffer.java +++ b/src/com/android/gallery3d/filtershow/pipeline/Buffer.java @@ -17,6 +17,7 @@ package com.android.gallery3d.filtershow.pipeline; import android.graphics.Bitmap; +import android.graphics.Canvas; import android.support.v8.renderscript.Allocation; import android.support.v8.renderscript.RenderScript; import android.util.Log; @@ -34,8 +35,7 @@ public class Buffer { RenderScript rs = CachingPipeline.getRenderScriptContext(); if (bitmap != null) { BitmapCache cache = MasterImage.getImage().getBitmapCache(); - cache.cache(mBitmap); - mBitmap = cache.getBitmapCopy(bitmap); + mBitmap = cache.getBitmapCopy(bitmap, BitmapCache.PREVIEW_CACHE); } if (mUseAllocation) { // TODO: recreate the allocation when the RS context changes @@ -45,7 +45,23 @@ public class Buffer { } } - public Bitmap getBitmap() { + public boolean isSameSize(Bitmap bitmap) { + if (mBitmap == null || bitmap == null) { + return false; + } + if (mBitmap.getWidth() == bitmap.getWidth() + && mBitmap.getHeight() == bitmap.getHeight()) { + return true; + } + return false; + } + + public synchronized void useBitmap(Bitmap bitmap) { + Canvas canvas = new Canvas(mBitmap); + canvas.drawBitmap(bitmap, 0, 0, null); + } + + public synchronized Bitmap getBitmap() { return mBitmap; } @@ -73,8 +89,9 @@ public class Buffer { public void remove() { BitmapCache cache = MasterImage.getImage().getBitmapCache(); - cache.cache(mBitmap); - mBitmap = null; + if (cache.cache(mBitmap)) { + mBitmap = null; + } } } diff --git a/src/com/android/gallery3d/filtershow/pipeline/CacheProcessing.java b/src/com/android/gallery3d/filtershow/pipeline/CacheProcessing.java index 2a8321908..c2912ed78 100644 --- a/src/com/android/gallery3d/filtershow/pipeline/CacheProcessing.java +++ b/src/com/android/gallery3d/filtershow/pipeline/CacheProcessing.java @@ -18,6 +18,8 @@ package com.android.gallery3d.filtershow.pipeline; import android.graphics.Bitmap; import android.util.Log; + +import com.android.gallery3d.filtershow.cache.BitmapCache; import com.android.gallery3d.filtershow.filters.FilterRepresentation; import com.android.gallery3d.filtershow.imageshow.GeometryMathUtils; @@ -27,6 +29,7 @@ import java.util.Vector; public class CacheProcessing { private static final String LOGTAG = "CacheProcessing"; private static final boolean DEBUG = false; + private static final boolean NO_CACHING = false; private Vector<CacheStep> mSteps = new Vector<CacheStep>(); static class CacheStep { @@ -90,6 +93,7 @@ public class CacheProcessing { public Bitmap apply(FilterEnvironment environment, Bitmap cacheBitmap) { boolean onlyGeometry = true; + Bitmap source = cacheBitmap; for (FilterRepresentation representation : representations) { if (representation.getFilterType() != FilterRepresentation.TYPE_GEOMETRY) { onlyGeometry = false; @@ -101,12 +105,25 @@ public class CacheProcessing { for (FilterRepresentation representation : representations) { geometry.add(representation); } + if (DEBUG) { + Log.v(LOGTAG, "Apply geometry to bitmap " + cacheBitmap); + } cacheBitmap = GeometryMathUtils.applyGeometryRepresentations(geometry, cacheBitmap); } else { for (FilterRepresentation representation : representations) { + if (DEBUG) { + Log.v(LOGTAG, "Apply " + representation.getSerializationName() + + " to bitmap " + cacheBitmap); + } cacheBitmap = environment.applyRepresentation(representation, cacheBitmap); } } + if (cacheBitmap != source) { + environment.cache(source); + } + if (DEBUG) { + Log.v(LOGTAG, "Apply returns bitmap " + cacheBitmap); + } return cacheBitmap; } } @@ -116,9 +133,11 @@ public class CacheProcessing { FilterEnvironment environment) { if (filters.size() == 0) { - return environment.getBitmapCopy(originalBitmap); + return environment.getBitmapCopy(originalBitmap, BitmapCache.PREVIEW_CACHE_NO_FILTERS); } + environment.getBimapCache().setCacheProcessing(this); + if (DEBUG) { displayFilters(filters); } @@ -145,9 +164,9 @@ public class CacheProcessing { if (similar) { similarUpToIndex = i; } else { - environment.cache(cacheStep.cache); mSteps.remove(i); mSteps.insertElementAt(newStep, i); + environment.cache(cacheStep.cache); } } if (DEBUG) { @@ -170,10 +189,26 @@ public class CacheProcessing { + mSteps.size() + " cacheBitmap: " + cacheBitmap); } + if (NO_CACHING) { + cacheBitmap = environment.getBitmapCopy(originalBitmap, + BitmapCache.PREVIEW_CACHE_NO_ROOT); + for (int i = 0; i < mSteps.size(); i++) { + CacheStep step = mSteps.elementAt(i); + Bitmap prev = cacheBitmap; + cacheBitmap = step.apply(environment, cacheBitmap); + if (prev != cacheBitmap) { + environment.cache(prev); + } + } + return cacheBitmap; + } + Bitmap originalCopy = null; + int lastPositionCached = -1; for (int i = findBaseImageIndex; i < mSteps.size(); i++) { if (i == -1 || cacheBitmap == null) { - cacheBitmap = environment.getBitmapCopy(originalBitmap); + cacheBitmap = environment.getBitmapCopy(originalBitmap, + BitmapCache.PREVIEW_CACHE_NO_ROOT); originalCopy = cacheBitmap; if (DEBUG) { Log.v(LOGTAG, "i: " + i + " cacheBitmap: " + cacheBitmap + " w: " @@ -191,9 +226,10 @@ public class CacheProcessing { Log.v(LOGTAG, "i: " + i + " get new copy for cacheBitmap " + cacheBitmap + " apply..."); } - cacheBitmap = environment.getBitmapCopy(cacheBitmap); + cacheBitmap = environment.getBitmapCopy(cacheBitmap, BitmapCache.PREVIEW_CACHE); cacheBitmap = step.apply(environment, cacheBitmap); step.cache = cacheBitmap; + lastPositionCached = i; } } environment.cache(originalCopy); @@ -206,17 +242,34 @@ public class CacheProcessing { // Let's see if we can cleanup the cache for unused bitmaps for (int i = 0; i < similarUpToIndex; i++) { CacheStep currentStep = mSteps.elementAt(i); - environment.cache(currentStep.cache); + Bitmap bitmap = currentStep.cache; currentStep.cache = null; + environment.cache(bitmap); } if (DEBUG) { Log.v(LOGTAG, "cleanup done..."); displayNbBitmapsInCache(); } + if (lastPositionCached != -1) { + // The last element will never be reused, remove it from the cache. + mSteps.elementAt(lastPositionCached).cache = null; + } + if (contains(cacheBitmap)) { + return environment.getBitmapCopy(cacheBitmap, BitmapCache.PREVIEW_CACHE_NO_APPLY); + } return cacheBitmap; } + public boolean contains(Bitmap bitmap) { + for (int i = 0; i < mSteps.size(); i++) { + if (mSteps.elementAt(i).cache == bitmap) { + return true; + } + } + return false; + } + private void displayFilters(Vector<FilterRepresentation> filters) { Log.v(LOGTAG, "------>>> Filters received"); for (int i = 0; i < filters.size(); i++) { diff --git a/src/com/android/gallery3d/filtershow/pipeline/CachingPipeline.java b/src/com/android/gallery3d/filtershow/pipeline/CachingPipeline.java index 823da642a..8ae9a7c7b 100644 --- a/src/com/android/gallery3d/filtershow/pipeline/CachingPipeline.java +++ b/src/com/android/gallery3d/filtershow/pipeline/CachingPipeline.java @@ -19,10 +19,16 @@ package com.android.gallery3d.filtershow.pipeline; import android.content.Context; import android.content.res.Resources; import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.RectF; import android.support.v8.renderscript.Allocation; import android.support.v8.renderscript.RenderScript; import android.util.Log; +import com.android.gallery3d.filtershow.cache.BitmapCache; import com.android.gallery3d.filtershow.cache.ImageLoader; import com.android.gallery3d.filtershow.filters.FilterRepresentation; import com.android.gallery3d.filtershow.filters.FiltersManager; @@ -177,6 +183,9 @@ public class CachingPipeline implements PipelineInterface { } private synchronized boolean updateOriginalAllocation(ImagePreset preset) { + if (preset == null) { + return false; + } Bitmap originalBitmap = mOriginalBitmap; if (originalBitmap == null) { @@ -214,7 +223,7 @@ public class CachingPipeline implements PipelineInterface { if (bitmap == null) { return; } - bitmap = mEnvironment.getBitmapCopy(bitmap); + bitmap = mEnvironment.getBitmapCopy(bitmap, BitmapCache.HIGHRES); bitmap = preset.applyGeometry(bitmap, mEnvironment); mEnvironment.setQuality(FilterEnvironment.QUALITY_PREVIEW); @@ -239,7 +248,7 @@ public class CachingPipeline implements PipelineInterface { if (bitmap == null) { return; } - bitmap = mEnvironment.getBitmapCopy(bitmap); + bitmap = mEnvironment.getBitmapCopy(bitmap, BitmapCache.GEOMETRY); bitmap = preset.applyGeometry(bitmap, mEnvironment); if (!mEnvironment.needsStop()) { request.setBitmap(bitmap); @@ -261,7 +270,7 @@ public class CachingPipeline implements PipelineInterface { if (bitmap == null) { return; } - bitmap = mEnvironment.getBitmapCopy(bitmap); + bitmap = mEnvironment.getBitmapCopy(bitmap, BitmapCache.FILTERS); bitmap = preset.apply(bitmap, mEnvironment); if (!mEnvironment.needsStop()) { request.setBitmap(bitmap); @@ -278,7 +287,8 @@ public class CachingPipeline implements PipelineInterface { if (getRenderScriptContext() == null) { return; } - if (((request.getType() != RenderingRequest.PARTIAL_RENDERING) + if ((request.getType() != RenderingRequest.PARTIAL_RENDERING + && request.getType() != RenderingRequest.ICON_RENDERING && request.getBitmap() == null) || request.getImagePreset() == null) { return; @@ -296,7 +306,7 @@ public class CachingPipeline implements PipelineInterface { if (request.getType() == RenderingRequest.PARTIAL_RENDERING) { MasterImage master = MasterImage.getImage(); bitmap = ImageLoader.getScaleOneImageForPreset(master.getActivity(), - mEnvironment, + mEnvironment.getBimapCache(), master.getUri(), request.getBounds(), request.getDestination()); if (bitmap == null) { @@ -311,7 +321,7 @@ public class CachingPipeline implements PipelineInterface { updateOriginalAllocation(preset); } - if (DEBUG) { + if (DEBUG && bitmap != null) { Log.v(LOGTAG, "after update, req bitmap (" + bitmap.getWidth() + "x" + bitmap.getHeight() + " ? resizeOriginal (" + mResizedOriginalBitmap.getWidth() + "x" + mResizedOriginalBitmap.getHeight()); @@ -336,6 +346,29 @@ public class CachingPipeline implements PipelineInterface { mEnvironment.setQuality(FilterEnvironment.QUALITY_PREVIEW); } + if (request.getType() == RenderingRequest.ICON_RENDERING) { + Rect iconBounds = request.getIconBounds(); + Bitmap source = MasterImage.getImage().getThumbnailBitmap(); + if (iconBounds.width() > source.getWidth() * 2) { + source = MasterImage.getImage().getLargeThumbnailBitmap(); + } + if (iconBounds != null) { + bitmap = mEnvironment.getBitmap(iconBounds.width(), + iconBounds.height(), BitmapCache.ICON); + Canvas canvas = new Canvas(bitmap); + Matrix m = new Matrix(); + float minSize = Math.min(source.getWidth(), source.getHeight()); + float maxSize = Math.max(iconBounds.width(), iconBounds.height()); + float scale = maxSize / minSize; + m.setScale(scale, scale); + float dx = (iconBounds.width() - (source.getWidth() * scale))/2.0f; + float dy = (iconBounds.height() - (source.getHeight() * scale))/2.0f; + m.postTranslate(dx, dy); + canvas.drawBitmap(source, m, new Paint(Paint.FILTER_BITMAP_FLAG)); + } else { + bitmap = mEnvironment.getBitmapCopy(source, BitmapCache.ICON); + } + } Bitmap bmp = preset.apply(bitmap, mEnvironment); if (!mEnvironment.needsStop()) { request.setBitmap(bmp); @@ -391,57 +424,6 @@ public class CachingPipeline implements PipelineInterface { mEnvironment.cache(result); } - public synchronized void computeOld(SharedBuffer buffer, ImagePreset preset, int type) { - synchronized (CachingPipeline.class) { - if (getRenderScriptContext() == null) { - return; - } - if (DEBUG) { - Log.v(LOGTAG, "compute preset " + preset); - preset.showFilters(); - } - - String thread = Thread.currentThread().getName(); - long time = System.currentTimeMillis(); - setupEnvironment(preset, false); - mFiltersManager.freeFilterResources(preset); - - Bitmap resizedOriginalBitmap = mResizedOriginalBitmap; - if (updateOriginalAllocation(preset) || buffer.getProducer() == null) { - resizedOriginalBitmap = mResizedOriginalBitmap; - buffer.setProducer(resizedOriginalBitmap); - mEnvironment.cache(buffer.getProducer()); - } - - Bitmap bitmap = buffer.getProducer().getBitmap(); - long time2 = System.currentTimeMillis(); - - if (bitmap == null || (bitmap.getWidth() != resizedOriginalBitmap.getWidth()) - || (bitmap.getHeight() != resizedOriginalBitmap.getHeight())) { - mEnvironment.cache(buffer.getProducer()); - buffer.setProducer(resizedOriginalBitmap); - bitmap = buffer.getProducer().getBitmap(); - } - mOriginalAllocation.copyTo(bitmap); - - Bitmap tmpbitmap = preset.apply(bitmap, mEnvironment); - if (tmpbitmap != bitmap) { - mEnvironment.cache(buffer.getProducer()); - buffer.setProducer(tmpbitmap); - } - - mFiltersManager.freeFilterResources(preset); - - time = System.currentTimeMillis() - time; - time2 = System.currentTimeMillis() - time2; - if (DEBUG) { - Log.v(LOGTAG, "Applying type " + type + " filters to bitmap " - + bitmap + " (" + bitmap.getWidth() + " x " + bitmap.getHeight() - + ") took " + time + " ms, " + time2 + " ms for the filter, on thread " + thread); - } - } - } - public boolean needsRepaint() { SharedBuffer buffer = MasterImage.getImage().getPreviewBuffer(); return buffer.checkRepaintNeeded(); diff --git a/src/com/android/gallery3d/filtershow/pipeline/FilterEnvironment.java b/src/com/android/gallery3d/filtershow/pipeline/FilterEnvironment.java index 72c02f32f..ebf83b720 100644 --- a/src/com/android/gallery3d/filtershow/pipeline/FilterEnvironment.java +++ b/src/com/android/gallery3d/filtershow/pipeline/FilterEnvironment.java @@ -67,12 +67,12 @@ public class FilterEnvironment { mBitmapCache.cache(bitmap); } - public Bitmap getBitmap(int w, int h) { - return mBitmapCache.getBitmap(w, h); + public Bitmap getBitmap(int w, int h, int type) { + return mBitmapCache.getBitmap(w, h, type); } - public Bitmap getBitmapCopy(Bitmap source) { - return mBitmapCache.getBitmapCopy(source); + public Bitmap getBitmapCopy(Bitmap source, int type) { + return mBitmapCache.getBitmapCopy(source, type); } public void setImagePreset(ImagePreset imagePreset) { @@ -168,4 +168,7 @@ public class FilterEnvironment { generalParameters.put(id, value); } + public BitmapCache getBimapCache() { + return mBitmapCache; + } } diff --git a/src/com/android/gallery3d/filtershow/pipeline/ImagePreset.java b/src/com/android/gallery3d/filtershow/pipeline/ImagePreset.java index 3f71547dd..4322ed700 100644 --- a/src/com/android/gallery3d/filtershow/pipeline/ImagePreset.java +++ b/src/com/android/gallery3d/filtershow/pipeline/ImagePreset.java @@ -41,7 +41,6 @@ import com.android.gallery3d.filtershow.imageshow.GeometryMathUtils; import com.android.gallery3d.filtershow.imageshow.MasterImage; import com.android.gallery3d.filtershow.state.State; import com.android.gallery3d.filtershow.state.StateAdapter; -import com.android.gallery3d.util.UsageStatistics; import java.io.IOException; import java.io.StringReader; @@ -53,6 +52,7 @@ import java.util.Vector; public class ImagePreset { private static final String LOGTAG = "ImagePreset"; + public static final String JASON_SAVED = "Saved"; private Vector<FilterRepresentation> mFilters = new Vector<FilterRepresentation>(); @@ -181,6 +181,16 @@ public class ImagePreset { return false; } + public boolean contains(byte type) { + for (FilterRepresentation representation : mFilters) { + if (representation.getFilterType() == type + && !representation.isNil()) { + return true; + } + } + return false; + } + public boolean isPanoramaSafe() { for (FilterRepresentation representation : mFilters) { if (representation.getFilterType() == FilterRepresentation.TYPE_GEOMETRY @@ -258,8 +268,20 @@ public class ImagePreset { for (int i = 0; i < preset.mFilters.size(); i++) { FilterRepresentation a = preset.mFilters.elementAt(i); FilterRepresentation b = mFilters.elementAt(i); - - if (!a.equals(b)) { + boolean isGeometry = false; + if (a instanceof FilterRotateRepresentation + || a instanceof FilterMirrorRepresentation + || a instanceof FilterCropRepresentation + || a instanceof FilterStraightenRepresentation) { + isGeometry = true; + } + boolean evaluate = true; + if (!isGeometry && mDoApplyGeometry && !mDoApplyFilters) { + evaluate = false; + } else if (isGeometry && !mDoApplyGeometry && mDoApplyFilters) { + evaluate = false; + } + if (evaluate && !a.equals(b)) { return false; } } @@ -325,12 +347,18 @@ public class ImagePreset { public void addFilter(FilterRepresentation representation) { if (representation instanceof FilterUserPresetRepresentation) { ImagePreset preset = ((FilterUserPresetRepresentation) representation).getImagePreset(); - // user preset replace everything but geometry - mFilters.clear(); - for (int i = 0; i < preset.nbFilters(); i++) { - addFilter(preset.getFilterRepresentation(i)); + if (preset.nbFilters() == 1 + && preset.contains(FilterRepresentation.TYPE_FX)) { + FilterRepresentation rep = preset.getFilterRepresentationForType( + FilterRepresentation.TYPE_FX); + addFilter(rep); + } else { + // user preset replaces everything + mFilters.clear(); + for (int i = 0; i < preset.nbFilters(); i++) { + addFilter(preset.getFilterRepresentation(i)); + } } - mFilters.add(representation); } else if (representation.getFilterType() == FilterRepresentation.TYPE_GEOMETRY) { // Add geometry filter, removing duplicates and do-nothing operations. for (int i = 0; i < mFilters.size(); i++) { @@ -354,56 +382,38 @@ public class ImagePreset { mFilters.add(representation); } } else if (representation.getFilterType() == FilterRepresentation.TYPE_FX) { - boolean found = false; + boolean replaced = false; for (int i = 0; i < mFilters.size(); i++) { FilterRepresentation current = mFilters.elementAt(i); - int type = current.getFilterType(); - if (found) { - if (type != FilterRepresentation.TYPE_VIGNETTE) { - mFilters.remove(i); - continue; - } - } - if (type == FilterRepresentation.TYPE_FX) { - if (current instanceof FilterUserPresetRepresentation) { - ImagePreset preset = ((FilterUserPresetRepresentation) current) - .getImagePreset(); - // If we had an existing user preset, let's remove all the presets that - // were added by it - for (int j = 0; j < preset.nbFilters(); j++) { - FilterRepresentation rep = preset.getFilterRepresentation(j); - int pos = getPositionForRepresentation(rep); - if (pos != -1) { - mFilters.remove(pos); - } - } - int pos = getPositionForRepresentation(current); - if (pos != -1) { - mFilters.remove(pos); - } else { - pos = 0; - } - if (!isNoneFxFilter(representation)) { - mFilters.add(pos, representation); - } - - } else { - mFilters.remove(i); - if (!isNoneFxFilter(representation)) { - mFilters.add(i, representation); - } + if (current.getFilterType() == FilterRepresentation.TYPE_FX) { + mFilters.remove(i); + replaced = true; + if (!isNoneFxFilter(representation)) { + mFilters.add(i, representation); } - found = true; + break; } } - if (!found) { - if (!isNoneFxFilter(representation)) { - mFilters.add(representation); - } + if (!replaced) { + mFilters.add(0, representation); } } else { mFilters.add(representation); } + // Enforces Filter type ordering for borders + FilterRepresentation border = null; + for (int i = 0; i < mFilters.size();) { + FilterRepresentation rep = mFilters.elementAt(i); + if (rep.getFilterType() == FilterRepresentation.TYPE_BORDER) { + border = rep; + mFilters.remove(i); + continue; + } + i++; + } + if (border != null) { + mFilters.add(border); + } } private boolean isNoneBorderFilter(FilterRepresentation representation) { @@ -461,7 +471,12 @@ public class ImagePreset { // Apply any transform -- 90 rotate, flip, straighten, crop // Returns a new bitmap. if (mDoApplyGeometry) { - bitmap = GeometryMathUtils.applyGeometryRepresentations(getGeometryFilters(), bitmap); + Bitmap bmp = GeometryMathUtils.applyGeometryRepresentations( + getGeometryFilters(), bitmap); + if (bmp != bitmap) { + environment.cache(bitmap); + } + return bmp; } return bitmap; } @@ -473,8 +488,6 @@ public class ImagePreset { if (border != null && mDoApplyGeometry) { bitmap = environment.applyRepresentation(border, bitmap); if (environment.getQuality() == FilterEnvironment.QUALITY_FINAL) { - UsageStatistics.onEvent(UsageStatistics.COMPONENT_EDITOR, - "SaveBorder", border.getSerializationName(), 1); } } return bitmap; @@ -492,10 +505,6 @@ public class ImagePreset { if (to == -1) { to = mFilters.size(); } - if (environment.getQuality() == FilterEnvironment.QUALITY_FINAL) { - UsageStatistics.onEvent(UsageStatistics.COMPONENT_EDITOR, - "SaveFilters", "Total", to - from + 1); - } for (int i = from; i < to; i++) { FilterRepresentation representation = mFilters.elementAt(i); if (representation.getFilterType() == FilterRepresentation.TYPE_GEOMETRY) { @@ -513,10 +522,6 @@ public class ImagePreset { if (tmp != bitmap) { environment.cache(tmp); } - if (environment.getQuality() == FilterEnvironment.QUALITY_FINAL) { - UsageStatistics.onEvent(UsageStatistics.COMPONENT_EDITOR, - "SaveFilter", representation.getSerializationName(), 1); - } if (environment.needsStop()) { return bitmap; } @@ -676,6 +681,7 @@ public class ImagePreset { } reader.close(); } catch (Exception e) { + Log.e(LOGTAG, "\""+filterString+"\""); Log.e(LOGTAG, "parsing the filter parameters:", e); return false; } diff --git a/src/com/android/gallery3d/filtershow/pipeline/ImageSavingTask.java b/src/com/android/gallery3d/filtershow/pipeline/ImageSavingTask.java index 5c416bccc..801aee46b 100644 --- a/src/com/android/gallery3d/filtershow/pipeline/ImageSavingTask.java +++ b/src/com/android/gallery3d/filtershow/pipeline/ImageSavingTask.java @@ -38,6 +38,7 @@ public class ImageSavingTask extends ProcessingTask { int quality; float sizeFactor; Bitmap previewImage; + boolean exit; } static class UpdateBitmap implements Update { @@ -49,8 +50,14 @@ public class ImageSavingTask extends ProcessingTask { int current; } + static class UpdatePreviewSaved implements Update { + Uri uri; + boolean exit; + } + static class URIResult implements Result { Uri uri; + boolean exit; } public ImageSavingTask(ProcessingService service) { @@ -60,7 +67,7 @@ public class ImageSavingTask extends ProcessingTask { public void saveImage(Uri sourceUri, Uri selectedUri, File destinationFile, ImagePreset preset, Bitmap previewImage, boolean flatten, - int quality, float sizeFactor) { + int quality, float sizeFactor, boolean exit) { SaveRequest request = new SaveRequest(); request.sourceUri = sourceUri; request.selectedUri = selectedUri; @@ -70,6 +77,7 @@ public class ImageSavingTask extends ProcessingTask { request.quality = quality; request.sizeFactor = sizeFactor; request.previewImage = previewImage; + request.exit = exit; postRequest(request); } @@ -81,15 +89,24 @@ public class ImageSavingTask extends ProcessingTask { Bitmap previewImage = request.previewImage; ImagePreset preset = request.preset; boolean flatten = request.flatten; + final boolean exit = request.exit; // We create a small bitmap showing the result that we can // give to the notification UpdateBitmap updateBitmap = new UpdateBitmap(); - updateBitmap.bitmap = createNotificationBitmap(sourceUri, preset); + updateBitmap.bitmap = createNotificationBitmap(previewImage, sourceUri, preset); postUpdate(updateBitmap); SaveImage saveImage = new SaveImage(mProcessingService, sourceUri, selectedUri, destinationFile, previewImage, new SaveImage.Callback() { @Override + public void onPreviewSaved(Uri uri){ + UpdatePreviewSaved previewSaved = new UpdatePreviewSaved(); + previewSaved.uri = uri; + previewSaved.exit = exit; + postUpdate(previewSaved); + } + + @Override public void onProgress(int max, int current) { UpdateProgress updateProgress = new UpdateProgress(); updateProgress.max = max; @@ -97,21 +114,27 @@ public class ImageSavingTask extends ProcessingTask { postUpdate(updateProgress); } }); - Uri uri = saveImage.processAndSaveImage(preset, !flatten, - request.quality, request.sizeFactor); + Uri uri = saveImage.processAndSaveImage(preset, flatten, + request.quality, request.sizeFactor, request.exit); URIResult result = new URIResult(); result.uri = uri; + result.exit = request.exit; return result; } @Override public void onResult(Result message) { URIResult result = (URIResult) message; - mProcessingService.completeSaveImage(result.uri); + mProcessingService.completeSaveImage(result.uri, result.exit); } @Override public void onUpdate(Update message) { + if (message instanceof UpdatePreviewSaved){ + Uri uri = ((UpdatePreviewSaved) message).uri; + boolean exit = ((UpdatePreviewSaved) message).exit; + mProcessingService.completePreviewSaveImage(uri, exit); + } if (message instanceof UpdateBitmap) { Bitmap bitmap = ((UpdateBitmap) message).bitmap; mProcessingService.updateNotificationWithBitmap(bitmap); @@ -122,9 +145,13 @@ public class ImageSavingTask extends ProcessingTask { } } - private Bitmap createNotificationBitmap(Uri sourceUri, ImagePreset preset) { + private Bitmap createNotificationBitmap(Bitmap preview, Uri sourceUri, ImagePreset preset) { int notificationBitmapSize = Resources.getSystem().getDimensionPixelSize( android.R.dimen.notification_large_icon_width); + if (preview != null) { + return Bitmap.createScaledBitmap(preview, + notificationBitmapSize, notificationBitmapSize, true); + } Bitmap bitmap = ImageLoader.loadConstrainedBitmap(sourceUri, getContext(), notificationBitmapSize, null, true); CachingPipeline pipeline = new CachingPipeline(FiltersManager.getManager(), "Thumb"); diff --git a/src/com/android/gallery3d/filtershow/pipeline/ProcessingService.java b/src/com/android/gallery3d/filtershow/pipeline/ProcessingService.java index 7d3767ae4..b5b636ec2 100644 --- a/src/com/android/gallery3d/filtershow/pipeline/ProcessingService.java +++ b/src/com/android/gallery3d/filtershow/pipeline/ProcessingService.java @@ -52,6 +52,7 @@ public class ProcessingService extends Service { private static final String SAVING = "saving"; private static final String FLATTEN = "flatten"; private static final String SIZE_FACTOR = "sizeFactor"; + private static final String EXIT = "exit"; private ProcessingTaskController mProcessingTaskController; private ImageSavingTask mImageSavingTask; @@ -140,7 +141,8 @@ public class ProcessingService extends Service { } public static Intent getSaveIntent(Context context, ImagePreset preset, File destination, - Uri selectedImageUri, Uri sourceImageUri, boolean doFlatten, int quality, float sizeFactor) { + Uri selectedImageUri, Uri sourceImageUri, boolean doFlatten, int quality, + float sizeFactor, boolean needsExit) { Intent processIntent = new Intent(context, ProcessingService.class); processIntent.putExtra(ProcessingService.SOURCE_URI, sourceImageUri.toString()); @@ -152,8 +154,9 @@ public class ProcessingService extends Service { processIntent.putExtra(ProcessingService.DESTINATION_FILE, destination.toString()); } processIntent.putExtra(ProcessingService.PRESET, - preset.getJsonString(context.getString(R.string.saved))); + preset.getJsonString(ImagePreset.JASON_SAVED)); processIntent.putExtra(ProcessingService.SAVING, true); + processIntent.putExtra(ProcessingService.EXIT, needsExit); if (doFlatten) { processIntent.putExtra(ProcessingService.FLATTEN, true); } @@ -196,6 +199,7 @@ public class ProcessingService extends Service { int quality = intent.getIntExtra(QUALITY, 100); float sizeFactor = intent.getFloatExtra(SIZE_FACTOR, 1); boolean flatten = intent.getBooleanExtra(FLATTEN, false); + boolean exit = intent.getBooleanExtra(EXIT, false); Uri sourceUri = Uri.parse(source); Uri selectedUri = null; if (selected != null) { @@ -211,7 +215,7 @@ public class ProcessingService extends Service { mSaving = true; handleSaveRequest(sourceUri, selectedUri, destinationFile, preset, MasterImage.getImage().getHighresImage(), - flatten, quality, sizeFactor); + flatten, quality, sizeFactor, exit); } return START_REDELIVER_INTENT; } @@ -230,10 +234,9 @@ public class ProcessingService extends Service { public void handleSaveRequest(Uri sourceUri, Uri selectedUri, File destinationFile, ImagePreset preset, Bitmap previewImage, - boolean flatten, int quality, float sizeFactor) { + boolean flatten, int quality, float sizeFactor, boolean exit) { mNotifyMgr = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); - - mNotificationId++; + mNotifyMgr.cancelAll(); mBuilder = new Notification.Builder(this) @@ -248,7 +251,7 @@ public class ProcessingService extends Service { // Process the image mImageSavingTask.saveImage(sourceUri, selectedUri, destinationFile, - preset, previewImage, flatten, quality, sizeFactor); + preset, previewImage, flatten, quality, sizeFactor, exit); } public void updateNotificationWithBitmap(Bitmap bitmap) { @@ -261,13 +264,25 @@ public class ProcessingService extends Service { mNotifyMgr.notify(mNotificationId, mBuilder.build()); } - public void completeSaveImage(Uri result) { + public void completePreviewSaveImage(Uri result, boolean exit) { + if (exit && !mNeedsAlive && !mFiltershowActivity.isSimpleEditAction()) { + mFiltershowActivity.completeSaveImage(result); + } + } + + public void completeSaveImage(Uri result, boolean exit) { if (SHOW_IMAGE) { // TODO: we should update the existing image in Gallery instead Intent viewImage = new Intent(Intent.ACTION_VIEW, result); viewImage.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(viewImage); } + mNotifyMgr.cancel(mNotificationId); + if (!exit) { + stopForeground(true); + stopSelf(); + return; + } stopForeground(true); stopSelf(); if (mNeedsAlive) { diff --git a/src/com/android/gallery3d/filtershow/pipeline/RenderingRequest.java b/src/com/android/gallery3d/filtershow/pipeline/RenderingRequest.java index 463b38d95..4cb9e5ad5 100644 --- a/src/com/android/gallery3d/filtershow/pipeline/RenderingRequest.java +++ b/src/com/android/gallery3d/filtershow/pipeline/RenderingRequest.java @@ -21,6 +21,7 @@ import android.graphics.Bitmap; import android.graphics.Rect; import com.android.gallery3d.app.Log; import com.android.gallery3d.filtershow.FilterShowActivity; +import com.android.gallery3d.filtershow.cache.BitmapCache; import com.android.gallery3d.filtershow.filters.FiltersManager; import com.android.gallery3d.filtershow.imageshow.MasterImage; @@ -34,6 +35,7 @@ public class RenderingRequest { private float mScaleFactor = 1.0f; private Rect mBounds = null; private Rect mDestination = null; + private Rect mIconBounds = null; private int mType = FULL_RENDERING; public static final int FULL_RENDERING = 0; public static final int FILTERS_RENDERING = 1; @@ -70,7 +72,7 @@ public class RenderingRequest { } else if (type != PARTIAL_RENDERING && type != HIGHRES_RENDERING && type != GEOMETRY_RENDERING && type != FILTERS_RENDERING) { bitmap = MasterImage.getImage().getBitmapCache().getBitmap( - source.getWidth(), source.getHeight()); + source.getWidth(), source.getHeight(), BitmapCache.RENDERING_REQUEST); } request.setBitmap(bitmap); @@ -90,6 +92,25 @@ public class RenderingRequest { request.post(context); } + public static void postIconRequest(Context context, int w, int h, + ImagePreset preset, + RenderingRequestCaller caller) { + if (preset == null || caller == null) { + Log.v(LOGTAG, "something null, preset: " + + preset + " or caller: " + caller); + return; + } + RenderingRequest request = new RenderingRequest(); + ImagePreset passedPreset = new ImagePreset(preset); + request.setOriginalImagePreset(preset); + request.setScaleFactor(MasterImage.getImage().getScaleFactor()); + request.setImagePreset(passedPreset); + request.setType(RenderingRequest.ICON_RENDERING); + request.setCaller(caller); + request.setIconBounds(new Rect(0, 0, w, h)); + request.post(context); + } + public void post(Context context) { if (context instanceof FilterShowActivity) { FilterShowActivity activity = (FilterShowActivity) context; @@ -166,6 +187,14 @@ public class RenderingRequest { mDestination = destination; } + public void setIconBounds(Rect bounds) { + mIconBounds = bounds; + } + + public Rect getIconBounds() { + return mIconBounds; + } + public ImagePreset getOriginalImagePreset() { return mOriginalImagePreset; } diff --git a/src/com/android/gallery3d/filtershow/pipeline/SharedBuffer.java b/src/com/android/gallery3d/filtershow/pipeline/SharedBuffer.java index 871e4cd6c..f243aa66e 100644 --- a/src/com/android/gallery3d/filtershow/pipeline/SharedBuffer.java +++ b/src/com/android/gallery3d/filtershow/pipeline/SharedBuffer.java @@ -29,15 +29,16 @@ public class SharedBuffer { private volatile boolean mNeedsSwap = false; private volatile boolean mNeedsRepaint = true; - public void setProducer(Bitmap producer) { - synchronized (this) { - if (mProducer != null) { - mProducer.remove(); - } + public synchronized void setProducer(Bitmap producer) { + if (mProducer != null + && !mProducer.isSameSize(producer)) { + mProducer.remove(); + mProducer = null; } - Buffer buffer = new Buffer(producer); - synchronized (this) { - mProducer = buffer; + if (mProducer == null) { + mProducer = new Buffer(producer); + } else { + mProducer.useBitmap(producer); } } diff --git a/src/com/android/gallery3d/filtershow/pipeline/SharedPreset.java b/src/com/android/gallery3d/filtershow/pipeline/SharedPreset.java index 3f850fed2..334361263 100644 --- a/src/com/android/gallery3d/filtershow/pipeline/SharedPreset.java +++ b/src/com/android/gallery3d/filtershow/pipeline/SharedPreset.java @@ -21,6 +21,7 @@ public class SharedPreset { private volatile ImagePreset mProducerPreset = null; private volatile ImagePreset mConsumerPreset = null; private volatile ImagePreset mIntermediatePreset = null; + private volatile boolean mHasNewContent = false; public synchronized void enqueuePreset(ImagePreset preset) { if (mProducerPreset == null || (!mProducerPreset.same(preset))) { @@ -31,12 +32,17 @@ public class SharedPreset { ImagePreset temp = mIntermediatePreset; mIntermediatePreset = mProducerPreset; mProducerPreset = temp; + mHasNewContent = true; } public synchronized ImagePreset dequeuePreset() { + if (!mHasNewContent) { + return mConsumerPreset; + } ImagePreset temp = mConsumerPreset; mConsumerPreset = mIntermediatePreset; mIntermediatePreset = temp; + mHasNewContent = false; return mConsumerPreset; } } diff --git a/src/com/android/gallery3d/filtershow/pipeline/UpdatePreviewTask.java b/src/com/android/gallery3d/filtershow/pipeline/UpdatePreviewTask.java index 406cc9bf5..61ee8eb71 100644 --- a/src/com/android/gallery3d/filtershow/pipeline/UpdatePreviewTask.java +++ b/src/com/android/gallery3d/filtershow/pipeline/UpdatePreviewTask.java @@ -17,10 +17,12 @@ package com.android.gallery3d.filtershow.pipeline; import android.graphics.Bitmap; + import com.android.gallery3d.filtershow.filters.FiltersManager; import com.android.gallery3d.filtershow.imageshow.MasterImage; public class UpdatePreviewTask extends ProcessingTask { + private static final String LOGTAG = "UpdatePreviewTask"; private CachingPipeline mPreviewPipeline = null; private boolean mHasUnhandledPreviewRequest = false; private boolean mPipelineIsOn = false; diff --git a/src/com/android/gallery3d/filtershow/state/StatePanel.java b/src/com/android/gallery3d/filtershow/state/StatePanel.java index ff405cd98..95c2df991 100644 --- a/src/com/android/gallery3d/filtershow/state/StatePanel.java +++ b/src/com/android/gallery3d/filtershow/state/StatePanel.java @@ -27,6 +27,7 @@ import android.widget.LinearLayout; import com.android.gallery3d.R; import com.android.gallery3d.filtershow.category.MainPanel; import com.android.gallery3d.filtershow.imageshow.MasterImage; +import com.android.gallery3d.util.FilterShowHelper; public class StatePanel extends Fragment { private static final String LOGTAG = "StatePanel"; @@ -49,9 +50,18 @@ public class StatePanel extends Fragment { track = (StatePanelTrack) panel; track.setAdapter(MasterImage.getImage().getState()); mToggleVersionsPanel = (ImageButton) mMainView.findViewById(R.id.toggleVersionsPanel); - if (mMainPanel != null) { - mMainPanel.setToggleVersionsPanelButton(mToggleVersionsPanel); - } else if (mToggleVersionsPanel != null) { + if (FilterShowHelper.shouldUseVersions()) { + if (mToggleVersionsPanel.getVisibility() == View.GONE + || mToggleVersionsPanel.getVisibility() == View.INVISIBLE) { + mToggleVersionsPanel.setVisibility(View.VISIBLE); + mToggleVersionsPanel.setImageBitmap(null); + } + if (mMainPanel != null) { + mMainPanel.setToggleVersionsPanelButton(mToggleVersionsPanel); + } else if (mToggleVersionsPanel != null) { + mToggleVersionsPanel.setVisibility(View.GONE); + } + } else { mToggleVersionsPanel.setVisibility(View.GONE); } return mMainView; diff --git a/src/com/android/gallery3d/filtershow/state/StateView.java b/src/com/android/gallery3d/filtershow/state/StateView.java index 73d57846a..a43cd47ba 100644 --- a/src/com/android/gallery3d/filtershow/state/StateView.java +++ b/src/com/android/gallery3d/filtershow/state/StateView.java @@ -19,17 +19,17 @@ package com.android.gallery3d.filtershow.state; import android.content.Context; import android.content.res.Resources; import android.graphics.*; -import android.util.AttributeSet; -import android.util.Log; import android.view.MotionEvent; import android.view.View; -import android.view.ViewParent; import android.widget.LinearLayout; import com.android.gallery3d.R; import com.android.gallery3d.filtershow.FilterShowActivity; +import com.android.gallery3d.filtershow.category.SwipableView; +import com.android.gallery3d.filtershow.filters.FilterRepresentation; import com.android.gallery3d.filtershow.imageshow.MasterImage; +import com.android.gallery3d.filtershow.pipeline.ImagePreset; -public class StateView extends View { +public class StateView extends View implements SwipableView { private static final String LOGTAG = "StateView"; private Path mPath = new Path(); @@ -51,6 +51,10 @@ public class StateView extends View { private static int sMargin = 16; private static int sArrowHeight = 16; private static int sArrowWidth = 8; + private float mStartTouchX = 0; + private float mStartTouchY = 0; + private float mDeleteSlope = 20; + private int mOrientation = LinearLayout.VERTICAL; private int mDirection = DOWN; private boolean mDuplicateButton; @@ -104,24 +108,6 @@ public class StateView extends View { invalidate(); } - @Override - public boolean onTouchEvent(MotionEvent event) { - if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { - ViewParent parent = getParent(); - if (parent instanceof PanelTrack) { - ((PanelTrack) getParent()).onTouch(event, this); - } - if (mType == BEGIN) { - MasterImage.getImage().setShowsOriginal(true); - } - } - if (event.getActionMasked() == MotionEvent.ACTION_UP - || event.getActionMasked() == MotionEvent.ACTION_CANCEL) { - MasterImage.getImage().setShowsOriginal(false); - } - return true; - } - public void drawText(Canvas canvas) { if (mText == null) { return; @@ -180,22 +166,42 @@ public class StateView extends View { } private void drawHorizontalPath(float w, float h, float r, float d) { - mPath.moveTo(0, 0); - if (mType == END) { - mPath.lineTo(w, 0); + if (this.getLayoutDirection() == LAYOUT_DIRECTION_RTL) { + mPath.moveTo(w, 0); + if (mType == END) { + mPath.lineTo(0, 0); + mPath.lineTo(0, h); + } else { + mPath.lineTo(d, 0); + mPath.lineTo(d, r); + mPath.lineTo(0, r + d); + mPath.lineTo(d, r + d + r); + mPath.lineTo(d, h); + } mPath.lineTo(w, h); + if (mType != BEGIN) { + mPath.lineTo(w, r + d + r); + mPath.lineTo(w - d, r + d); + mPath.lineTo(w, r); + } } else { - mPath.lineTo(w - d, 0); - mPath.lineTo(w - d, r); - mPath.lineTo(w, r + d); - mPath.lineTo(w - d, r + d + r); - mPath.lineTo(w - d, h); - } - mPath.lineTo(0, h); - if (mType != BEGIN) { - mPath.lineTo(0, r + d + r); - mPath.lineTo(d, r + d); - mPath.lineTo(0, r); + mPath.moveTo(0, 0); + if (mType == END) { + mPath.lineTo(w, 0); + mPath.lineTo(w, h); + } else { + mPath.lineTo(w - d, 0); + mPath.lineTo(w - d, r); + mPath.lineTo(w, r + d); + mPath.lineTo(w - d, r + d + r); + mPath.lineTo(w - d, h); + } + mPath.lineTo(0, h); + if (mType != BEGIN) { + mPath.lineTo(0, r + d + r); + mPath.lineTo(d, r + d); + mPath.lineTo(0, r); + } } mPath.close(); } @@ -288,4 +294,54 @@ public class StateView extends View { public boolean isDraggable() { return mState.isDraggable(); } + + @Override + public void delete() { + FilterShowActivity activity = (FilterShowActivity) getContext(); + FilterRepresentation representation = getState().getFilterRepresentation(); + activity.removeFilterRepresentation(representation); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + boolean ret = super.onTouchEvent(event); + FilterShowActivity activity = (FilterShowActivity) getContext(); + + if (event.getActionMasked() == MotionEvent.ACTION_UP) { + activity.startTouchAnimation(this, event.getX(), event.getY()); + } + if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { + mStartTouchY = event.getY(); + mStartTouchX = event.getX(); + if (mType == BEGIN) { + MasterImage.getImage().setShowsOriginal(true); + } + } + if (event.getActionMasked() == MotionEvent.ACTION_UP + || event.getActionMasked() == MotionEvent.ACTION_CANCEL) { + setTranslationX(0); + setTranslationY(0); + MasterImage.getImage().setShowsOriginal(false); + if (mType != BEGIN && event.getActionMasked() == MotionEvent.ACTION_UP) { + setSelected(true); + FilterRepresentation representation = getState().getFilterRepresentation(); + MasterImage image = MasterImage.getImage(); + ImagePreset preset = image != null ? image.getCurrentPreset() : null; + if (getTranslationY() == 0 + && image != null && preset != null + && representation != image.getCurrentFilterRepresentation() + && preset.getRepresentation(representation) != null) { + activity.showRepresentation(representation); + setSelected(false); + } + } + } + if (mType != BEGIN && event.getActionMasked() == MotionEvent.ACTION_MOVE) { + float delta = event.getY() - mStartTouchY; + if (Math.abs(delta) > mDeleteSlope) { + activity.setHandlesSwipeForView(this, mStartTouchX, mStartTouchY); + } + } + return true; + } } diff --git a/src/com/android/gallery3d/filtershow/tools/SaveImage.java b/src/com/android/gallery3d/filtershow/tools/SaveImage.java index 51dddfd6d..354081ed2 100644 --- a/src/com/android/gallery3d/filtershow/tools/SaveImage.java +++ b/src/com/android/gallery3d/filtershow/tools/SaveImage.java @@ -35,12 +35,12 @@ import com.android.gallery3d.common.Utils; import com.android.gallery3d.exif.ExifInterface; import com.android.gallery3d.filtershow.FilterShowActivity; import com.android.gallery3d.filtershow.cache.ImageLoader; +import com.android.gallery3d.filtershow.filters.FilterRepresentation; import com.android.gallery3d.filtershow.filters.FiltersManager; import com.android.gallery3d.filtershow.imageshow.MasterImage; import com.android.gallery3d.filtershow.pipeline.CachingPipeline; import com.android.gallery3d.filtershow.pipeline.ImagePreset; import com.android.gallery3d.filtershow.pipeline.ProcessingService; -import com.android.gallery3d.util.UsageStatistics; import com.android.gallery3d.util.XmpUtilHelper; import java.io.File; @@ -63,6 +63,7 @@ public class SaveImage { * Callback for updates */ public interface Callback { + void onPreviewSaved(Uri uri); void onProgress(int max, int current); } @@ -314,10 +315,23 @@ public class SaveImage { } } - public Uri processAndSaveImage(ImagePreset preset, boolean doAuxBackup, - int quality, float sizeFactor) { + private void updateExifData(ExifInterface exif, long time) { + // Set tags + exif.addDateTimeStampTag(ExifInterface.TAG_DATE_TIME, time, + TimeZone.getDefault()); + exif.setTag(exif.buildTag(ExifInterface.TAG_ORIENTATION, + ExifInterface.Orientation.TOP_LEFT)); + // Remove old thumbnail + exif.removeCompressedThumbnail(); + } + + public Uri processAndSaveImage(ImagePreset preset, boolean flatten, + int quality, float sizeFactor, boolean exit) { - Uri uri = resetToOriginalImageIfNeeded(preset, doAuxBackup); + Uri uri = null; + if (exit) { + uri = resetToOriginalImageIfNeeded(preset, !flatten); + } if (uri != null) { return null; } @@ -332,33 +346,45 @@ public class SaveImage { // newSourceUri is then pointing to the new location. // If no file is moved, newSourceUri will be the same as mSourceUri. Uri newSourceUri = mSourceUri; - if (doAuxBackup) { + if (!flatten) { newSourceUri = moveSrcToAuxIfNeeded(mSourceUri, mDestinationFile); } Uri savedUri = mSelectedImageUri; if (mPreviewImage != null) { - Object xmp = getPanoramaXMPData(newSourceUri, preset); - ExifInterface exif = getExifData(newSourceUri); - // Set tags - long time = System.currentTimeMillis(); - exif.addDateTimeStampTag(ExifInterface.TAG_DATE_TIME, time, - TimeZone.getDefault()); - exif.setTag(exif.buildTag(ExifInterface.TAG_ORIENTATION, - ExifInterface.Orientation.TOP_LEFT)); - // Remove old thumbnail - exif.removeCompressedThumbnail(); - // If we succeed in writing the bitmap as a jpeg, return a uri. - if (putExifData(mDestinationFile, exif, mPreviewImage, quality)) { - putPanoramaXMPData(mDestinationFile, xmp); - // mDestinationFile will save the newSourceUri info in the XMP. - XmpPresets.writeFilterXMP(mContext, newSourceUri, - mDestinationFile, preset); - - // After this call, mSelectedImageUri will be actually - // pointing at the new file mDestinationFile. - savedUri = SaveImage.linkNewFileToUri(mContext, mSelectedImageUri, - mDestinationFile, time, doAuxBackup); + if (flatten) { + Object xmp = getPanoramaXMPData(newSourceUri, preset); + ExifInterface exif = getExifData(newSourceUri); + long time = System.currentTimeMillis(); + updateExifData(exif, time); + if (putExifData(mDestinationFile, exif, mPreviewImage, quality)) { + putPanoramaXMPData(mDestinationFile, xmp); + ContentValues values = getContentValues(mContext, mSelectedImageUri, mDestinationFile, time); + Object result = mContext.getContentResolver().insert( + Images.Media.EXTERNAL_CONTENT_URI, values); + + } + } else { + Object xmp = getPanoramaXMPData(newSourceUri, preset); + ExifInterface exif = getExifData(newSourceUri); + long time = System.currentTimeMillis(); + updateExifData(exif, time); + // If we succeed in writing the bitmap as a jpeg, return a uri. + if (putExifData(mDestinationFile, exif, mPreviewImage, quality)) { + putPanoramaXMPData(mDestinationFile, xmp); + // mDestinationFile will save the newSourceUri info in the XMP. + if (!flatten) { + XmpPresets.writeFilterXMP(mContext, newSourceUri, + mDestinationFile, preset); + } + // After this call, mSelectedImageUri will be actually + // pointing at the new file mDestinationFile. + savedUri = SaveImage.linkNewFileToUri(mContext, mSelectedImageUri, + mDestinationFile, time, !flatten); + } + } + if (mCallback != null) { + mCallback.onPreviewSaved(savedUri); } } @@ -387,33 +413,31 @@ public class SaveImage { Object xmp = getPanoramaXMPData(newSourceUri, preset); ExifInterface exif = getExifData(newSourceUri); - - updateProgress(); - // Set tags long time = System.currentTimeMillis(); - exif.addDateTimeStampTag(ExifInterface.TAG_DATE_TIME, time, - TimeZone.getDefault()); - exif.setTag(exif.buildTag(ExifInterface.TAG_ORIENTATION, - ExifInterface.Orientation.TOP_LEFT)); - // Remove old thumbnail - exif.removeCompressedThumbnail(); + updateProgress(); + updateExifData(exif, time); updateProgress(); // If we succeed in writing the bitmap as a jpeg, return a uri. if (putExifData(mDestinationFile, exif, bitmap, quality)) { putPanoramaXMPData(mDestinationFile, xmp); // mDestinationFile will save the newSourceUri info in the XMP. - XmpPresets.writeFilterXMP(mContext, newSourceUri, - mDestinationFile, preset); + if (!flatten) { + XmpPresets.writeFilterXMP(mContext, newSourceUri, + mDestinationFile, preset); + uri = updateFile(mContext, savedUri, mDestinationFile, time); + + } else { - uri = updateFile(mContext, savedUri, mDestinationFile, time); + ContentValues values = getContentValues(mContext, mSelectedImageUri, mDestinationFile, time); + Object result = mContext.getContentResolver().insert( + Images.Media.EXTERNAL_CONTENT_URI, values); + } } updateProgress(); noBitmap = false; - UsageStatistics.onEvent(UsageStatistics.COMPONENT_EDITOR, - "SaveComplete", null); } catch (OutOfMemoryError e) { // Try 5 times before failing for good. if (++num_tries >= 5) { @@ -508,9 +532,12 @@ public class SaveImage { File destination) { Uri selectedImageUri = filterShowActivity.getSelectedImageUri(); Uri sourceImageUri = MasterImage.getImage().getUri(); - + boolean flatten = false; + if (preset.contains(FilterRepresentation.TYPE_TINYPLANET)){ + flatten = true; + } Intent processIntent = ProcessingService.getSaveIntent(filterShowActivity, preset, - destination, selectedImageUri, sourceImageUri, false, 90, 1f); + destination, selectedImageUri, sourceImageUri, flatten, 90, 1f, true); filterShowActivity.startService(processIntent); @@ -520,9 +547,6 @@ public class SaveImage { Toast.makeText(filterShowActivity, toastMessage, Toast.LENGTH_SHORT).show(); - - // terminate for now - filterShowActivity.completeSaveImage(selectedImageUri); } } diff --git a/src/com/android/gallery3d/filtershow/tools/XmpPresets.java b/src/com/android/gallery3d/filtershow/tools/XmpPresets.java index 3995eeb85..7095e742d 100644 --- a/src/com/android/gallery3d/filtershow/tools/XmpPresets.java +++ b/src/com/android/gallery3d/filtershow/tools/XmpPresets.java @@ -39,6 +39,7 @@ public class XmpPresets { public static final String XMP_GOOGLE_FILTER_PREFIX = "AFltr"; public static final String XMP_SRC_FILE_URI = "SourceFileUri"; public static final String XMP_FILTERSTACK = "filterstack"; + private static final String LOGTAG = "XmpPresets"; public static class XMresults { @@ -76,7 +77,7 @@ public class XmpPresets { xmpMeta.setProperty(XMP_GOOGLE_FILTER_NAMESPACE, XMP_SRC_FILE_URI, srcUri.toString()); xmpMeta.setProperty(XMP_GOOGLE_FILTER_NAMESPACE, - XMP_FILTERSTACK, preset.getJsonString(context.getString(R.string.saved))); + XMP_FILTERSTACK, preset.getJsonString(ImagePreset.JASON_SAVED)); } catch (XMPException e) { Log.v(LOGTAG, "Write XMP meta to file failed:" + dstFile.getAbsolutePath()); return; @@ -116,7 +117,7 @@ public class XmpPresets { Uri srcUri = Uri.parse(strSrcUri); ret.originalimage = srcUri; - ret.preset = new ImagePreset(mMasterImage.getPreset()); + ret.preset = new ImagePreset(); ret.presetString = filterString; boolean ok = ret.preset.readJsonFromString(filterString); if (!ok) { diff --git a/src/com/android/gallery3d/filtershow/ui/ExportDialog.java b/src/com/android/gallery3d/filtershow/ui/ExportDialog.java index b0046e1bb..f6a84cee2 100644 --- a/src/com/android/gallery3d/filtershow/ui/ExportDialog.java +++ b/src/com/android/gallery3d/filtershow/ui/ExportDialog.java @@ -157,11 +157,11 @@ public class ExportDialog extends DialogFragment implements View.OnClickListener case R.id.done: FilterShowActivity activity = (FilterShowActivity) getActivity(); Uri sourceUri = MasterImage.getImage().getUri(); - File dest = SaveImage.getNewFile(activity, sourceUri); + File dest = SaveImage.getNewFile(activity, activity.getSelectedImageUri()); float scaleFactor = mExportWidth / (float) mOriginalBounds.width(); Intent processIntent = ProcessingService.getSaveIntent(activity, MasterImage .getImage().getPreset(), dest, activity.getSelectedImageUri(), sourceUri, - true, mSeekBar.getProgress(), scaleFactor); + true, mSeekBar.getProgress(), scaleFactor, false); activity.startService(processIntent); dismiss(); break; @@ -170,6 +170,9 @@ public class ExportDialog extends DialogFragment implements View.OnClickListener public void updateCompressionFactor() { Bitmap bitmap = MasterImage.getImage().getFilteredImage(); + if (bitmap == null) { + return; + } ByteArrayOutputStream out = new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.JPEG, mQuality, out); mCompressedSize = out.size(); diff --git a/src/com/android/gallery3d/gadget/WidgetClickHandler.java b/src/com/android/gallery3d/gadget/WidgetClickHandler.java index 37ee1a651..e66a2a66f 100644 --- a/src/com/android/gallery3d/gadget/WidgetClickHandler.java +++ b/src/com/android/gallery3d/gadget/WidgetClickHandler.java @@ -27,7 +27,7 @@ import android.util.Log; import android.widget.Toast; import com.android.gallery3d.R; -import com.android.gallery3d.app.Gallery; +import com.android.gallery3d.app.GalleryActivity; import com.android.gallery3d.app.PhotoPage; import com.android.gallery3d.common.ApiHelper; @@ -63,7 +63,7 @@ public class WidgetClickHandler extends Activity { } else { Toast.makeText(this, R.string.no_such_item, Toast.LENGTH_LONG).show(); - intent = new Intent(this, Gallery.class); + intent = new Intent(this, GalleryActivity.class); } if (tediousBack) { intent.setFlags( diff --git a/src/com/android/gallery3d/glrenderer/TiledTexture.java b/src/com/android/gallery3d/glrenderer/TiledTexture.java index 6ca1de088..78cb2f2de 100644 --- a/src/com/android/gallery3d/glrenderer/TiledTexture.java +++ b/src/com/android/gallery3d/glrenderer/TiledTexture.java @@ -129,18 +129,25 @@ public class TiledTexture implements Texture { @Override protected Bitmap onGetBitmap() { - int x = BORDER_SIZE - offsetX; - int y = BORDER_SIZE - offsetY; - int r = bitmap.getWidth() + x; - int b = bitmap.getHeight() + y; - sCanvas.drawBitmap(bitmap, x, y, sBitmapPaint); + // make a local copy of the reference to the bitmap, + // since it might be null'd in a different thread. b/8694871 + Bitmap localBitmapRef = bitmap; bitmap = null; - // draw borders if need - if (x > 0) sCanvas.drawLine(x - 1, 0, x - 1, TILE_SIZE, sPaint); - if (y > 0) sCanvas.drawLine(0, y - 1, TILE_SIZE, y - 1, sPaint); - if (r < CONTENT_SIZE) sCanvas.drawLine(r, 0, r, TILE_SIZE, sPaint); - if (b < CONTENT_SIZE) sCanvas.drawLine(0, b, TILE_SIZE, b, sPaint); + if (localBitmapRef != null) { + int x = BORDER_SIZE - offsetX; + int y = BORDER_SIZE - offsetY; + int r = localBitmapRef.getWidth() + x; + int b = localBitmapRef.getHeight() + y; + sCanvas.drawBitmap(localBitmapRef, x, y, sBitmapPaint); + localBitmapRef = null; + + // draw borders if need + if (x > 0) sCanvas.drawLine(x - 1, 0, x - 1, TILE_SIZE, sPaint); + if (y > 0) sCanvas.drawLine(0, y - 1, TILE_SIZE, y - 1, sPaint); + if (r < CONTENT_SIZE) sCanvas.drawLine(r, 0, r, TILE_SIZE, sPaint); + if (b < CONTENT_SIZE) sCanvas.drawLine(0, b, TILE_SIZE, b, sPaint); + } return sUploadBitmap; } diff --git a/src/com/android/gallery3d/ingest/MtpDeviceIndex.java b/src/com/android/gallery3d/ingest/MtpDeviceIndex.java index d30f94a87..fed851e0e 100644 --- a/src/com/android/gallery3d/ingest/MtpDeviceIndex.java +++ b/src/com/android/gallery3d/ingest/MtpDeviceIndex.java @@ -267,6 +267,9 @@ public class MtpDeviceIndex { break; } } + if (mBuckets.length == 0 || mUnifiedLookupIndex.length == 0) { + return -1; + } int mappedPos = mBuckets[bucketNumber].unifiedStartIndex + position - mBuckets[bucketNumber].itemsStartIndex; if (order == SortOrder.Descending) { @@ -283,6 +286,9 @@ public class MtpDeviceIndex { return bucket.itemsStartIndex + position - 1 - bucket.unifiedStartIndex; } else { int zeroIndex = mUnifiedLookupIndex.length - 1 - position; + if (mBuckets.length == 0 || mUnifiedLookupIndex.length == 0) { + return -1; + } DateBucket bucket = mBuckets[mUnifiedLookupIndex[zeroIndex]]; if (bucket.unifiedEndIndex == zeroIndex) zeroIndex--; return mMtpObjects.length - 1 - bucket.itemsStartIndex diff --git a/src/com/android/gallery3d/ui/MenuExecutor.java b/src/com/android/gallery3d/ui/MenuExecutor.java index 8f4854e10..1ace71829 100644 --- a/src/com/android/gallery3d/ui/MenuExecutor.java +++ b/src/com/android/gallery3d/ui/MenuExecutor.java @@ -26,6 +26,7 @@ import android.content.DialogInterface.OnClickListener; import android.content.Intent; import android.os.Handler; import android.os.Message; +import android.support.v4.print.PrintHelper; import android.view.Menu; import android.view.MenuItem; @@ -45,7 +46,6 @@ import com.android.gallery3d.util.ThreadPool.JobContext; import java.util.ArrayList; public class MenuExecutor { - @SuppressWarnings("unused") private static final String TAG = "MenuExecutor"; private static final int MSG_TASK_COMPLETE = 1; @@ -177,6 +177,8 @@ public class MenuExecutor { boolean supportCache = (supported & MediaObject.SUPPORT_CACHE) != 0; boolean supportEdit = (supported & MediaObject.SUPPORT_EDIT) != 0; boolean supportInfo = (supported & MediaObject.SUPPORT_INFO) != 0; + boolean supportPrint = (supported & MediaObject.SUPPORT_PRINT) != 0; + supportPrint &= PrintHelper.systemSupportsPrint(); setMenuItemVisible(menu, R.id.action_delete, supportDelete); setMenuItemVisible(menu, R.id.action_rotate_ccw, supportRotate); @@ -192,6 +194,7 @@ public class MenuExecutor { setMenuItemVisible(menu, R.id.action_edit, supportEdit); // setMenuItemVisible(menu, R.id.action_simple_edit, supportEdit); setMenuItemVisible(menu, R.id.action_details, supportInfo); + setMenuItemVisible(menu, R.id.print, supportPrint); } public static void updateMenuForPanorama(Menu menu, boolean shareAsPanorama360, diff --git a/src/com/android/gallery3d/util/GalleryUtils.java b/src/com/android/gallery3d/util/GalleryUtils.java index 9245e2c5f..9a78fcd27 100644 --- a/src/com/android/gallery3d/util/GalleryUtils.java +++ b/src/com/android/gallery3d/util/GalleryUtils.java @@ -37,7 +37,7 @@ import android.util.Log; import android.view.WindowManager; import com.android.gallery3d.R; -import com.android.gallery3d.app.Gallery; +import com.android.gallery3d.app.GalleryActivity; import com.android.gallery3d.app.PackagesMonitor; import com.android.gallery3d.common.ApiHelper; import com.android.gallery3d.data.DataManager; @@ -239,8 +239,8 @@ public class GalleryUtils { int state = pm.getComponentEnabledSetting(name); sCameraAvailableInitialized = true; sCameraAvailable = - (state == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) - || (state == PackageManager.COMPONENT_ENABLED_STATE_ENABLED); + (state == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) + || (state == PackageManager.COMPONENT_ENABLED_STATE_ENABLED); return sCameraAvailable; } @@ -252,7 +252,7 @@ public class GalleryUtils { } public static void startGalleryActivity(Context context) { - Intent intent = new Intent(context, Gallery.class) + Intent intent = new Intent(context, GalleryActivity.class) .setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(intent); diff --git a/src/com/android/gallery3d/util/PrintJob.java b/src/com/android/gallery3d/util/PrintJob.java deleted file mode 100644 index 83cb96aa4..000000000 --- a/src/com/android/gallery3d/util/PrintJob.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.gallery3d.util; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Matrix; -import android.graphics.RectF; -import android.net.Uri; -import android.os.Bundle; -import android.os.CancellationSignal; -import android.os.ParcelFileDescriptor; -import android.print.PageRange; -import android.print.PrintAttributes; -import android.print.PrintDocumentAdapter; -import android.print.PrintDocumentInfo; -import android.print.PrintManager; -import android.print.pdf.PdfDocument.Page; -import android.print.pdf.PrintedPdfDocument; - -import com.android.gallery3d.filtershow.cache.ImageLoader; - -import java.io.FileOutputStream; -import java.io.IOException; - -public class PrintJob { - private final static int MAX_PRINT_SIZE = 2048; - - public static void printBitmap(final Context context, final String jobName, - final Bitmap bitmap) { - if (bitmap == null) { - return; - } - PrintManager printManager = (PrintManager) context.getSystemService(Context.PRINT_SERVICE); - printManager.print(jobName, - new PrintDocumentAdapter() { - private PrintAttributes mAttributes; - - @Override - public void onLayout(PrintAttributes oldPrintAttributes, - PrintAttributes newPrintAttributes, - CancellationSignal cancellationSignal, - LayoutResultCallback layoutResultCallback, - Bundle bundle) { - - mAttributes = newPrintAttributes; - - PrintDocumentInfo info = new PrintDocumentInfo - .Builder(jobName, newPrintAttributes) - .setContentType(PrintDocumentInfo.CONTENT_TYPE_PHOTO) - .setColorMode(PrintAttributes.COLOR_MODE_COLOR) - .setPageCount(1) - .create(); - - layoutResultCallback.onLayoutFinished(info, false); - } - - @Override - public void onWrite(PageRange[] pageRanges, ParcelFileDescriptor fileDescriptor, - CancellationSignal cancellationSignal, - WriteResultCallback writeResultCallback) { - try { - PrintedPdfDocument pdfDocument = PrintedPdfDocument.open(context, - mAttributes); - Page page = pdfDocument.startPage(1); - - RectF content = new RectF(page.getInfo().getContentSize()); - Matrix matrix = new Matrix(); - - // Handle orientation. - if (mAttributes.getOrientation() - == PrintAttributes.ORIENTATION_LANDSCAPE) { - // Compute and apply scale based on fitting mode. - final float scale; - switch (mAttributes.getFittingMode()) { - case PrintAttributes.FITTING_MODE_SCALE_TO_FILL: { - scale = Math.max(content.width() / bitmap.getHeight(), - content.height() / bitmap.getWidth()); - } break; - - case PrintAttributes.FITTING_MODE_SCALE_TO_FIT: { - scale = Math.min(content.width() / bitmap.getHeight(), - content.height() / bitmap.getWidth()); - } break; - - default: { - scale = 1.0f; - } - } - matrix.postScale(scale, scale); - - // Apply the rotation. - matrix.postRotate(90); - matrix.postTranslate(bitmap.getHeight() * scale, 0); - - // Center the content. - final float translateX = (content.width() - - bitmap.getHeight() * scale) / 2; - final float translateY = (content.height() - - bitmap.getWidth() * scale) / 2; - matrix.postTranslate(translateX, translateY); - } else { - // Compute and apply scale based on fitting mode. - float scale = 1.0f; - switch (mAttributes.getFittingMode()) { - case PrintAttributes.FITTING_MODE_SCALE_TO_FILL: { - scale = Math.max(content.width() / bitmap.getWidth(), - content.height() / bitmap.getHeight()); - } break; - - case PrintAttributes.FITTING_MODE_SCALE_TO_FIT: { - scale = Math.min(content.width() / bitmap.getWidth(), - content.height() / bitmap.getHeight()); - } break; - } - matrix.postScale(scale, scale); - - // Center the content. - final float translateX = (content.width() - - bitmap.getWidth() * scale) / 2; - final float translateY = (content.height() - - bitmap.getHeight() * scale) / 2; - matrix.postTranslate(translateX, translateY); - } - - // Draw the bitmap. - page.getCanvas().drawBitmap(bitmap, matrix, null); - - // Write the document. - pdfDocument.finishPage(page); - pdfDocument.writeTo(new FileOutputStream( - fileDescriptor.getFileDescriptor())); - pdfDocument.close(); - - // Done. - writeResultCallback.onWriteFinished( - new PageRange[] { PageRange.ALL_PAGES }); - } finally { - if (fileDescriptor != null) { - try { - fileDescriptor.close(); - } catch (IOException ioe) { - /* ignore */ - } - } - writeResultCallback.onWriteFailed(null); - } - } - }, new PrintAttributes.Builder().create()); - } - - public static void printBitmapAtUri(Context context, String imagePrint, Uri uri) { - // TODO: load full size images. For now, it's better to constrain ourselves. - Bitmap bitmap = ImageLoader.loadConstrainedBitmap(uri, context, MAX_PRINT_SIZE, null, false); - printBitmap(context, imagePrint, bitmap); - } -} diff --git a/src/com/android/photos/AlbumFragment.java b/src/com/android/photos/AlbumFragment.java index 406fd2a29..886ca68a3 100644 --- a/src/com/android/photos/AlbumFragment.java +++ b/src/com/android/photos/AlbumFragment.java @@ -31,7 +31,7 @@ import android.widget.ImageView; import android.widget.TextView; import com.android.gallery3d.R; -import com.android.gallery3d.app.Gallery; +import com.android.gallery3d.app.GalleryActivity; import com.android.photos.adapters.PhotoThumbnailAdapter; import com.android.photos.data.PhotoSetLoader; import com.android.photos.shims.LoaderCompatShim; @@ -108,7 +108,7 @@ public class AlbumFragment extends MultiSelectGridFragment implements LoaderCall Cursor item = (Cursor) getItemAtPosition(position); Uri uri = mLoaderCompatShim.uriForItem(item); Intent intent = new Intent(Intent.ACTION_VIEW, uri); - intent.setClass(getActivity(), Gallery.class); + intent.setClass(getActivity(), GalleryActivity.class); startActivity(intent); } diff --git a/src/com/android/photos/PhotoSetFragment.java b/src/com/android/photos/PhotoSetFragment.java index 961fd0bf2..7ce876fd4 100644 --- a/src/com/android/photos/PhotoSetFragment.java +++ b/src/com/android/photos/PhotoSetFragment.java @@ -28,7 +28,7 @@ import android.view.View; import android.view.ViewGroup; import android.widget.GridView; -import com.android.gallery3d.app.Gallery; +import com.android.gallery3d.app.GalleryActivity; import com.android.photos.adapters.PhotoThumbnailAdapter; import com.android.photos.data.PhotoSetLoader; import com.android.photos.shims.LoaderCompatShim; @@ -74,7 +74,7 @@ public class PhotoSetFragment extends MultiSelectGridFragment implements LoaderC Cursor item = (Cursor) getItemAtPosition(position); Uri uri = mLoaderCompatShim.uriForItem(item); Intent intent = new Intent(Intent.ACTION_VIEW, uri); - intent.setClass(getActivity(), Gallery.class); + intent.setClass(getActivity(), GalleryActivity.class); startActivity(intent); } |