diff options
Diffstat (limited to 'src/com/android/gallery3d/ui')
-rw-r--r-- | src/com/android/gallery3d/ui/ActionModeHandler.java | 2 | ||||
-rw-r--r-- | src/com/android/gallery3d/ui/AlbumLabelMaker.java | 79 | ||||
-rw-r--r-- | src/com/android/gallery3d/ui/DetailsHelper.java | 2 | ||||
-rw-r--r-- | src/com/android/gallery3d/ui/DialogDetailsView.java | 34 | ||||
-rw-r--r-- | src/com/android/gallery3d/ui/Knob.java | 337 | ||||
-rw-r--r-- | src/com/android/gallery3d/ui/Paper.java | 62 | ||||
-rwxr-xr-x[-rw-r--r--] | src/com/android/gallery3d/ui/PhotoView.java | 22 | ||||
-rw-r--r-- | src/com/android/gallery3d/ui/SlotView.java | 112 |
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(); + } } |