Kaynağa Gözat

增加浏览大图功能

316044749 7 yıl önce
ebeveyn
işleme
21ddf81630
22 değiştirilmiş dosya ile 2896 ekleme ve 1 silme
  1. 4 0
      app/src/main/AndroidManifest.xml
  2. 49 0
      app/src/main/java/com/ynstkz/shitu/android/activity/ImageBrowseActivity.java
  3. 12 1
      app/src/main/java/com/ynstkz/shitu/android/adapter/OrgDetailCommentPicAdapter.java
  4. 14 0
      app/src/main/res/layout/activity_imagebrowse.xml
  5. 59 0
      library/src/main/java/com/common/library/view/photoview/Compat.java
  6. 99 0
      library/src/main/java/com/common/library/view/photoview/DefaultOnDoubleTapListener.java
  7. 364 0
      library/src/main/java/com/common/library/view/photoview/IPhotoView.java
  8. 313 0
      library/src/main/java/com/common/library/view/photoview/PhotoView.java
  9. 1213 0
      library/src/main/java/com/common/library/view/photoview/PhotoViewAttacher.java
  10. 147 0
      library/src/main/java/com/common/library/view/photoview/gestures/CupcakeGestureDetector.java
  11. 91 0
      library/src/main/java/com/common/library/view/photoview/gestures/EclairGestureDetector.java
  12. 72 0
      library/src/main/java/com/common/library/view/photoview/gestures/FroyoGestureDetector.java
  13. 30 0
      library/src/main/java/com/common/library/view/photoview/gestures/GestureDetector.java
  14. 27 0
      library/src/main/java/com/common/library/view/photoview/gestures/OnGestureListener.java
  15. 42 0
      library/src/main/java/com/common/library/view/photoview/gestures/VersionedGestureDetector.java
  16. 35 0
      library/src/main/java/com/common/library/view/photoview/log/LogManager.java
  17. 42 0
      library/src/main/java/com/common/library/view/photoview/log/Logger.java
  18. 76 0
      library/src/main/java/com/common/library/view/photoview/log/LoggerDefault.java
  19. 68 0
      library/src/main/java/com/common/library/view/photoview/scrollerproxy/GingerScroller.java
  20. 33 0
      library/src/main/java/com/common/library/view/photoview/scrollerproxy/IcsScroller.java
  21. 58 0
      library/src/main/java/com/common/library/view/photoview/scrollerproxy/PreGingerScroller.java
  22. 48 0
      library/src/main/java/com/common/library/view/photoview/scrollerproxy/ScrollerProxy.java

+ 4 - 0
app/src/main/AndroidManifest.xml

@@ -154,6 +154,10 @@
         <activity android:name=".activity.AlterHeadpicActivity"
             android:screenOrientation="portrait"/>
 
+        <!--图片浏览-->
+        <activity android:name=".activity.ImageBrowseActivity"
+            android:screenOrientation="portrait"/>
+
         <!--定位服务-->
         <meta-data android:name="com.amap.api.v2.apikey" android:value="45fb5d8b52ba4f9f214bfb4fdaf81a72"/>
         <service android:name="com.amap.api.location.APSService"/>

+ 49 - 0
app/src/main/java/com/ynstkz/shitu/android/activity/ImageBrowseActivity.java

@@ -0,0 +1,49 @@
+package com.ynstkz.shitu.android.activity;
+
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.text.TextUtils;
+import android.widget.Toast;
+
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.load.engine.DiskCacheStrategy;
+import com.common.library.view.photoview.PhotoView;
+import com.ynstkz.shitu.android.R;
+import com.ynstkz.shitu.android.base.BaseActivity;
+
+import butterknife.Bind;
+import butterknife.ButterKnife;
+
+/**
+ * 作者:fuchangle on 2018/3/26 17:49
+ */
+
+public class ImageBrowseActivity extends BaseActivity {
+
+    @Bind(R.id.photoview)
+    PhotoView photoview;
+
+    private String imageUrl;
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_imagebrowse);
+        ButterKnife.bind(this);
+        initView();
+        initData();
+    }
+
+    private void initView(){
+
+    }
+
+    private void initData(){
+        imageUrl = getIntent().getStringExtra("imageUrl");
+        if (TextUtils.isEmpty(imageUrl)) {
+            Toast.makeText(this, "图片地址不正确!", Toast.LENGTH_SHORT).show();
+            finish();
+        }
+        Glide.with(this).load(imageUrl).into(photoview);
+    }
+}

+ 12 - 1
app/src/main/java/com/ynstkz/shitu/android/adapter/OrgDetailCommentPicAdapter.java

@@ -1,6 +1,7 @@
 package com.ynstkz.shitu.android.adapter;
 
 import android.content.Context;
+import android.content.Intent;
 import android.view.View;
 import android.widget.ImageView;
 
@@ -8,6 +9,7 @@ import com.bumptech.glide.Glide;
 import com.common.library.adapter.CCAdapterHolder;
 import com.common.library.adapter.CCListAdapter;
 import com.ynstkz.shitu.android.R;
+import com.ynstkz.shitu.android.activity.ImageBrowseActivity;
 import com.ynstkz.shitu.android.bean.EvaluateListBean;
 import com.ynstkz.shitu.android.data.UrlCat;
 
@@ -51,8 +53,17 @@ public class OrgDetailCommentPicAdapter extends CCListAdapter<EvaluateListBean.E
             }
 
             @Override
-            public void updateView(EvaluateListBean.EvaluatePicListBean content, int position) {
+            public void updateView(final EvaluateListBean.EvaluatePicListBean content, int position) {
                 Glide.with(context).load(UrlCat.HOST + content.getPicUrl()).into(orgdetailCommentPic);
+
+                orgdetailCommentPic.setOnClickListener(new View.OnClickListener() {
+                    @Override
+                    public void onClick(View view) {
+                        Intent intent = new Intent(context, ImageBrowseActivity.class);
+                        intent.putExtra("imageUrl", UrlCat.HOST + content.getPicUrl());
+                        context.startActivity(intent);
+                    }
+                });
             }
         };
     }

+ 14 - 0
app/src/main/res/layout/activity_imagebrowse.xml

