summaryrefslogtreecommitdiffstats
path: root/src/com/android/gallery3d/ui
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/gallery3d/ui')
-rw-r--r--src/com/android/gallery3d/ui/ActionModeHandler.java2
-rw-r--r--src/com/android/gallery3d/ui/AlbumLabelMaker.java79
-rw-r--r--src/com/android/gallery3d/ui/DetailsHelper.java2
-rw-r--r--src/com/android/gallery3d/ui/DialogDetailsView.java34
-rw-r--r--src/com/android/gallery3d/ui/Knob.java337
-rw-r--r--src/com/android/gallery3d/ui/Paper.java62
-rwxr-xr-x[-rw-r--r--]src/com/android/gallery3d/ui/PhotoView.java22
-rw-r--r--src/com/android/gallery3d/ui/SlotView.java112
8 files changed, 565 insertions, 85 deletions
diff --git a/src/com/android/gallery3d/ui/ActionModeHandler.java b/src/com/android/gallery3d/ui/ActionModeHandler.java
index 6b4f10312..411c578a5 100644
--- a/src/com/android/gallery3d/ui/ActionModeHandler.java
+++ b/src/com/android/gallery3d/ui/ActionModeHandler.java
@@ -272,7 +272,7 @@ public class ActionModeHandler implements Callback, PopupList.OnPopupItemClickLi
ArrayList<MediaObject> selected = new ArrayList<MediaObject>();
DataManager manager = mActivity.getDataManager();
for (Path path : unexpandedPaths) {
- if (jc.isCancelled()) {
+ if (jc.isCancelled() || !mSelectionManager.inSelectionMode()) {
return null;
}
selected.add(manager.getMediaObject(path));
diff --git a/src/com/android/gallery3d/ui/AlbumLabelMaker.java b/src/com/android/gallery3d/ui/AlbumLabelMaker.java
index da1cac0bd..3ac3bb7fe 100644
--- a/src/com/android/gallery3d/ui/AlbumLabelMaker.java
+++ b/src/com/android/gallery3d/ui/AlbumLabelMaker.java
@@ -25,6 +25,7 @@ import android.graphics.PorterDuff;
import android.graphics.Typeface;
import android.text.TextPaint;
import android.text.TextUtils;
+import android.view.View;
import com.android.gallery3d.R;
import com.android.gallery3d.data.DataSourceType;
@@ -32,6 +33,8 @@ import com.android.photos.data.GalleryBitmapPool;
import com.android.gallery3d.util.ThreadPool;
import com.android.gallery3d.util.ThreadPool.JobContext;
+import java.util.Locale;
+
public class AlbumLabelMaker {
private static final int BORDER_SIZE = 0;
@@ -170,30 +173,60 @@ public class AlbumLabelMaker {
canvas.translate(BORDER_SIZE, BORDER_SIZE);
- // draw title
- if (jc.isCancelled()) return null;
- int x = s.leftMargin + s.iconSize;
- // TODO: is the offset relevant in new reskin?
- // int y = s.titleOffset;
- int y = (s.labelBackgroundHeight - s.titleFontSize) / 2;
- drawText(canvas, x, y, title, labelWidth - s.leftMargin - x -
- s.titleRightMargin, mTitlePaint);
-
- // draw count
- if (jc.isCancelled()) return null;
- x = labelWidth - s.titleRightMargin;
- y = (s.labelBackgroundHeight - s.countFontSize) / 2;
- drawText(canvas, x, y, count,
- labelWidth - x , mCountPaint);
-
- // draw the icon
- if (icon != null) {
+ if (View.LAYOUT_DIRECTION_RTL == TextUtils
+ .getLayoutDirectionFromLocale(Locale.getDefault())) {// RTL
+ // draw title
+ if (jc.isCancelled()) return null;
+ int strLength = (int) mTitlePaint.measureText(title);
+ int x = labelWidth - (s.leftMargin + s.iconSize) - strLength;
+ // TODO: is the offset relevant in new reskin?
+ // int y = s.titleOffset;
+ int y = (s.labelBackgroundHeight - s.titleFontSize) / 2;
+ drawText(canvas, x, y, title, labelWidth - s.leftMargin - x -
+ s.titleRightMargin, mTitlePaint);
+
+ // draw count
+ if (jc.isCancelled()) return null;
+ x = s.leftMargin + 10;// plus 10 to get a much bigger margin
+ y = (s.labelBackgroundHeight - s.countFontSize) / 2;
+ drawText(canvas, x, y, count,
+ labelWidth - x, mCountPaint);
+ // draw the icon
+ if (icon != null) {
+ if (jc.isCancelled()) return null;
+ float scale = (float) s.iconSize / icon.getWidth();
+ canvas.translate(labelWidth - s.leftMargin - s.iconSize,
+ (s.labelBackgroundHeight -
+ Math.round(scale * icon.getHeight())) / 2f);
+ canvas.scale(scale, scale);
+ canvas.drawBitmap(icon, 0, 0, null);
+ }
+ } else { // LTR
+ // draw title
+ if (jc.isCancelled()) return null;
+ int x = s.leftMargin + s.iconSize;
+ // TODO: is the offset relevant in new reskin?
+ // int y = s.titleOffset;
+ int y = (s.labelBackgroundHeight - s.titleFontSize) / 2;
+ drawText(canvas, x, y, title, labelWidth - s.leftMargin - x -
+ s.titleRightMargin, mTitlePaint);
+
+ // draw count
if (jc.isCancelled()) return null;
- float scale = (float) s.iconSize / icon.getWidth();
- canvas.translate(s.leftMargin, (s.labelBackgroundHeight -
- Math.round(scale * icon.getHeight()))/2f);
- canvas.scale(scale, scale);
- canvas.drawBitmap(icon, 0, 0, null);
+ x = labelWidth - s.titleRightMargin;
+ y = (s.labelBackgroundHeight - s.countFontSize) / 2;
+ drawText(canvas, x, y, count,
+ labelWidth - x, mCountPaint);
+
+ // draw the icon
+ if (icon != null) {
+ if (jc.isCancelled()) return null;
+ float scale = (float) s.iconSize / icon.getWidth();
+ canvas.translate(s.leftMargin, (s.labelBackgroundHeight -
+ Math.round(scale * icon.getHeight())) / 2f);
+ canvas.scale(scale, scale);
+ canvas.drawBitmap(icon, 0, 0, null);
+ }
}
return bitmap;
diff --git a/src/com/android/gallery3d/ui/DetailsHelper.java b/src/com/android/gallery3d/ui/DetailsHelper.java
index 47296f655..4f610407f 100644
--- a/src/com/android/gallery3d/ui/DetailsHelper.java
+++ b/src/com/android/gallery3d/ui/DetailsHelper.java
@@ -139,6 +139,8 @@ public class DetailsHelper {
return context.getString(R.string.exposure_time);
case MediaDetails.INDEX_ISO:
return context.getString(R.string.iso);
+ case MediaDetails.INDEX_DATETIME_ORIGINAL:
+ return context.getString(R.string.record_time);
default:
return "Unknown key" + key;
}
diff --git a/src/com/android/gallery3d/ui/DialogDetailsView.java b/src/com/android/gallery3d/ui/DialogDetailsView.java
index 30fd1e18f..3e2af0d40 100644
--- a/src/com/android/gallery3d/ui/DialogDetailsView.java
+++ b/src/com/android/gallery3d/ui/DialogDetailsView.java
@@ -21,6 +21,7 @@ import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnDismissListener;
+import android.text.TextUtils;
import android.text.format.Formatter;
import android.view.LayoutInflater;
import android.view.View;
@@ -33,14 +34,18 @@ import com.android.gallery3d.R;
import com.android.gallery3d.app.AbstractGalleryActivity;
import com.android.gallery3d.common.Utils;
import com.android.gallery3d.data.MediaDetails;
+import com.android.gallery3d.exif.ExifInterface;
import com.android.gallery3d.ui.DetailsAddressResolver.AddressResolvingListener;
import com.android.gallery3d.ui.DetailsHelper.CloseListener;
import com.android.gallery3d.ui.DetailsHelper.DetailsSource;
import com.android.gallery3d.ui.DetailsHelper.DetailsViewContainer;
import com.android.gallery3d.ui.DetailsHelper.ResolutionResolvingListener;
+import java.text.DateFormat;
import java.text.DecimalFormat;
+import java.text.ParseException;
import java.util.ArrayList;
+import java.util.Date;
import java.util.Locale;
import java.util.Map.Entry;
@@ -131,6 +136,15 @@ public class DialogDetailsView implements DetailsViewContainer {
setDetails(context, details);
}
+ private String exifDateToFormatedDate(String exifDt) {
+ try {
+ Date date = ExifInterface.DATETIME_FORMAT.parse(exifDt);
+ return DateFormat.getDateTimeInstance().format(date);
+ } catch (ParseException e) {
+ return exifDt;
+ }
+ }
+
private void setDetails(Context context, MediaDetails details) {
boolean resolutionIsValid = true;
String path = null;
@@ -221,6 +235,9 @@ public class DialogDetailsView implements DetailsViewContainer {
case MediaDetails.INDEX_ORIENTATION:
value = toLocalInteger(detail.getValue());
break;
+ case MediaDetails.INDEX_DATETIME_ORIGINAL:
+ value = exifDateToFormatedDate(detail.getValue().toString());
+ break;
default: {
Object valueObj = detail.getValue();
// This shouldn't happen, log its key to help us diagnose the problem.
@@ -236,13 +253,20 @@ public class DialogDetailsView implements DetailsViewContainer {
value = String.format("%s: %s %s", DetailsHelper.getDetailsName(
context, key), value, context.getString(details.getUnit(key)));
} else {
- value = String.format("%s: %s", DetailsHelper.getDetailsName(
- context, key), value);
+ if (View.LAYOUT_DIRECTION_RTL == TextUtils
+ .getLayoutDirectionFromLocale(Locale.getDefault())
+ && (key == MediaDetails.INDEX_PATH)) {
+ value = String.format("%s : \n%s",
+ DetailsHelper.getDetailsName(context, key), value);
+ } else {
+ value = String.format("%s: %s", DetailsHelper.getDetailsName(context, key),
+ value);
+ }
}
mItems.add(value);
- }
- if (!resolutionIsValid) {
- DetailsHelper.resolveResolution(path, this);
+ if (!resolutionIsValid) {
+ DetailsHelper.resolveResolution(path, this);
+ }
}
}
diff --git a/src/com/android/gallery3d/ui/Knob.java b/src/com/android/gallery3d/ui/Knob.java
new file mode 100644
index 000000000..179023e02
--- /dev/null
+++ b/src/com/android/gallery3d/ui/Knob.java
@@ -0,0 +1,337 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.android.gallery3d.ui;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.RectF;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import java.lang.Math;
+
+import com.android.gallery3d.R;
+
+public class Knob extends FrameLayout {
+ private static final int STROKE_WIDTH = 6;
+ private static final float TEXT_SIZE = 0.20f;
+ private static final float TEXT_PADDING = 0.31f;
+ private static final float LABEL_PADDING = 0.05f;
+ private static final float LABEL_SIZE = 0.09f;
+ private static final float LABEL_WIDTH = 0.80f;
+ private static final float INDICATOR_RADIUS = 0.38f;
+
+ public interface OnKnobChangeListener {
+ void onValueChanged(Knob knob, int value, boolean fromUser);
+ boolean onSwitchChanged(Knob knob, boolean on);
+ }
+
+ private OnKnobChangeListener mOnKnobChangeListener = null;
+
+ private float mProgress = 0.0f;
+ private int mMax = 100;
+ private boolean mOn = false;
+ private boolean mEnabled = false;
+
+ private int mHighlightColor;
+ private int mLowlightColor;
+ private int mDisabledColor;
+
+ private final Paint mPaint;
+
+ private final TextView mLabelTV;
+ private final TextView mProgressTV;
+
+ private final ImageView mKnobOn;
+ private final ImageView mKnobOff;
+
+ private float mLastX;
+ private float mLastY;
+ private boolean mMoved;
+
+ private int mWidth = 0;
+ private int mIndicatorWidth = 0;
+
+ private RectF mRectF;
+
+ public Knob(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Knob, 0, 0);
+
+ String label;
+ int foreground;
+ try {
+ label = a.getString(R.styleable.Knob_label);
+ foreground = a.getResourceId(R.styleable.Knob_foreground, R.drawable.knob);
+ } finally {
+ a.recycle();
+ }
+
+ LayoutInflater li = (LayoutInflater)
+ context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ li.inflate(R.layout.knob, this, true);
+
+ Resources res = getResources();
+ mHighlightColor = res.getColor(R.color.highlight);
+ mLowlightColor = res.getColor(R.color.lowlight);
+ mDisabledColor = res.getColor(R.color.disabled_knob);
+
+ ((ImageView) findViewById(R.id.knob_foreground)).setImageResource(foreground);
+
+ mLabelTV = (TextView) findViewById(R.id.knob_label);
+ mLabelTV.setText(label);
+ mProgressTV = (TextView) findViewById(R.id.knob_value);
+
+ mKnobOn = (ImageView) findViewById(R.id.knob_toggle_on);
+ mKnobOff = (ImageView) findViewById(R.id.knob_toggle_off);
+
+ mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mPaint.setColor(mHighlightColor);
+ mPaint.setStrokeWidth(STROKE_WIDTH);
+ mPaint.setStrokeCap(Paint.Cap.ROUND);
+ mPaint.setStyle(Paint.Style.STROKE);
+
+ setWillNotDraw(false);
+ }
+
+ public Knob(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public Knob(Context context) {
+ this(context, null);
+ }
+
+ public void setOnKnobChangeListener(OnKnobChangeListener l) {
+ mOnKnobChangeListener = l;
+ }
+
+ public void setValue(int value) {
+ if (mMax != 0) {
+ setProgress(((float) value) / mMax);
+ }
+ }
+
+ public int getValue() {
+ return (int) (mProgress * mMax);
+ }
+
+ public void setProgress(float progress) {
+ setProgress(progress, false);
+ }
+
+ private void setProgressText(boolean on) {
+ if (on) {
+ mProgressTV.setText((int) (mProgress * 100) + "%");
+ } else {
+ mProgressTV.setText("--%");
+ }
+ }
+
+ private void setProgress(float progress, boolean fromUser) {
+ if (progress > 1.0f) {
+ progress = 1.0f;
+ }
+ if (progress < 0.0f) {
+ progress = 0.0f;
+ }
+ mProgress = progress;
+ setProgressText(mOn && mEnabled);
+
+ invalidate();
+
+ if (mOnKnobChangeListener != null) {
+ mOnKnobChangeListener.onValueChanged(this, (int) (progress * mMax), fromUser);
+ }
+ }
+
+ public void setMax(int max) {
+ mMax = max;
+ }
+
+ public float getProgress() {
+ return mProgress;
+ }
+
+ private void drawIndicator() {
+ float r = mWidth * INDICATOR_RADIUS;
+ ImageView view = mOn ? mKnobOn : mKnobOff;
+ view.setTranslationX((float) Math.sin(mProgress * 2 * Math.PI) * r - mIndicatorWidth / 2);
+ view.setTranslationY((float) -Math.cos(mProgress * 2 * Math.PI) * r - mIndicatorWidth / 2);
+ }
+
+ @Override
+ public void setEnabled(boolean enabled) {
+ mEnabled = enabled;
+ setOn(enabled);
+ }
+
+ public void setOn(boolean on) {
+ if (on != mOn) {
+ mOn = on;
+ }
+ on = on && mEnabled;
+ mLabelTV.setTextColor(on ? mHighlightColor : mDisabledColor);
+ mProgressTV.setTextColor(on ? mHighlightColor : mDisabledColor);
+ setProgressText(on);
+ mPaint.setColor(on ? mHighlightColor : mDisabledColor);
+ mKnobOn.setVisibility(on ? View.VISIBLE : View.GONE);
+ mKnobOff.setVisibility(on ? View.GONE : View.VISIBLE);
+ invalidate();
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ drawIndicator();
+ if (mOn && mEnabled) {
+ canvas.drawArc(mRectF, -90, mProgress * 360, false, mPaint);
+ }
+ }
+
+ @Override
+ protected void onSizeChanged(int w, int h, int oldW, int oldH) {
+ int size = w > h ? h : w;
+ mWidth = size;
+ mIndicatorWidth = mKnobOn.getWidth();
+
+ int diff;
+ if (w > h) {
+ diff = (w - h) / 2;
+ mRectF = new RectF(STROKE_WIDTH + diff, STROKE_WIDTH,
+ w - STROKE_WIDTH - diff, h - STROKE_WIDTH);
+ } else {
+ diff = (h - w) / 2;
+ mRectF = new RectF(STROKE_WIDTH, STROKE_WIDTH + diff,
+ w - STROKE_WIDTH, h - STROKE_WIDTH - diff);
+ }
+
+ mProgressTV.setTextSize(TypedValue.COMPLEX_UNIT_PX, size * TEXT_SIZE);
+ mProgressTV.setPadding(0, (int) (size * TEXT_PADDING), 0, 0);
+ mProgressTV.setVisibility(View.VISIBLE);
+ mLabelTV.setTextSize(TypedValue.COMPLEX_UNIT_PX, size * LABEL_SIZE);
+ mLabelTV.setPadding(0, (int) (size * LABEL_PADDING), 0, 0);
+ mLabelTV.setLayoutParams(new LinearLayout.LayoutParams((int) (w * LABEL_WIDTH),
+ LayoutParams.WRAP_CONTENT));
+ mLabelTV.setVisibility(View.VISIBLE);
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ return true;
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ if (mOn) {
+ mLastX = event.getX();
+ mLastY = event.getY();
+ getParent().requestDisallowInterceptTouchEvent(true);
+ }
+ break;
+ case MotionEvent.ACTION_MOVE:
+ if (mOn) {
+ float x = event.getX();
+ float y = event.getY();
+ float center = mWidth / 2;
+ if (mMoved || (x - center) * (x - center) + (y - center) * (y - center)
+ > center * center / 4) {
+ float delta = getDelta(x, y);
+ setProgress(mProgress + delta / 360, true);
+ mMoved = true;
+ }
+ mLastX = x;
+ mLastY = y;
+ }
+ break;
+ case MotionEvent.ACTION_UP:
+ if (!mMoved) {
+ if (mOnKnobChangeListener == null
+ || mOnKnobChangeListener.onSwitchChanged(this, !mOn)) {
+ if (mEnabled) {
+ setOn(!mOn);
+ invalidate();
+ }
+ }
+ }
+ mMoved = false;
+ break;
+ default:
+ break;
+ }
+ return true;
+ }
+
+ private float getDelta(float x, float y) {
+ float angle = angle(x, y);
+ float oldAngle = angle(mLastX, mLastY);
+ float delta = angle - oldAngle;
+ if (delta >= 180.0f) {
+ delta = -oldAngle;
+ } else if (delta <= -180.0f) {
+ delta = 360 - oldAngle;
+ }
+ return delta;
+ }
+
+ private float angle(float x, float y) {
+ float center = mWidth / 2.0f;
+ x -= center;
+ y -= center;
+
+ if (x == 0.0f) {
+ if (y > 0.0f) {
+ return 180.0f;
+ } else {
+ return 0.0f;
+ }
+ }
+
+ float angle = (float) (Math.atan(y / x) / Math.PI * 180.0);
+ if (x > 0.0f) {
+ angle += 90;
+ } else {
+ angle += 270;
+ }
+ return angle;
+ }
+}
diff --git a/src/com/android/gallery3d/ui/Paper.java b/src/com/android/gallery3d/ui/Paper.java
index b36f5c3a2..6ed5013a2 100644
--- a/src/com/android/gallery3d/ui/Paper.java
+++ b/src/com/android/gallery3d/ui/Paper.java
@@ -28,53 +28,76 @@ class Paper {
@SuppressWarnings("unused")
private static final String TAG = "Paper";
private static final int ROTATE_FACTOR = 4;
- private EdgeAnimation mAnimationLeft = new EdgeAnimation();
- private EdgeAnimation mAnimationRight = new EdgeAnimation();
+ private EdgeAnimation mAnimationBegin = new EdgeAnimation();
+ private EdgeAnimation mAnimationEnd = new EdgeAnimation();
private int mWidth;
+ private int mHeight;
private float[] mMatrix = new float[16];
+ private final boolean mIsWide;
+
+ public Paper(boolean wide) {
+ mIsWide = wide;
+ }
+
public void overScroll(float distance) {
distance /= mWidth; // make it relative to width
if (distance < 0) {
- mAnimationLeft.onPull(-distance);
+ mAnimationBegin.onPull(-distance);
} else {
- mAnimationRight.onPull(distance);
+ mAnimationEnd.onPull(distance);
}
}
public void edgeReached(float velocity) {
velocity /= mWidth; // make it relative to width
if (velocity < 0) {
- mAnimationRight.onAbsorb(-velocity);
+ mAnimationEnd.onAbsorb(-velocity);
} else {
- mAnimationLeft.onAbsorb(velocity);
+ mAnimationBegin.onAbsorb(velocity);
}
}
public void onRelease() {
- mAnimationLeft.onRelease();
- mAnimationRight.onRelease();
+ mAnimationBegin.onRelease();
+ mAnimationEnd.onRelease();
}
public boolean advanceAnimation() {
// Note that we use "|" because we want both animations get updated.
- return mAnimationLeft.update() | mAnimationRight.update();
+ return mAnimationBegin.update() | mAnimationEnd.update();
}
public void setSize(int width, int height) {
mWidth = width;
+ mHeight = height;
}
- public float[] getTransform(Rect rect, float scrollX) {
- float left = mAnimationLeft.getValue();
- float right = mAnimationRight.getValue();
- float screenX = rect.centerX() - scrollX;
- // We linearly interpolate the value [left, right] for the screenX
- // range int [-1/4, 5/4]*mWidth. So if part of the thumbnail is outside
+ public float[] getTransform(Rect rect, float scroll) {
+ Log.d(TAG, rect.toString());
+ float start = mAnimationBegin.getValue();
+ float end = mAnimationEnd.getValue();
+ int center = 0;
+ int screenWidth = mWidth;
+ int rotateX = 0;
+ int rotateY = 0;
+ final boolean wide = mIsWide;
+ if (wide) {
+ center = rect.centerX();
+ rotateY = 1;
+ } else {
+ center = rect.centerY();
+ rotateX = 1;
+ screenWidth = mHeight;
+ }
+ float screen = center - scroll;
+ // We linearly interpolate the value [start, end] for the screen
+ // range int [-1/4, 5/4]*screenWidth. So if part of the thumbnail is outside
// the screen, we still get some transform.
- float x = screenX + mWidth / 4;
- int range = 3 * mWidth / 2;
- float t = ((range - x) * left - x * right) / range;
+ float x = screen + screenWidth / 4;
+ int range = 3 * screenWidth / 2;
+ float t = ((range - x) * start - x * end) / range;
+
// compress t to the range (-1, 1) by the function
// f(t) = (1 / (1 + e^-t) - 0.5) * 2
// then multiply by 90 to make the range (-45, 45)
@@ -82,8 +105,9 @@ class Paper {
(1 / (1 + (float) Math.exp(-t * ROTATE_FACTOR)) - 0.5f) * 2 * -45;
Matrix.setIdentityM(mMatrix, 0);
Matrix.translateM(mMatrix, 0, mMatrix, 0, rect.centerX(), rect.centerY(), 0);
- Matrix.rotateM(mMatrix, 0, degrees, 0, 1, 0);
+ Matrix.rotateM(mMatrix, 0, degrees, rotateX, rotateY, 0);
Matrix.translateM(mMatrix, 0, mMatrix, 0, -rect.width() / 2, -rect.height() / 2, 0);
+
return mMatrix;
}
}
diff --git a/src/com/android/gallery3d/ui/PhotoView.java b/src/com/android/gallery3d/ui/PhotoView.java
index e8c706f05..347d4b3af 100644..100755
--- a/src/com/android/gallery3d/ui/PhotoView.java
+++ b/src/com/android/gallery3d/ui/PhotoView.java
@@ -92,6 +92,9 @@ public class PhotoView extends GLView {
// Returns true if the item is a Video.
public boolean isVideo(int offset);
+ // Returns true if the item is a Gif.
+ public boolean isGif(int offset);
+
// Returns true if the item can be deleted.
public boolean isDeletable(int offset);
@@ -593,7 +596,6 @@ public class PhotoView extends GLView {
private boolean mIsCamera;
private boolean mIsPanorama;
private boolean mIsStaticCamera;
- private boolean mIsVideo;
private boolean mIsDeletable;
private int mLoadingState = Model.LOADING_INIT;
private Size mSize = new Size();
@@ -606,7 +608,6 @@ public class PhotoView extends GLView {
mIsCamera = mModel.isCamera(0);
mIsPanorama = mModel.isPanorama(0);
mIsStaticCamera = mModel.isStaticCamera(0);
- mIsVideo = mModel.isVideo(0);
mIsDeletable = mModel.isDeletable(0);
mLoadingState = mModel.getLoadingState(0);
setScreenNail(mModel.getScreenNail(0));
@@ -731,8 +732,11 @@ public class PhotoView extends GLView {
// Draw the play video icon and the message.
canvas.translate((int) (cx + 0.5f), (int) (cy + 0.5f));
int s = (int) (scale * Math.min(r.width(), r.height()) + 0.5f);
- if (mIsVideo) drawVideoPlayIcon(canvas, s);
- if (mLoadingState == Model.LOADING_FAIL) {
+ //Full pic locates at index 0 of the array in PhotoDataAdapter
+ if (mModel.isVideo(0) || mModel.isGif(0)) {
+ drawVideoPlayIcon(canvas, s);
+ }
+ if (mLoadingState == Model.LOADING_FAIL ) {
drawLoadingFailMessage(canvas);
}
@@ -774,7 +778,6 @@ public class PhotoView extends GLView {
private boolean mIsCamera;
private boolean mIsPanorama;
private boolean mIsStaticCamera;
- private boolean mIsVideo;
private boolean mIsDeletable;
private int mLoadingState = Model.LOADING_INIT;
private Size mSize = new Size();
@@ -788,7 +791,6 @@ public class PhotoView extends GLView {
mIsCamera = mModel.isCamera(mIndex);
mIsPanorama = mModel.isPanorama(mIndex);
mIsStaticCamera = mModel.isStaticCamera(mIndex);
- mIsVideo = mModel.isVideo(mIndex);
mIsDeletable = mModel.isDeletable(mIndex);
mLoadingState = mModel.getLoadingState(mIndex);
setScreenNail(mModel.getScreenNail(mIndex));
@@ -852,8 +854,10 @@ public class PhotoView extends GLView {
invalidate();
}
int s = Math.min(drawW, drawH);
- if (mIsVideo) drawVideoPlayIcon(canvas, s);
- if (mLoadingState == Model.LOADING_FAIL) {
+ if (mModel.isVideo(mIndex) || mModel.isGif(mIndex)) {
+ drawVideoPlayIcon(canvas, s);
+ }
+ if (mLoadingState == Model.LOADING_FAIL ) {
drawLoadingFailMessage(canvas);
}
canvas.restore();
@@ -1128,6 +1132,7 @@ public class PhotoView extends GLView {
}
private void deleteAfterAnimation(int duration) {
+ if (mHandler.hasMessages(MSG_DELETE_ANIMATION_DONE)) return;
MediaItem item = mModel.getMediaItem(mTouchBoxIndex);
if (item == null) return;
mListener.onCommitDeleteImage();
@@ -1854,4 +1859,5 @@ public class PhotoView extends GLView {
}
return effect;
}
+
}
diff --git a/src/com/android/gallery3d/ui/SlotView.java b/src/com/android/gallery3d/ui/SlotView.java
index bd0ffdc15..475d93a67 100644
--- a/src/com/android/gallery3d/ui/SlotView.java
+++ b/src/com/android/gallery3d/ui/SlotView.java
@@ -18,20 +18,24 @@ package com.android.gallery3d.ui;
import android.graphics.Rect;
import android.os.Handler;
+import android.text.TextUtils;
import android.view.GestureDetector;
import android.view.MotionEvent;
+import android.view.View;
import android.view.animation.DecelerateInterpolator;
+import com.android.gallery3d.R;
import com.android.gallery3d.anim.Animation;
import com.android.gallery3d.app.AbstractGalleryActivity;
import com.android.gallery3d.common.Utils;
import com.android.gallery3d.glrenderer.GLCanvas;
+import java.util.Locale;
+
public class SlotView extends GLView {
@SuppressWarnings("unused")
private static final String TAG = "SlotView";
- private static final boolean WIDE = true;
private static final int INDEX_NONE = -1;
public static final int RENDER_MORE_PASS = 1;
@@ -62,7 +66,7 @@ public class SlotView extends GLView {
private final GestureDetector mGestureDetector;
private final ScrollerHelper mScroller;
- private final Paper mPaper = new Paper();
+ private final Paper mPaper;
private Listener mListener;
private UserInteractionListener mUIListener;
@@ -88,10 +92,17 @@ public class SlotView extends GLView {
// to prevent allocating memory
private final Rect mTempRect = new Rect();
+ // Flag to check whether it is come from Photo Page.
+ private boolean isFromPhotoPage = false;
+
+ private final boolean mIsWide;
+
public SlotView(AbstractGalleryActivity activity, Spec spec) {
+ mIsWide = activity.getResources().getBoolean(R.bool.config_scroll_horizontal);
mGestureDetector = new GestureDetector(activity, new MyGestureListener());
mScroller = new ScrollerHelper(activity);
mHandler = new SynchronizedHandler(activity.getGLRoot());
+ mPaper = new Paper(mIsWide);
setSlotSpec(spec);
}
@@ -109,7 +120,7 @@ public class SlotView extends GLView {
return;
}
Rect rect = mLayout.getSlotRect(index, mTempRect);
- int position = WIDE
+ int position = mIsWide
? (rect.left + rect.right - getWidth()) / 2
: (rect.top + rect.bottom - getHeight()) / 2;
setScrollPosition(position);
@@ -117,11 +128,11 @@ public class SlotView extends GLView {
public void makeSlotVisible(int index) {
Rect rect = mLayout.getSlotRect(index, mTempRect);
- int visibleBegin = WIDE ? mScrollX : mScrollY;
- int visibleLength = WIDE ? getWidth() : getHeight();
+ int visibleBegin = mIsWide ? mScrollX : mScrollY;
+ int visibleLength = mIsWide ? getWidth() : getHeight();
int visibleEnd = visibleBegin + visibleLength;
- int slotBegin = WIDE ? rect.left : rect.top;
- int slotEnd = WIDE ? rect.right : rect.bottom;
+ int slotBegin = mIsWide ? rect.left : rect.top;
+ int slotEnd = mIsWide ? rect.right : rect.bottom;
int position = visibleBegin;
if (visibleLength < slotEnd - slotBegin) {
@@ -135,7 +146,20 @@ public class SlotView extends GLView {
setScrollPosition(position);
}
+ /**
+ * Set the flag which used for check whether it is come from Photo Page.
+ */
+ public void setIsFromPhotoPage(boolean flag) {
+ isFromPhotoPage = flag;
+ }
+
public void setScrollPosition(int position) {
+ if (View.LAYOUT_DIRECTION_RTL == TextUtils
+ .getLayoutDirectionFromLocale(Locale.getDefault())
+ && position == 0 && !isFromPhotoPage) {
+ // If RTL and not from Photo Page, set position to max.
+ position = mLayout.getScrollLimit();
+ }
position = Utils.clamp(position, 0, mLayout.getScrollLimit());
mScroller.setPosition(position);
updateScrollPosition(position, false);
@@ -179,8 +203,8 @@ public class SlotView extends GLView {
}
private void updateScrollPosition(int position, boolean force) {
- if (!force && (WIDE ? position == mScrollX : position == mScrollY)) return;
- if (WIDE) {
+ if (!force && (mIsWide ? position == mScrollX : position == mScrollY)) return;
+ if (mIsWide) {
mScrollX = position;
} else {
mScrollY = position;
@@ -315,7 +339,7 @@ public class SlotView extends GLView {
canvas.save(GLCanvas.SAVE_FLAG_ALPHA | GLCanvas.SAVE_FLAG_MATRIX);
Rect rect = mLayout.getSlotRect(index, mTempRect);
if (paperActive) {
- canvas.multiplyMatrix(mPaper.getTransform(rect, mScrollX), 0);
+ canvas.multiplyMatrix(mPaper.getTransform(rect, (mIsWide ? mScrollX : mScrollY)), 0);
} else {
canvas.translate(rect.left, rect.top, 0);
}
@@ -389,6 +413,8 @@ public class SlotView extends GLView {
public int rowsLand = -1;
public int rowsPort = -1;
+ public int colsLand = -1;
+ public int colsPort = -1;
public int slotGap = -1;
}
@@ -434,9 +460,17 @@ public class SlotView extends GLView {
public Rect getSlotRect(int index, Rect rect) {
int col, row;
- if (WIDE) {
- col = index / mUnitCount;
- row = index - col * mUnitCount;
+ if (mIsWide) {
+ if (View.LAYOUT_DIRECTION_RTL == TextUtils
+ .getLayoutDirectionFromLocale(Locale.getDefault())) {
+ // If RTL, recalculate the columns and rows.
+ int count = ((mSlotCount + mUnitCount - 1) / mUnitCount);
+ col = count - index / mUnitCount - 1;
+ row = index % mUnitCount;
+ } else {
+ col = index / mUnitCount;
+ row = index - col * mUnitCount;
+ }
} else {
row = index / mUnitCount;
col = index - row * mUnitCount;
@@ -498,10 +532,17 @@ public class SlotView extends GLView {
mSlotWidth = mSpec.slotWidth;
mSlotHeight = mSpec.slotHeight;
} else {
- int rows = (mWidth > mHeight) ? mSpec.rowsLand : mSpec.rowsPort;
- mSlotGap = mSpec.slotGap;
- mSlotHeight = Math.max(1, (mHeight - (rows - 1) * mSlotGap) / rows);
- mSlotWidth = mSlotHeight - mSpec.slotHeightAdditional;
+ if (mIsWide) {
+ int rows = (mWidth > mHeight) ? mSpec.rowsLand : mSpec.rowsPort;
+ mSlotGap = mSpec.slotGap;
+ mSlotHeight = Math.max(1, (mHeight - (rows - 1) * mSlotGap) / rows);
+ mSlotWidth = mSlotHeight - mSpec.slotHeightAdditional;
+ } else {
+ int cols = (mWidth > mHeight) ? mSpec.colsLand : mSpec.colsPort;
+ mSlotGap = mSpec.slotGap;
+ mSlotHeight = Math.max(1, (mWidth - (cols - 1) * mSlotGap) / cols);
+ mSlotWidth = mSlotHeight - mSpec.slotHeightAdditional;
+ }
}
if (mRenderer != null) {
@@ -509,7 +550,7 @@ public class SlotView extends GLView {
}
int[] padding = new int[2];
- if (WIDE) {
+ if (mIsWide) {
initLayoutParameters(mWidth, mHeight, mSlotWidth, mSlotHeight, padding);
mVerticalPadding.startAnimateTo(padding[0]);
mHorizontalPadding.startAnimateTo(padding[1]);
@@ -530,7 +571,14 @@ public class SlotView extends GLView {
private void updateVisibleSlotRange() {
int position = mScrollPosition;
- if (WIDE) {
+ if (mIsWide) {
+ if (View.LAYOUT_DIRECTION_RTL == TextUtils
+ .getLayoutDirectionFromLocale(Locale.getDefault())) {
+ // If RTL, recalculate the position.
+ position = mContentLength > mWidth ? (mContentLength - position - mWidth)
+ : position;
+ position = Math.max(0, position);
+ }
int startCol = position / (mSlotWidth + mSlotGap);
int start = Math.max(0, mUnitCount * startCol);
int endCol = (position + mWidth + mSlotWidth + mSlotGap - 1) /
@@ -575,9 +623,8 @@ public class SlotView extends GLView {
}
public int getSlotIndexByPosition(float x, float y) {
- int absoluteX = Math.round(x) + (WIDE ? mScrollPosition : 0);
- int absoluteY = Math.round(y) + (WIDE ? 0 : mScrollPosition);
-
+ int absoluteX = Math.round(x) + (mIsWide ? mScrollPosition : 0);
+ int absoluteY = Math.round(y) + (mIsWide ? 0 : mScrollPosition);
absoluteX -= mHorizontalPadding.get();
absoluteY -= mVerticalPadding.get();
@@ -588,11 +635,11 @@ public class SlotView extends GLView {
int columnIdx = absoluteX / (mSlotWidth + mSlotGap);
int rowIdx = absoluteY / (mSlotHeight + mSlotGap);
- if (!WIDE && columnIdx >= mUnitCount) {
+ if (!mIsWide && columnIdx >= mUnitCount) {
return INDEX_NONE;
}
- if (WIDE && rowIdx >= mUnitCount) {
+ if (mIsWide && rowIdx >= mUnitCount) {
return INDEX_NONE;
}
@@ -604,7 +651,7 @@ public class SlotView extends GLView {
return INDEX_NONE;
}
- int index = WIDE
+ int index = mIsWide
? (columnIdx * mUnitCount + rowIdx)
: (rowIdx * mUnitCount + columnIdx);
@@ -612,7 +659,7 @@ public class SlotView extends GLView {
}
public int getScrollLimit() {
- int limit = WIDE ? mContentLength - mWidth : mContentLength - mHeight;
+ int limit = mIsWide ? mContentLength - mWidth : mContentLength - mHeight;
return limit <= 0 ? 0 : limit;
}
@@ -660,7 +707,7 @@ public class SlotView extends GLView {
cancelDown(false);
int scrollLimit = mLayout.getScrollLimit();
if (scrollLimit == 0) return false;
- float velocity = WIDE ? velocityX : velocityY;
+ float velocity = mIsWide ? velocityX : velocityY;
mScroller.fling((int) -velocity, 0, scrollLimit);
if (mUIListener != null) mUIListener.onUserInteractionBegin();
invalidate();
@@ -671,7 +718,7 @@ public class SlotView extends GLView {
public boolean onScroll(MotionEvent e1,
MotionEvent e2, float distanceX, float distanceY) {
cancelDown(false);
- float distance = WIDE ? distanceX : distanceY;
+ float distance = mIsWide ? distanceX : distanceY;
int overDistance = mScroller.startScroll(
Math.round(distance), 0, mLayout.getScrollLimit());
if (mOverscrollEffect == OVERSCROLL_3D && overDistance != 0) {
@@ -718,7 +765,7 @@ public class SlotView extends GLView {
mStartIndex = INDEX_NONE;
}
// Reset the scroll position to avoid scrolling over the updated limit.
- setScrollPosition(WIDE ? mScrollX : mScrollY);
+ setScrollPosition(mIsWide ? mScrollX : mScrollY);
return changed;
}
@@ -785,4 +832,11 @@ public class SlotView extends GLView {
if (progress == 1f) mEnabled = false;
}
}
+
+ /**
+ * Get the SlotView's max scroll value.
+ */
+ public int getScrollLimit() {
+ return mLayout.getScrollLimit();
+ }
}