import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Matrix;
+import android.graphics.Point;
import android.graphics.SurfaceTexture;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
return;
}
- mPeekAnimationHandler.startAnimationJob(data, new Callback<Bitmap>() {
+ mPeekAnimationHandler.startDecodingJob(data, new Callback<Bitmap>() {
@Override
public void onCallback(Bitmap result) {
mCameraAppUI.startPeekAnimation(result, true);
* @param callback {@link com.android.camera.util.Callback} after the
* decoding is done.
*/
- public void startAnimationJob(final LocalData data,
- final com.android.camera.util.Callback<Bitmap>
- callback) {
+ public void startDecodingJob(final LocalData data,
+ final com.android.camera.util.Callback<Bitmap> callback) {
PeekAnimationHandler.this.obtainMessage(0 /** dummy integer **/,
new DataAndCallback(data, callback)).sendToTarget();
}
Log.e(TAG, "File not found:" + data.getPath());
return;
}
+ Point dim = CameraUtil.resizeToFill(data.getWidth(), data.getHeight(),
+ data.getRotation(), mAboveFilmstripControlLayout.getWidth(),
+ mAboveFilmstripControlLayout.getMeasuredHeight());
+ if (data.getRotation() % 180 != 0) {
+ int dummy = dim.x;
+ dim.x = dim.y;
+ dim.y = dummy;
+ }
bitmap = LocalDataUtil
.loadImageThumbnailFromStream(stream, data.getWidth(), data.getHeight(),
- data.getWidth() / 4, data.getHeight() / 4,
- data.getOrientation(), MAX_PEEK_BITMAP_PIXELS);
+ (int) (dim.x * 0.7f), (int) (dim.y * 0.7),
+ data.getRotation(), MAX_PEEK_BITMAP_PIXELS);
break;
case LocalData.LOCAL_VIDEO:
}
@Override
- public int getOrientation() {
- return mLocalData.getOrientation();
+ public int getRotation() {
+ return mLocalData.getRotation();
}
@Override
/** 32K buffer. */
byte[] decodeBuffer = new byte[32 * 1024];
+ if (orientation % 180 != 0) {
+ int dummy = imageHeight;
+ imageHeight = imageWidth;
+ imageWidth = dummy;
+ }
+
// Generate Bitmap of maximum size that fits into widthBound x heightBound.
// Algorithm: start with full size and step down in powers of 2.
int targetWidth = imageWidth;
}
@Override
- public int getOrientation() {
+ public int getRotation() {
return 0;
}
}
@Override
- public int getOrientation() {
+ public int getRotation() {
return mOrientation;
}
}
PhotoData imageData = (PhotoData) data;
- int originRotation = imageData.getOrientation();
+ int originRotation = imageData.getRotation();
int finalRotationDegrees;
if (mClockwise) {
finalRotationDegrees = (originRotation + 90) % 360;
}
@Override
- public int getOrientation() {
+ public int getRotation() {
return 0;
}
public int getHeight();
/**
- * Returns the orientation of the image in degrees. The valid values are
- * 0, 90, 180, and 270.
+ * Returns the rotation of the image in degrees clockwise. The valid values
+ * are 0, 90, 180, and 270.
*/
- public int getOrientation();
+ public int getRotation();
/** Returns the image data type. The current valid values are
* {@code VIEW_TYPE_*}.
import com.android.camera.CameraActivity;
import com.android.camera.CameraDisabledException;
+import com.android.camera.filmstrip.ImageData;
import com.android.camera2.R;
import java.io.Closeable;
}
}
+ /**
+ * Calculates a new dimension to fill the bound with the original aspect
+ * ratio preserved.
+ *
+ * @param imageWidth The original width.
+ * @param imageHeight The original height.
+ * @param imageRotation The clockwise rotation in degrees of the image
+ * which the original dimension comes from.
+ * @param boundWidth The width of the bound.
+ * @param boundHeight The height of the bound.
+ *
+ * @returns The final width/height stored in Point.x/Point.y to fill the
+ * bounds and preserve image aspect ratio.
+ */
+ public static Point resizeToFill(int imageWidth, int imageHeight, int imageRotation,
+ int boundWidth, int boundHeight) {
+ if (imageRotation % 180 != 0) {
+ // Swap width and height.
+ int savedWidth = imageWidth;
+ imageWidth = imageHeight;
+ imageHeight = savedWidth;
+ }
+ if (imageWidth == ImageData.SIZE_FULL
+ || imageHeight == ImageData.SIZE_FULL) {
+ imageWidth = boundWidth;
+ imageHeight = boundHeight;
+ }
+
+ Point p = new Point();
+ p.x = boundWidth;
+ p.y = boundHeight;
+
+ if (imageWidth * boundHeight > boundWidth * imageHeight) {
+ p.y = imageHeight * p.x / imageWidth;
+ } else {
+ p.x = imageWidth * p.y / imageHeight;
+ }
+
+ return p;
+ }
+
private static class ImageFileNamer {
private final SimpleDateFormat mFormat;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
+import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.RectF;
import android.net.Uri;
import com.android.camera.filmstrip.ImageData;
import com.android.camera.ui.FilmstripGestureRecognizer;
import com.android.camera.ui.ZoomView;
+import com.android.camera.util.CameraUtil;
import com.android.camera2.R;
import java.util.Arrays;
return false;
}
- /** Returns [width, height] preserving image aspect ratio. */
- private int[] calculateChildDimension(
- int imageWidth, int imageHeight, int imageOrientation,
- int boundWidth, int boundHeight) {
- if (imageOrientation == 90 || imageOrientation == 270) {
- // Swap width and height.
- int savedWidth = imageWidth;
- imageWidth = imageHeight;
- imageHeight = savedWidth;
- }
- if (imageWidth == ImageData.SIZE_FULL
- || imageHeight == ImageData.SIZE_FULL) {
- imageWidth = boundWidth;
- imageHeight = boundHeight;
- }
-
- int[] ret = new int[2];
- ret[0] = boundWidth;
- ret[1] = boundHeight;
-
- if (imageWidth * ret[1] > ret[0] * imageHeight) {
- ret[1] = imageHeight * ret[0] / imageWidth;
- } else {
- ret[0] = imageWidth * ret[1] / imageHeight;
- }
-
- return ret;
- }
-
private void measureViewItem(ViewItem item, int boundWidth, int boundHeight) {
int id = item.getId();
ImageData imageData = mDataAdapter.getImageData(id);
return;
}
- int[] dim = calculateChildDimension(imageData.getWidth(),
- imageData.getHeight(),
- imageData.getOrientation(), boundWidth, boundHeight);
+ Point dim = CameraUtil.resizeToFill(imageData.getWidth(), imageData.getHeight(),
+ imageData.getRotation(), boundWidth, boundHeight);
- item.measure(MeasureSpec.makeMeasureSpec(dim[0], MeasureSpec.EXACTLY),
- MeasureSpec.makeMeasureSpec(dim[1], MeasureSpec.EXACTLY));
+ item.measure(MeasureSpec.makeMeasureSpec(dim.x, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(dim.y, MeasureSpec.EXACTLY));
}
@Override
}
final ImageData data = mDataAdapter.getImageData(dataID);
- int[] dim = calculateChildDimension(
- data.getWidth(), data.getHeight(), data.getOrientation(),
- getMeasuredWidth(), getMeasuredHeight());
- final int offsetX = dim[0] + mViewGapInPixel;
+ Point dim = CameraUtil
+ .resizeToFill(data.getWidth(), data.getHeight(), data.getRotation(),
+ getMeasuredWidth(), getMeasuredHeight());
+ final int offsetX = dim.x + mViewGapInPixel;
ViewItem viewItem = buildItemFromData(dataID);
if (insertedItemId >= mCurrentItem) {
if (!mIsUserScrolling && !mController.isScrolling()) {
// If there is no scrolling at all, adjust mCenterX to place
// the current item at the center.
- int[] dim = calculateChildDimension(
- data.getWidth(), data.getHeight(), data.getOrientation(),
- getMeasuredWidth(), getMeasuredHeight());
- mCenterX = curr.getLeftPosition() + dim[0] / 2;
+ Point dim = CameraUtil.resizeToFill(data.getWidth(), data.getHeight(),
+ data.getRotation(), getMeasuredWidth(), getMeasuredHeight());
+ mCenterX = curr.getLeftPosition() + dim.x / 2;
}
}
return FULL_SCREEN_SCALE;
}
float imageWidth = imageData.getWidth();
- if (imageData.getOrientation() == 90
- || imageData.getOrientation() == 270) {
+ if (imageData.getRotation() == 90
+ || imageData.getRotation() == 270) {
imageWidth = imageData.getHeight();
}
float scale = imageWidth / curr.getWidth();
if (uri == null || uri == Uri.EMPTY) {
return;
}
- int orientation = imageData.getOrientation();
+ int orientation = imageData.getRotation();
mZoomView.loadBitmap(uri, orientation, viewRect);
}
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Bitmap;
+import android.graphics.Canvas;
import android.graphics.Point;
+import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.widget.ImageView;
+import com.android.camera.util.CameraUtil;
+
/**
* An ImageView which has the built-in peek animation support.
*/
public class PeekView extends ImageView {
private static final float ROTATE_ANGLE = -15f;
- private static final long PEEK_IN_DURATION_MS = 300;
- private static final long PEEK_STAY_DURATION_MS = 200;
- private static final long PEEK_OUT_DURATION_MS = 300;
+ private static final long PEEK_IN_DURATION_MS = 200;
+ private static final long PEEK_STAY_DURATION_MS = 100;
+ private static final long PEEK_OUT_DURATION_MS = 200;
+ private static final float FILMSTRIP_SCALE = 0.7f;
private AnimatorSet mPeekAnimator;
private float mPeekRotateAngle;
private Point mRotationPivot;
private float mRotateScale;
private boolean mAnimationCanceled;
+ private Drawable mImageDrawable;
+ private Rect mDrawableBound;
public PeekView(Context context) {
super(context);
private void init() {
mRotationPivot = new Point();
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+
+ @Override
+ protected void onDraw(Canvas c) {
+ super.onDraw(c);
+ if (mImageDrawable == null) {
+ return;
+ }
+ c.save();
+ c.rotate(mPeekRotateAngle, mRotationPivot.x, mRotationPivot.y);
+ mImageDrawable.setBounds(mDrawableBound);
+ mImageDrawable.draw(c);
+ c.restore();
+ }
+
+ /**
+ * Starts the peek animation.
+ *
+ * @param bitmap The bitmap for the animation.
+ * @param strong {@code true} if the animation is the strong version which
+ * shows more portion of the bitmap.
+ */
+ public void startPeekAnimation(final Bitmap bitmap, boolean strong) {
ValueAnimator.AnimatorUpdateListener updateListener =
new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
mPeekRotateAngle = mRotateScale * (Float) valueAnimator.getAnimatedValue();
- drawPeekAnimation();
+ invalidate();
}
};
ValueAnimator peekAnimateIn = ValueAnimator.ofFloat(0f, ROTATE_ANGLE);
}
});
- }
- @Override
- public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- setTranslationX(getMeasuredWidth());
- }
-
- /**
- * Starts the peek animation.
- *
- * @param bitmap The bitmap for the animation.
- * @param strong {@code true} if the animation is the strong version which
- * shows more portion of the bitmap.
- */
- public void startPeekAnimation(final Bitmap bitmap, boolean strong) {
mRotateScale = (strong ? 1.0f : 0.5f);
- setImageDrawable(new BitmapDrawable(getResources(), bitmap));
- mRotationPivot.set(0, getHeight());
+ mImageDrawable = new BitmapDrawable(getResources(), bitmap);
+ Point drawDim = CameraUtil.resizeToFill(mImageDrawable.getIntrinsicWidth(),
+ mImageDrawable.getIntrinsicHeight(), 0, (int) (getWidth() * FILMSTRIP_SCALE),
+ (int) (getHeight() * FILMSTRIP_SCALE));
+ int x = getMeasuredWidth();
+ int y = (getMeasuredHeight() - drawDim.y) / 2;
+ mDrawableBound = new Rect(x, y, x + drawDim.x, y + drawDim.y);
+ mRotationPivot.set(x, (int) (y + drawDim.y * 1.1));
mPeekAnimator.start();
}
}
}
- private void drawPeekAnimation() {
- if (mPeekAnimator.isRunning()) {
- setTranslationX(getMeasuredWidth());
- setRotation(mPeekRotateAngle);
- setPivotX(mRotationPivot.x);
- setPivotY(mRotationPivot.y);
- }
- }
-
private void clear() {
setVisibility(INVISIBLE);
setImageDrawable(null);
- setRotation(0);
}
}