@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    android:background="@color/black">
+
+    <com.common.library.view.photoview.PhotoView
+        android:id="@+id/photoview"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_centerInParent="true"/>
+
+</RelativeLayout>

+ 59 - 0
library/src/main/java/com/common/library/view/photoview/Compat.java

@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * Copyright 2011, 2012 Chris Banes.
+ *
+ * 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.common.library.view.photoview;
+
+import android.annotation.TargetApi;
+import android.os.Build.VERSION;
+import android.os.Build.VERSION_CODES;
+import android.view.MotionEvent;
+import android.view.View;
+
+public class Compat {
+
+    private static final int SIXTY_FPS_INTERVAL = 1000 / 60;
+
+    public static void postOnAnimation(View view, Runnable runnable) {
+        if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) {
+            postOnAnimationJellyBean(view, runnable);
+        } else {
+            view.postDelayed(runnable, SIXTY_FPS_INTERVAL);
+        }
+    }
+
+    @TargetApi(16)
+    private static void postOnAnimationJellyBean(View view, Runnable runnable) {
+        view.postOnAnimation(runnable);
+    }
+
+    public static int getPointerIndex(int action) {
+        if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB)
+            return getPointerIndexHoneyComb(action);
+        else
+            return getPointerIndexEclair(action);
+    }
+
+    @SuppressWarnings("deprecation")
+    @TargetApi(VERSION_CODES.ECLAIR)
+    private static int getPointerIndexEclair(int action) {
+        return (action & MotionEvent.ACTION_POINTER_ID_MASK) >> MotionEvent.ACTION_POINTER_ID_SHIFT;
+    }
+
+    @TargetApi(VERSION_CODES.HONEYCOMB)
+    private static int getPointerIndexHoneyComb(int action) {
+        return (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
+    }
+
+}

+ 99 - 0
library/src/main/java/com/common/library/view/photoview/DefaultOnDoubleTapListener.java

@@ -0,0 +1,99 @@
+package com.common.library.view.photoview;
+
+import android.graphics.RectF;
+import android.view.GestureDetector;
+import android.view.MotionEvent;
+import android.widget.ImageView;
+
+/**
+ * Provided default implementation of GestureDetector.OnDoubleTapListener, to be overriden with custom behavior, if needed
+ * <p>&nbsp;</p>
+ */
+public class DefaultOnDoubleTapListener implements GestureDetector.OnDoubleTapListener {
+
+    private PhotoViewAttacher photoViewAttacher;
+
+    /**
+     * Default constructor
+     *
+     * @param photoViewAttacher PhotoViewAttacher to bind to
+     */
+    public DefaultOnDoubleTapListener(PhotoViewAttacher photoViewAttacher) {
+        setPhotoViewAttacher(photoViewAttacher);
+    }
+
+    /**
+     * Allows to change PhotoViewAttacher within range of single instance
+     *
+     * @param newPhotoViewAttacher PhotoViewAttacher to bind to
+     */
+    public void setPhotoViewAttacher(PhotoViewAttacher newPhotoViewAttacher) {
+        this.photoViewAttacher = newPhotoViewAttacher;
+    }
+
+    @Override
+    public boolean onSingleTapConfirmed(MotionEvent e) {
+        if (this.photoViewAttacher == null)
+            return false;
+
+        ImageView imageView = photoViewAttacher.getImageView();
+
+        if (null != photoViewAttacher.getOnPhotoTapListener()) {
+            final RectF displayRect = photoViewAttacher.getDisplayRect();
+
+            if (null != displayRect) {
+                final float x = e.getX(), y = e.getY();
+
+                // Check to see if the user tapped on the photo
+                if (displayRect.contains(x, y)) {
+
+                    float xResult = (x - displayRect.left)
+                            / displayRect.width();
+                    float yResult = (y - displayRect.top)
+                            / displayRect.height();
+
+                    photoViewAttacher.getOnPhotoTapListener().onPhotoTap(imageView, xResult, yResult);
+                    return true;
+                }else{
+                    photoViewAttacher.getOnPhotoTapListener().onOutsidePhotoTap();
+                }
+            }
+        }
+        if (null != photoViewAttacher.getOnViewTapListener()) {
+            photoViewAttacher.getOnViewTapListener().onViewTap(imageView, e.getX(), e.getY());
+        }
+
+        return false;
+    }
+
+    @Override
+    public boolean onDoubleTap(MotionEvent ev) {
+        if (photoViewAttacher == null)
+            return false;
+
+        try {
+            float scale = photoViewAttacher.getScale();
+            float x = ev.getX();
+            float y = ev.getY();
+
+            if (scale < photoViewAttacher.getMediumScale()) {
+                photoViewAttacher.setScale(photoViewAttacher.getMediumScale(), x, y, true);
+            } else if (scale >= photoViewAttacher.getMediumScale() && scale < photoViewAttacher.getMaximumScale()) {
+                photoViewAttacher.setScale(photoViewAttacher.getMaximumScale(), x, y, true);
+            } else {
+                photoViewAttacher.setScale(photoViewAttacher.getMinimumScale(), x, y, true);
+            }
+        } catch (ArrayIndexOutOfBoundsException e) {
+            // Can sometimes happen when getX() and getY() is called
+        }
+
+        return true;
+    }
+
+    @Override
+    public boolean onDoubleTapEvent(MotionEvent e) {
+        // Wait for the confirmed onDoubleTap() instead
+        return false;
+    }
+
+}

+ 364 - 0
library/src/main/java/com/common/library/view/photoview/IPhotoView.java

@@ -0,0 +1,364 @@
+/*******************************************************************************
+ * Copyright 2011, 2012 Chris Banes.
+ *
+ * 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.common.library.view.photoview;
+
+import android.graphics.Bitmap;
+import android.graphics.Matrix;
+import android.graphics.RectF;
+import android.view.GestureDetector;
+import android.view.View;
+import android.widget.ImageView;
+
+
+public interface IPhotoView {
+
+    public static final float DEFAULT_MAX_SCALE = 3.0f;
+    public static final float DEFAULT_MID_SCALE = 1.75f;
+    public static final float DEFAULT_MIN_SCALE = 1.0f;
+    public static final int DEFAULT_ZOOM_DURATION = 200;
+
+    /**
+     * Returns true if the PhotoView is set to allow zooming of Photos.
+     *
+     * @return true if the PhotoView allows zooming.
+     */
+    boolean canZoom();
+
+    /**
+     * Gets the Display Rectangle of the currently displayed Drawable. The Rectangle is relative to
+     * this View and includes all scaling and translations.
+     *
+     * @return - RectF of Displayed Drawable
+     */
+    RectF getDisplayRect();
+
+    /**
+     * Sets the Display Matrix of the currently displayed Drawable. The Rectangle is considered
+     * relative to this View and includes all scaling and translations.
+     *
+     * @param finalMatrix target matrix to set PhotoView to
+     * @return - true if rectangle was applied successfully
+     */
+    boolean setDisplayMatrix(Matrix finalMatrix);
+
+    /**
+     * Gets the Display Matrix of the currently displayed Drawable. The Rectangle is considered
+     * relative to this View and includes all scaling and translations.
+     *
+     * @return copy of current Display Matrix
+     */
+    Matrix getDisplayMatrix();
+
+    /**
+     * Copies the Display Matrix of the currently displayed Drawable. The Rectangle is considered
+     * relative to this View and includes all scaling and translations.
+     *
+     * @param matrix target matrix to copy to
+     */
+    void getDisplayMatrix(Matrix matrix);
+
+    /**
+     * Use {@link #getMinimumScale()} instead, this will be removed in future release
+     *
+     * @return The current minimum scale level. What this value represents depends on the current
+     * {@link ImageView.ScaleType}.
+     */
+    @Deprecated
+    float getMinScale();
+
+    /**
+     * @return The current minimum scale level. What this value represents depends on the current
+     * {@link ImageView.ScaleType}.
+     */
+    float getMinimumScale();
+
+    /**
+     * Use {@link #getMediumScale()} instead, this will be removed in future release
+     *
+     * @return The current middle scale level. What this value represents depends on the current
+     * {@link ImageView.ScaleType}.
+     */
+    @Deprecated
+    float getMidScale();
+
+    /**
+     * @return The current medium scale level. What this value represents depends on the current
+     * {@link ImageView.ScaleType}.
+     */
+    float getMediumScale();
+
+    /**
+     * Use {@link #getMaximumScale()} instead, this will be removed in future release
+     *
+     * @return The current maximum scale level. What this value represents depends on the current
+     * {@link ImageView.ScaleType}.
+     */
+    @Deprecated
+    float getMaxScale();
+
+    /**
+     * @return The current maximum scale level. What this value represents depends on the current
+     * {@link ImageView.ScaleType}.
+     */
+    float getMaximumScale();
+
+    /**
+     * Returns the current scale value
+     *
+     * @return float - current scale value
+     */
+    float getScale();
+
+    /**
+     * Return the current scale type in use by the ImageView.
+     *
+     * @return current ImageView.ScaleType
+     */
+    ImageView.ScaleType getScaleType();
+
+    /**
+     * Whether to allow the ImageView's parent to intercept the touch event when the photo is scroll
+     * to it's horizontal edge.
+     *
+     * @param allow whether to allow intercepting by parent element or not
+     */
+    void setAllowParentInterceptOnEdge(boolean allow);
+
+    /**
+     * Use {@link #setMinimumScale(float minimumScale)} instead, this will be removed in future
+     * release
+     * <p>&nbsp;</p>
+     * Sets the minimum scale level. What this value represents depends on the current {@link
+     * ImageView.ScaleType}.
+     *
+     * @param minScale minimum allowed scale
+     */
+    @Deprecated
+    void setMinScale(float minScale);
+
+    /**
+     * Sets the minimum scale level. What this value represents depends on the current {@link
+     * ImageView.ScaleType}.
+     *
+     * @param minimumScale minimum allowed scale
+     */
+    void setMinimumScale(float minimumScale);
+
+    /**
+     * Use {@link #setMediumScale(float mediumScale)} instead, this will be removed in future
+     * release
+     * <p>&nbsp;</p>
+     * Sets the middle scale level. What this value represents depends on the current {@link
+     * ImageView.ScaleType}.
+     *
+     * @param midScale medium scale preset
+     */
+    @Deprecated
+    void setMidScale(float midScale);
+
+    /*
+     * Sets the medium scale level. What this value represents depends on the current {@link android.widget.ImageView.ScaleType}.
+     *
+     * @param mediumScale medium scale preset
+     */
+    void setMediumScale(float mediumScale);
+
+    /**
+     * Use {@link #setMaximumScale(float maximumScale)} instead, this will be removed in future
+     * release
+     * <p>&nbsp;</p>
+     * Sets the maximum scale level. What this value represents depends on the current {@link
+     * ImageView.ScaleType}.
+     *
+     * @param maxScale maximum allowed scale preset
+     */
+    @Deprecated
+    void setMaxScale(float maxScale);
+
+    /**
+     * Sets the maximum scale level. What this value represents depends on the current {@link
+     * ImageView.ScaleType}.
+     *
+     * @param maximumScale maximum allowed scale preset
+     */
+    void setMaximumScale(float maximumScale);
+
+    /**
+     * Allows to set all three scale levels at once, so you don't run into problem with setting
+     * medium/minimum scale before the maximum one
+     *
+     * @param minimumScale minimum allowed scale
+     * @param mediumScale  medium allowed scale
+     * @param maximumScale maximum allowed scale preset
+     */
+    void setScaleLevels(float minimumScale, float mediumScale, float maximumScale);
+
+    /**
+     * Register a callback to be invoked when the Photo displayed by this view is long-pressed.
+     *
+     * @param listener - Listener to be registered.
+     */
+    void setOnLongClickListener(View.OnLongClickListener listener);
+
+    /**
+     * Register a callback to be invoked when the Matrix has changed for this View. An example would
+     * be the user panning or scaling the Photo.
+     *
+     * @param listener - Listener to be registered.
+     */
+    void setOnMatrixChangeListener(PhotoViewAttacher.OnMatrixChangedListener listener);
+
+    /**
+     * Register a callback to be invoked when the Photo displayed by this View is tapped with a
+     * single tap.
+     *
+     * @param listener - Listener to be registered.
+     */
+    void setOnPhotoTapListener(PhotoViewAttacher.OnPhotoTapListener listener);
+
+    /**
+     * Returns a listener to be invoked when the Photo displayed by this View is tapped with a
+     * single tap.
+     *
+     * @return PhotoViewAttacher.OnPhotoTapListener currently set, may be null
+     */
+    PhotoViewAttacher.OnPhotoTapListener getOnPhotoTapListener();
+
+    /**
+     * Register a callback to be invoked when the View is tapped with a single tap.
+     *
+     * @param listener - Listener to be registered.
+     */
+    void setOnViewTapListener(PhotoViewAttacher.OnViewTapListener listener);
+
+    /**
+     * Enables rotation via PhotoView internal functions.
+     *
+     * @param rotationDegree - Degree to rotate PhotoView to, should be in range 0 to 360
+     */
+    void setRotationTo(float rotationDegree);
+
+    /**
+     * Enables rotation via PhotoView internal functions.
+     *
+     * @param rotationDegree - Degree to rotate PhotoView by, should be in range 0 to 360
+     */
+    void setRotationBy(float rotationDegree);
+
+    /**
+     * Returns a callback listener to be invoked when the View is tapped with a single tap.
+     *
+     * @return PhotoViewAttacher.OnViewTapListener currently set, may be null
+     */
+    PhotoViewAttacher.OnViewTapListener getOnViewTapListener();
+
+    /**
+     * Changes the current scale to the specified value.
+     *
+     * @param scale - Value to scale to
+     */
+    void setScale(float scale);
+
+    /**
+     * Changes the current scale to the specified value.
+     *
+     * @param scale   - Value to scale to
+     * @param animate - Whether to animate the scale
+     */
+    void setScale(float scale, boolean animate);
+
+    /**
+     * Changes the current scale to the specified value, around the given focal point.
+     *
+     * @param scale   - Value to scale to
+     * @param focalX  - X Focus Point
+     * @param focalY  - Y Focus Point
+     * @param animate - Whether to animate the scale
+     */
+    void setScale(float scale, float focalX, float focalY, boolean animate);
+
+    /**
+     * Controls how the image should be resized or moved to match the size of the ImageView. Any
+     * scaling or panning will happen within the confines of this {@link
+     * ImageView.ScaleType}.
+     *
+     * @param scaleType - The desired scaling mode.
+     */
+    void setScaleType(ImageView.ScaleType scaleType);
+
+    /**
+     * Allows you to enable/disable the zoom functionality on the ImageView. When disable the
+     * ImageView reverts to using the FIT_CENTER matrix.
+     *
+     * @param zoomable - Whether the zoom functionality is enabled.
+     */
+    void setZoomable(boolean zoomable);
+
+    /**
+     * Enables rotation via PhotoView internal functions. Name is chosen so it won't collide with
+     * View.setRotation(float) in API since 11
+     *
+     * @param rotationDegree - Degree to rotate PhotoView to, should be in range 0 to 360
+     * @deprecated use {@link #setRotationTo(float)}
+     */
+    void setPhotoViewRotation(float rotationDegree);
+
+    /**
+     * Extracts currently visible area to Bitmap object, if there is no image loaded yet or the
+     * ImageView is already destroyed, returns {@code null}
+     *
+     * @return currently visible area as bitmap or null
+     */
+    Bitmap getVisibleRectangleBitmap();
+
+    /**
+     * Allows to change zoom transition speed, default value is 200 (PhotoViewAttacher.DEFAULT_ZOOM_DURATION).
+     * Will default to 200 if provided negative value
+     *
+     * @param milliseconds duration of zoom interpolation
+     */
+    void setZoomTransitionDuration(int milliseconds);
+
+    /**
+     * Will return instance of IPhotoView (eg. PhotoViewAttacher), can be used to provide better
+     * integration
+     *
+     * @return IPhotoView implementation instance if available, null if not
+     */
+    IPhotoView getIPhotoViewImplementation();
+
+    /**
+     * Sets custom double tap listener, to intercept default given functions. To reset behavior to
+     * default, you can just pass in "null" or public field of PhotoViewAttacher.defaultOnDoubleTapListener
+     *
+     * @param newOnDoubleTapListener custom OnDoubleTapListener to be set on ImageView
+     */
+    void setOnDoubleTapListener(GestureDetector.OnDoubleTapListener newOnDoubleTapListener);
+
+    /**
+     * Will report back about scale changes
+     *
+     * @param onScaleChangeListener OnScaleChangeListener instance
+     */
+    void setOnScaleChangeListener(PhotoViewAttacher.OnScaleChangeListener onScaleChangeListener);
+
+    /**
+     * Will report back about fling(single touch)
+     *
+     * @param onSingleFlingListener OnSingleFlingListener instance
+     */
+    void setOnSingleFlingListener(PhotoViewAttacher.OnSingleFlingListener onSingleFlingListener);
+}

+ 313 - 0
library/src/main/java/com/common/library/view/photoview/PhotoView.java

@@ -0,0 +1,313 @@
+/*******************************************************************************
+ * Copyright 2011, 2012 Chris Banes.
+ *
+ * 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.common.library.view.photoview;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Matrix;
+import android.graphics.RectF;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.util.AttributeSet;
+import android.view.GestureDetector;
+import android.widget.ImageView;
+
+public class PhotoView extends ImageView implements IPhotoView {
+
+    private PhotoViewAttacher mAttacher;
+
+    private ScaleType mPendingScaleType;
+
+    public PhotoView(Context context) {
+        this(context, null);
+    }
+
+    public PhotoView(Context context, AttributeSet attr) {
+        this(context, attr, 0);
+    }
+
+    public PhotoView(Context context, AttributeSet attr, int defStyle) {
+        super(context, attr, defStyle);
+        super.setScaleType(ScaleType.MATRIX);
+        init();
+    }
+
+    protected void init() {
+        if (null == mAttacher || null == mAttacher.getImageView()) {
+            mAttacher = new PhotoViewAttacher(this);
+        }
+
+        if (null != mPendingScaleType) {
+            setScaleType(mPendingScaleType);
+            mPendingScaleType = null;
+        }
+    }
+
+    /**
+     * @deprecated use {@link #setRotationTo(float)}
+     */
+    @Override
+    public void setPhotoViewRotation(float rotationDegree) {
+        mAttacher.setRotationTo(rotationDegree);
+    }
+
+    @Override
+    public void setRotationTo(float rotationDegree) {
+        mAttacher.setRotationTo(rotationDegree);
+    }
+
+    @Override
+    public void setRotationBy(float rotationDegree) {
+        mAttacher.setRotationBy(rotationDegree);
+    }
+
+    @Override
+    public boolean canZoom() {
+        return mAttacher.canZoom();
+    }
+
+    @Override
+    public RectF getDisplayRect() {
+        return mAttacher.getDisplayRect();
+    }
+
+    @Override
+    public Matrix getDisplayMatrix() {
+        return mAttacher.getDisplayMatrix();
+    }
+
+    @Override
+    public void getDisplayMatrix(Matrix matrix) {
+        mAttacher.getDisplayMatrix(matrix);
+    }
+
+    @Override
+    public boolean setDisplayMatrix(Matrix finalRectangle) {
+        return mAttacher.setDisplayMatrix(finalRectangle);
+    }
+
+    @Override
+    @Deprecated
+    public float getMinScale() {
+        return getMinimumScale();
+    }
+
+    @Override
+    public float getMinimumScale() {
+        return mAttacher.getMinimumScale();
+    }
+
+    @Override
+    @Deprecated
+    public float getMidScale() {
+        return getMediumScale();
+    }
+
+    @Override
+    public float getMediumScale() {
+        return mAttacher.getMediumScale();
+    }
+
+    @Override
+    @Deprecated
+    public float getMaxScale() {
+        return getMaximumScale();
+    }
+
+    @Override
+    public float getMaximumScale() {
+        return mAttacher.getMaximumScale();
+    }
+
+    @Override
+    public float getScale() {
+        return mAttacher.getScale();
+    }
+
+    @Override
+    public ScaleType getScaleType() {
+        return mAttacher.getScaleType();
+    }
+
+    @Override
+    public void setAllowParentInterceptOnEdge(boolean allow) {
+        mAttacher.setAllowParentInterceptOnEdge(allow);
+    }
+
+    @Override
+    @Deprecated
+    public void setMinScale(float minScale) {
+        setMinimumScale(minScale);
+    }
+
+    @Override
+    public void setMinimumScale(float minimumScale) {
+        mAttacher.setMinimumScale(minimumScale);
+    }
+
+    @Override
+    @Deprecated
+    public void setMidScale(float midScale) {
+        setMediumScale(midScale);
+    }
+
+    @Override
+    public void setMediumScale(float mediumScale) {
+        mAttacher.setMediumScale(mediumScale);
+    }
+
+    @Override
+    @Deprecated
+    public void setMaxScale(float maxScale) {
+        setMaximumScale(maxScale);
+    }
+
+    @Override
+    public void setMaximumScale(float maximumScale) {
+        mAttacher.setMaximumScale(maximumScale);
+    }
+
+    @Override
+    public void setScaleLevels(float minimumScale, float mediumScale, float maximumScale) {
+        mAttacher.setScaleLevels(minimumScale, mediumScale, maximumScale);
+    }
+
+    @Override
+    // setImageBitmap calls through to this method
+    public void setImageDrawable(Drawable drawable) {
+        super.setImageDrawable(drawable);
+        if (null != mAttacher) {
+            mAttacher.update();
+        }
+    }
+
+    @Override
+    public void setImageResource(int resId) {
+        super.setImageResource(resId);
+        if (null != mAttacher) {
+            mAttacher.update();
+        }
+    }
+
+    @Override
+    public void setImageURI(Uri uri) {
+        super.setImageURI(uri);
+        if (null != mAttacher) {
+            mAttacher.update();
+        }
+    }
+
+    @Override
+    public void setOnMatrixChangeListener(PhotoViewAttacher.OnMatrixChangedListener listener) {
+        mAttacher.setOnMatrixChangeListener(listener);
+    }
+
+    @Override
+    public void setOnLongClickListener(OnLongClickListener l) {
+        mAttacher.setOnLongClickListener(l);
+    }
+
+    @Override
+    public void setOnPhotoTapListener(PhotoViewAttacher.OnPhotoTapListener listener) {
+        mAttacher.setOnPhotoTapListener(listener);
+    }
+
+    @Override
+    public PhotoViewAttacher.OnPhotoTapListener getOnPhotoTapListener() {
+        return mAttacher.getOnPhotoTapListener();
+    }
+
+    @Override
+    public void setOnViewTapListener(PhotoViewAttacher.OnViewTapListener listener) {
+        mAttacher.setOnViewTapListener(listener);
+    }
+
+    @Override
+    public PhotoViewAttacher.OnViewTapListener getOnViewTapListener() {
+        return mAttacher.getOnViewTapListener();
+    }
+
+    @Override
+    public void setScale(float scale) {
+        mAttacher.setScale(scale);
+    }
+
+    @Override
+    public void setScale(float scale, boolean animate) {
+        mAttacher.setScale(scale, animate);
+    }
+
+    @Override
+    public void setScale(float scale, float focalX, float focalY, boolean animate) {
+        mAttacher.setScale(scale, focalX, focalY, animate);
+    }
+
+    @Override
+    public void setScaleType(ScaleType scaleType) {
+        if (null != mAttacher) {
+            mAttacher.setScaleType(scaleType);
+        } else {
+            mPendingScaleType = scaleType;
+        }
+    }
+
+    @Override
+    public void setZoomable(boolean zoomable) {
+        mAttacher.setZoomable(zoomable);
+    }
+
+    @Override
+    public Bitmap getVisibleRectangleBitmap() {
+        return mAttacher.getVisibleRectangleBitmap();
+    }
+
+    @Override
+    public void setZoomTransitionDuration(int milliseconds) {
+        mAttacher.setZoomTransitionDuration(milliseconds);
+    }
+
+    @Override
+    public IPhotoView getIPhotoViewImplementation() {
+        return mAttacher;
+    }
+
+    @Override
+    public void setOnDoubleTapListener(GestureDetector.OnDoubleTapListener newOnDoubleTapListener) {
+        mAttacher.setOnDoubleTapListener(newOnDoubleTapListener);
+    }
+
+    @Override
+    public void setOnScaleChangeListener(PhotoViewAttacher.OnScaleChangeListener onScaleChangeListener) {
+        mAttacher.setOnScaleChangeListener(onScaleChangeListener);
+    }
+
+    @Override
+    public void setOnSingleFlingListener(PhotoViewAttacher.OnSingleFlingListener onSingleFlingListener) {
+        mAttacher.setOnSingleFlingListener(onSingleFlingListener);
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        mAttacher.cleanup();
+        super.onDetachedFromWindow();
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        init();
+        super.onAttachedToWindow();
+    }
+}

Dosya farkı çok büyük olduğundan ihmal edildi
+ 1213 - 0
library/src/main/java/com/common/library/view/photoview/PhotoViewAttacher.java


+ 147 - 0
library/src/main/java/com/common/library/view/photoview/gestures/CupcakeGestureDetector.java

@@ -0,0 +1,147 @@
+/*******************************************************************************
+ * Copyright 2011, 2012 Chris Banes.
+ *
+ * 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.common.library.view.photoview.gestures;
+
+import android.content.Context;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+import android.view.ViewConfiguration;
+
+import com.common.library.view.photoview.log.LogManager;
+
+public class CupcakeGestureDetector implements GestureDetector {
+
+    protected OnGestureListener mListener;
+    private static final String LOG_TAG = "CupcakeGestureDetector";
+    float mLastTouchX;
+    float mLastTouchY;
+    final float mTouchSlop;
+    final float mMinimumVelocity;
+
+    @Override
+    public void setOnGestureListener(OnGestureListener listener) {
+        this.mListener = listener;
+    }
+
+    public CupcakeGestureDetector(Context context) {
+        final ViewConfiguration configuration = ViewConfiguration
+                .get(context);
+        mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
+        mTouchSlop = configuration.getScaledTouchSlop();
+    }
+
+    private VelocityTracker mVelocityTracker;
+    private boolean mIsDragging;
+
+    float getActiveX(MotionEvent ev) {
+        return ev.getX();
+    }
+
+    float getActiveY(MotionEvent ev) {
+        return ev.getY();
+    }
+
+    public boolean isScaling() {
+        return false;
+    }
+
+    public boolean isDragging() {
+        return mIsDragging;
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        switch (ev.getAction()) {
+            case MotionEvent.ACTION_DOWN: {
+                mVelocityTracker = VelocityTracker.obtain();
+                if (null != mVelocityTracker) {
+                    mVelocityTracker.addMovement(ev);
+                } else {
+                    LogManager.getLogger().i(LOG_TAG, "Velocity tracker is null");
+                }
+
+                mLastTouchX = getActiveX(ev);
+                mLastTouchY = getActiveY(ev);
+                mIsDragging = false;
+                break;
+            }
+
+            case MotionEvent.ACTION_MOVE: {
+                final float x = getActiveX(ev);
+                final float y = getActiveY(ev);
+                final float dx = x - mLastTouchX, dy = y - mLastTouchY;
+
+                if (!mIsDragging) {
+                    // Use Pythagoras to see if drag length is larger than
+                    // touch slop
+                    mIsDragging = Math.sqrt((dx * dx) + (dy * dy)) >= mTouchSlop;
+                }
+
+                if (mIsDragging) {
+                    mListener.onDrag(dx, dy);
+                    mLastTouchX = x;
+                    mLastTouchY = y;
+
+                    if (null != mVelocityTracker) {
+                        mVelocityTracker.addMovement(ev);
+                    }
+                }
+                break;
+            }
+
+            case MotionEvent.ACTION_CANCEL: {
+                // Recycle Velocity Tracker
+                if (null != mVelocityTracker) {
+                    mVelocityTracker.recycle();
+                    mVelocityTracker = null;
+                }
+                break;
+            }
+
+            case MotionEvent.ACTION_UP: {
+                if (mIsDragging) {
+                    if (null != mVelocityTracker) {
+                        mLastTouchX = getActiveX(ev);
+                        mLastTouchY = getActiveY(ev);
+
+                        // Compute velocity within the last 1000ms
+                        mVelocityTracker.addMovement(ev);
+                        mVelocityTracker.computeCurrentVelocity(1000);
+
+                        final float vX = mVelocityTracker.getXVelocity(), vY = mVelocityTracker
+                                .getYVelocity();
+
+                        // If the velocity is greater than minVelocity, call
+                        // listener
+                        if (Math.max(Math.abs(vX), Math.abs(vY)) >= mMinimumVelocity) {
+                            mListener.onFling(mLastTouchX, mLastTouchY, -vX,
+                                    -vY);
+                        }
+                    }
+                }
+
+                // Recycle Velocity Tracker
+                if (null != mVelocityTracker) {
+                    mVelocityTracker.recycle();
+                    mVelocityTracker = null;
+                }
+                break;
+            }
+        }
+
+        return true;
+    }
+}

+ 91 - 0
library/src/main/java/com/common/library/view/photoview/gestures/EclairGestureDetector.java

@@ -0,0 +1,91 @@
+/*******************************************************************************
+ * Copyright 2011, 2012 Chris Banes.
+ * <p/>
+ * 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
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * 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.common.library.view.photoview.gestures;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.view.MotionEvent;
+
+import com.common.library.view.photoview.Compat;
+
+@TargetApi(5)
+public class EclairGestureDetector extends CupcakeGestureDetector {
+
+    private static final int INVALID_POINTER_ID = -1;
+    private int mActivePointerId = INVALID_POINTER_ID;
+    private int mActivePointerIndex = 0;
+
+    public EclairGestureDetector(Context context) {
+        super(context);
+    }
+
+    @Override
+    float getActiveX(MotionEvent ev) {
+        try {
+            return ev.getX(mActivePointerIndex);
+        } catch (Exception e) {
+            return ev.getX();
+        }
+    }
+
+    @Override
+    float getActiveY(MotionEvent ev) {
+        try {
+            return ev.getY(mActivePointerIndex);
+        } catch (Exception e) {
+            return ev.getY();
+        }
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        final int action = ev.getAction();
+        switch (action & MotionEvent.ACTION_MASK) {
+            case MotionEvent.ACTION_DOWN:
+                mActivePointerId = ev.getPointerId(0);
+                break;
+            case MotionEvent.ACTION_CANCEL:
+            case MotionEvent.ACTION_UP:
+                mActivePointerId = INVALID_POINTER_ID;
+                break;
+            case MotionEvent.ACTION_POINTER_UP:
+                // Ignore deprecation, ACTION_POINTER_ID_MASK and
+                // ACTION_POINTER_ID_SHIFT has same value and are deprecated
+                // You can have either deprecation or lint target api warning
+                final int pointerIndex = Compat.getPointerIndex(ev.getAction());
+                final int pointerId = ev.getPointerId(pointerIndex);
+                if (pointerId == mActivePointerId) {
+                    // This was our active pointer going up. Choose a new
+                    // active pointer and adjust accordingly.
+                    final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
+                    mActivePointerId = ev.getPointerId(newPointerIndex);
+                    mLastTouchX = ev.getX(newPointerIndex);
+                    mLastTouchY = ev.getY(newPointerIndex);
+                }
+                break;
+        }
+
+        mActivePointerIndex = ev
+                .findPointerIndex(mActivePointerId != INVALID_POINTER_ID ? mActivePointerId
+                        : 0);
+        try {
+            return super.onTouchEvent(ev);
+        } catch (IllegalArgumentException e) {
+            // Fix for support lib bug, happening when onDestroy is
+            return true;
+        }
+    }
+}

+ 72 - 0
library/src/main/java/com/common/library/view/photoview/gestures/FroyoGestureDetector.java

@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * Copyright 2011, 2012 Chris Banes.
+ * <p/>
+ * 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
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * 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.common.library.view.photoview.gestures;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.view.MotionEvent;
+import android.view.ScaleGestureDetector;
+
+@TargetApi(8)
+public class FroyoGestureDetector extends EclairGestureDetector {
+
+    protected final ScaleGestureDetector mDetector;
+
+    public FroyoGestureDetector(Context context) {
+        super(context);
+        ScaleGestureDetector.OnScaleGestureListener mScaleListener = new ScaleGestureDetector.OnScaleGestureListener() {
+
+            @Override
+            public boolean onScale(ScaleGestureDetector detector) {
+                float scaleFactor = detector.getScaleFactor();
+
+                if (Float.isNaN(scaleFactor) || Float.isInfinite(scaleFactor))
+                    return false;
+
+                mListener.onScale(scaleFactor,
+                        detector.getFocusX(), detector.getFocusY());
+                return true;
+            }
+
+            @Override
+            public boolean onScaleBegin(ScaleGestureDetector detector) {
+                return true;
+            }
+
+            @Override
+            public void onScaleEnd(ScaleGestureDetector detector) {
+                // NO-OP
+            }
+        };
+        mDetector = new ScaleGestureDetector(context, mScaleListener);
+    }
+
+    @Override
+    public boolean isScaling() {
+        return mDetector.isInProgress();
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        try {
+            mDetector.onTouchEvent(ev);
+            return super.onTouchEvent(ev);
+        } catch (IllegalArgumentException e) {
+            // Fix for support lib bug, happening when onDestroy is
+            return true;
+        }
+    }
+}

+ 30 - 0
library/src/main/java/com/common/library/view/photoview/gestures/GestureDetector.java

@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright 2011, 2012 Chris Banes.
+ *
+ * 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.common.library.view.photoview.gestures;
+
+import android.view.MotionEvent;
+
+public interface GestureDetector {
+
+    public boolean onTouchEvent(MotionEvent ev);
+
+    public boolean isScaling();
+
+    public boolean isDragging();
+
+    public void setOnGestureListener(OnGestureListener listener);
+
+}

+ 27 - 0
library/src/main/java/com/common/library/view/photoview/gestures/OnGestureListener.java

@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright 2011, 2012 Chris Banes.
+ *
+ * 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.common.library.view.photoview.gestures;
+
+public interface OnGestureListener {
+
+    public void onDrag(float dx, float dy);
+
+    public void onFling(float startX, float startY, float velocityX,
+                        float velocityY);
+
+    public void onScale(float scaleFactor, float focusX, float focusY);
+
+}

+ 42 - 0
library/src/main/java/com/common/library/view/photoview/gestures/VersionedGestureDetector.java

@@ -0,0 +1,42 @@
+package com.common.library.view.photoview.gestures;
+
+/*******************************************************************************
+ * Copyright 2011, 2012 Chris Banes.
+ *
+ * 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.
+ *******************************************************************************/
+
+import android.content.Context;
+import android.os.Build;
+
+public final class VersionedGestureDetector {
+
+    public static GestureDetector newInstance(Context context,
+                                              OnGestureListener listener) {
+        final int sdkVersion = Build.VERSION.SDK_INT;
+        GestureDetector detector;
+
+        if (sdkVersion < Build.VERSION_CODES.ECLAIR) {
+            detector = new CupcakeGestureDetector(context);
+        } else if (sdkVersion < Build.VERSION_CODES.FROYO) {
+            detector = new EclairGestureDetector(context);
+        } else {
+            detector = new FroyoGestureDetector(context);
+        }
+
+        detector.setOnGestureListener(listener);
+
+        return detector;
+    }
+
+}

+ 35 - 0
library/src/main/java/com/common/library/view/photoview/log/LogManager.java

@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright 2011, 2012 Chris Banes.
+ *
+ * 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.common.library.view.photoview.log;
+
+import android.util.Log;
+
+/**
+ * class that holds the {@link Logger} for this library, defaults to {@link LoggerDefault} to send logs to android {@link Log}
+ */
+public final class LogManager {
+
+    private static Logger logger = new LoggerDefault();
+
+    public static void setLogger(Logger newLogger) {
+        logger = newLogger;
+    }
+
+    public static Logger getLogger() {
+        return logger;
+    }
+
+}

+ 42 - 0
library/src/main/java/com/common/library/view/photoview/log/Logger.java

@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright 2011, 2012 Chris Banes.
+ *
+ * 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.common.library.view.photoview.log;
+
+/**
+ * interface for a logger class to replace the static calls to {@link android.util.Log}
+ */
+public interface Logger {
+
+    int v(String tag, String msg);
+
+    int v(String tag, String msg, Throwable tr);
+
+    int d(String tag, String msg);
+
+    int d(String tag, String msg, Throwable tr);
+
+    int i(String tag, String msg);
+
+    int i(String tag, String msg, Throwable tr);
+
+    int w(String tag, String msg);
+
+    int w(String tag, String msg, Throwable tr);
+
+    int e(String tag, String msg);
+
+    int e(String tag, String msg, Throwable tr);
+}

+ 76 - 0
library/src/main/java/com/common/library/view/photoview/log/LoggerDefault.java

@@ -0,0 +1,76 @@
+/*******************************************************************************
+ * Copyright 2011, 2012 Chris Banes.
+ *
+ * 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.common.library.view.photoview.log;
+
+import android.util.Log;
+
+/**
+ * Helper class to redirect {@link LogManager#logger} to {@link Log}
+ */
+public class LoggerDefault implements Logger {
+
+    @Override
+    public int v(String tag, String msg) {
+        return Log.v(tag, msg);
+    }
+
+    @Override
+    public int v(String tag, String msg, Throwable tr) {
+        return Log.v(tag, msg, tr);
+    }
+
+    @Override
+    public int d(String tag, String msg) {
+        return Log.d(tag, msg);
+    }
+
+    @Override
+    public int d(String tag, String msg, Throwable tr) {
+        return Log.d(tag, msg, tr);
+    }
+
+    @Override
+    public int i(String tag, String msg) {
+        return Log.i(tag, msg);
+    }
+
+    @Override
+    public int i(String tag, String msg, Throwable tr) {
+        return Log.i(tag, msg, tr);
+    }
+
+    @Override
+    public int w(String tag, String msg) {
+        return Log.w(tag, msg);
+    }
+
+    @Override
+    public int w(String tag, String msg, Throwable tr) {
+        return Log.w(tag, msg, tr);
+    }
+
+    @Override
+    public int e(String tag, String msg) {
+        return Log.e(tag, msg);
+    }
+
+    @Override
+    public int e(String tag, String msg, Throwable tr) {
+        return Log.e(tag, msg, tr);
+    }
+
+
+}

+ 68 - 0
library/src/main/java/com/common/library/view/photoview/scrollerproxy/GingerScroller.java

@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * Copyright 2011, 2012 Chris Banes.
+ *
+ * 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.common.library.view.photoview.scrollerproxy;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.widget.OverScroller;
+
+@TargetApi(9)
+public class GingerScroller extends ScrollerProxy {
+
+    protected final OverScroller mScroller;
+    private boolean mFirstScroll = false;
+
+    public GingerScroller(Context context) {
+        mScroller = new OverScroller(context);
+    }
+
+    @Override
+    public boolean computeScrollOffset() {
+        // Workaround for first scroll returning 0 for the direction of the edge it hits.
+        // Simply recompute values.
+        if (mFirstScroll) {
+            mScroller.computeScrollOffset();
+            mFirstScroll = false;
+        }
+        return mScroller.computeScrollOffset();
+    }
+
+    @Override
+    public void fling(int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY, int maxY,
+                      int overX, int overY) {
+        mScroller.fling(startX, startY, velocityX, velocityY, minX, maxX, minY, maxY, overX, overY);
+    }
+
+    @Override
+    public void forceFinished(boolean finished) {
+        mScroller.forceFinished(finished);
+    }
+
+    @Override
+    public boolean isFinished() {
+        return mScroller.isFinished();
+    }
+
+    @Override
+    public int getCurrX() {
+        return mScroller.getCurrX();
+    }
+
+    @Override
+    public int getCurrY() {
+        return mScroller.getCurrY();
+    }
+}

+ 33 - 0
library/src/main/java/com/common/library/view/photoview/scrollerproxy/IcsScroller.java

@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright 2011, 2012 Chris Banes.
+ *
+ * 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.common.library.view.photoview.scrollerproxy;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+
+@TargetApi(14)
+public class IcsScroller extends GingerScroller {
+
+    public IcsScroller(Context context) {
+        super(context);
+    }
+
+    @Override
+    public boolean computeScrollOffset() {
+        return mScroller.computeScrollOffset();
+    }
+
+}

+ 58 - 0
library/src/main/java/com/common/library/view/photoview/scrollerproxy/PreGingerScroller.java

@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright 2011, 2012 Chris Banes.
+ *
+ * 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.common.library.view.photoview.scrollerproxy;
+
+import android.content.Context;
+import android.widget.Scroller;
+
+public class PreGingerScroller extends ScrollerProxy {
+
+    private final Scroller mScroller;
+
+    public PreGingerScroller(Context context) {
+        mScroller = new Scroller(context);
+    }
+
+    @Override
+    public boolean computeScrollOffset() {
+        return mScroller.computeScrollOffset();
+    }
+
+    @Override
+    public void fling(int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY, int maxY,
+                      int overX, int overY) {
+        mScroller.fling(startX, startY, velocityX, velocityY, minX, maxX, minY, maxY);
+    }
+
+    @Override
+    public void forceFinished(boolean finished) {
+        mScroller.forceFinished(finished);
+    }
+
+    public boolean isFinished() {
+        return mScroller.isFinished();
+    }
+
+    @Override
+    public int getCurrX() {
+        return mScroller.getCurrX();
+    }
+
+    @Override
+    public int getCurrY() {
+        return mScroller.getCurrY();
+    }
+}

+ 48 - 0
library/src/main/java/com/common/library/view/photoview/scrollerproxy/ScrollerProxy.java

@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright 2011, 2012 Chris Banes.
+ *
+ * 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.common.library.view.photoview.scrollerproxy;
+
+import android.content.Context;
+import android.os.Build.VERSION;
+import android.os.Build.VERSION_CODES;
+
+public abstract class ScrollerProxy {
+
+    public static ScrollerProxy getScroller(Context context) {
+        if (VERSION.SDK_INT < VERSION_CODES.GINGERBREAD) {
+            return new PreGingerScroller(context);
+        } else if (VERSION.SDK_INT < VERSION_CODES.ICE_CREAM_SANDWICH) {
+            return new GingerScroller(context);
+        } else {
+            return new IcsScroller(context);
+        }
+    }
+
+    public abstract boolean computeScrollOffset();
+
+    public abstract void fling(int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY,
+                               int maxY, int overX, int overY);
+
+    public abstract void forceFinished(boolean finished);
+
+    public abstract boolean isFinished();
+
+    public abstract int getCurrX();
+
+    public abstract int getCurrY();
+
+
+}