diff --git a/.gradle/2.8/taskArtifacts/cache.properties.lock b/.gradle/2.8/taskArtifacts/cache.properties.lock index 7d9072d..bb5a154 100644 Binary files a/.gradle/2.8/taskArtifacts/cache.properties.lock and b/.gradle/2.8/taskArtifacts/cache.properties.lock differ diff --git a/.gradle/2.8/taskArtifacts/fileHashes.bin b/.gradle/2.8/taskArtifacts/fileHashes.bin index bbc7beb..7b8dc50 100644 Binary files a/.gradle/2.8/taskArtifacts/fileHashes.bin and b/.gradle/2.8/taskArtifacts/fileHashes.bin differ diff --git a/.gradle/2.8/taskArtifacts/fileSnapshots.bin b/.gradle/2.8/taskArtifacts/fileSnapshots.bin index f0e9285..9c0655b 100644 Binary files a/.gradle/2.8/taskArtifacts/fileSnapshots.bin and b/.gradle/2.8/taskArtifacts/fileSnapshots.bin differ diff --git a/.gradle/2.8/taskArtifacts/outputFileStates.bin b/.gradle/2.8/taskArtifacts/outputFileStates.bin index 6d516a1..e7576eb 100644 Binary files a/.gradle/2.8/taskArtifacts/outputFileStates.bin and b/.gradle/2.8/taskArtifacts/outputFileStates.bin differ diff --git a/.gradle/2.8/taskArtifacts/taskArtifacts.bin b/.gradle/2.8/taskArtifacts/taskArtifacts.bin index c457f2e..56016ad 100644 Binary files a/.gradle/2.8/taskArtifacts/taskArtifacts.bin and b/.gradle/2.8/taskArtifacts/taskArtifacts.bin differ diff --git a/.idea/gradle.xml b/.idea/gradle.xml index e046e46..7a5d518 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -10,6 +10,7 @@ diff --git a/.idea/modules.xml b/.idea/modules.xml index a094de9..c748180 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -4,6 +4,7 @@ + diff --git a/.idea/workspace.xml b/.idea/workspace.xml index cf7a959..4813806 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -6,7 +6,6 @@ - @@ -25,115 +24,47 @@ + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - + + - - - - + + - - + + + + + + + + + + + + - + @@ -165,6 +96,10 @@ @@ -522,6 +457,10 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1713,6 +2197,11 @@ + + + + + + + @@ -2276,10 +2852,17 @@ @@ -2287,7 +2870,7 @@ - @@ -2928,17 +3235,17 @@ - + - + - + @@ -2952,8 +3259,8 @@ - - + + @@ -2971,11 +3278,11 @@ - + - + @@ -2991,7 +3298,7 @@ - + @@ -3010,199 +3317,25 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -3221,6 +3354,7 @@ + @@ -3267,13 +3401,6 @@ - - - - - - - @@ -3478,22 +3605,6 @@ - - - - - - - - - - - - - - - - @@ -3598,27 +3709,10 @@ - + - - - - - - - - - - - - - - - - - - - + + @@ -3633,8 +3727,8 @@ - - + + @@ -3645,41 +3739,147 @@ - + - + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - - + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Android-Pdf-Viewer-Library.iml b/Android-Pdf-Viewer-Library.iml index e6b0607..a8f705a 100644 --- a/Android-Pdf-Viewer-Library.iml +++ b/Android-Pdf-Viewer-Library.iml @@ -8,7 +8,7 @@ - + diff --git a/PdfView/PdfView.iml b/PdfView/PdfView.iml index e76329a..85ebbf7 100644 --- a/PdfView/PdfView.iml +++ b/PdfView/PdfView.iml @@ -80,5 +80,6 @@ + \ No newline at end of file diff --git a/PdfView/build.gradle b/PdfView/build.gradle index f75faa9..fef3f0b 100644 --- a/PdfView/build.gradle +++ b/PdfView/build.gradle @@ -1,18 +1,21 @@ apply plugin: 'com.android.library' - android { - compileSdkVersion 21 - buildToolsVersion "23.0.2" + compileSdkVersion 21 + buildToolsVersion "23.0.2" - defaultConfig { - minSdkVersion 4 - targetSdkVersion 4 - } - - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' + defaultConfig { + minSdkVersion 14 + targetSdkVersion 4 + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' + } } - } } + +dependencies { + compile project(':gestureimageview') +} \ No newline at end of file diff --git a/PdfView/build/intermediates/bundles/release/AndroidManifest.xml b/PdfView/build/intermediates/bundles/release/AndroidManifest.xml index ecd6cca..59c9e3a 100644 --- a/PdfView/build/intermediates/bundles/release/AndroidManifest.xml +++ b/PdfView/build/intermediates/bundles/release/AndroidManifest.xml @@ -5,7 +5,7 @@ android:versionName="1.0" > diff --git a/PdfView/build/intermediates/bundles/release/aapt/AndroidManifest.xml b/PdfView/build/intermediates/bundles/release/aapt/AndroidManifest.xml index ecd6cca..59c9e3a 100644 --- a/PdfView/build/intermediates/bundles/release/aapt/AndroidManifest.xml +++ b/PdfView/build/intermediates/bundles/release/aapt/AndroidManifest.xml @@ -5,7 +5,7 @@ android:versionName="1.0" > diff --git a/PdfView/build/intermediates/bundles/release/classes.jar b/PdfView/build/intermediates/bundles/release/classes.jar index 105662e..780e726 100644 Binary files a/PdfView/build/intermediates/bundles/release/classes.jar and b/PdfView/build/intermediates/bundles/release/classes.jar differ diff --git a/PdfView/build/intermediates/classes/release/net/sf/andpdf/pdfviewer/gui/PdfView$1.class b/PdfView/build/intermediates/classes/release/net/sf/andpdf/pdfviewer/gui/PdfView$1.class index a80b68c..8f10343 100644 Binary files a/PdfView/build/intermediates/classes/release/net/sf/andpdf/pdfviewer/gui/PdfView$1.class and b/PdfView/build/intermediates/classes/release/net/sf/andpdf/pdfviewer/gui/PdfView$1.class differ diff --git a/PdfView/build/intermediates/classes/release/net/sf/andpdf/pdfviewer/gui/PdfView$2.class b/PdfView/build/intermediates/classes/release/net/sf/andpdf/pdfviewer/gui/PdfView$2.class index 91b685a..4f49bbe 100644 Binary files a/PdfView/build/intermediates/classes/release/net/sf/andpdf/pdfviewer/gui/PdfView$2.class and b/PdfView/build/intermediates/classes/release/net/sf/andpdf/pdfviewer/gui/PdfView$2.class differ diff --git a/PdfView/build/intermediates/classes/release/net/sf/andpdf/pdfviewer/gui/PdfView$3.class b/PdfView/build/intermediates/classes/release/net/sf/andpdf/pdfviewer/gui/PdfView$3.class index 124fc60..24369f9 100644 Binary files a/PdfView/build/intermediates/classes/release/net/sf/andpdf/pdfviewer/gui/PdfView$3.class and b/PdfView/build/intermediates/classes/release/net/sf/andpdf/pdfviewer/gui/PdfView$3.class differ diff --git a/PdfView/build/intermediates/classes/release/net/sf/andpdf/pdfviewer/gui/PdfView.class b/PdfView/build/intermediates/classes/release/net/sf/andpdf/pdfviewer/gui/PdfView.class index 819954a..e3f30d6 100644 Binary files a/PdfView/build/intermediates/classes/release/net/sf/andpdf/pdfviewer/gui/PdfView.class and b/PdfView/build/intermediates/classes/release/net/sf/andpdf/pdfviewer/gui/PdfView.class differ diff --git a/PdfView/build/intermediates/classes/release/net/sf/andpdf/utils/MathUtils.class b/PdfView/build/intermediates/classes/release/net/sf/andpdf/utils/MathUtils.class new file mode 100644 index 0000000..7c2611c Binary files /dev/null and b/PdfView/build/intermediates/classes/release/net/sf/andpdf/utils/MathUtils.class differ diff --git a/PdfView/build/intermediates/classes/release/net/sf/andpdf/utils/VectorF.class b/PdfView/build/intermediates/classes/release/net/sf/andpdf/utils/VectorF.class new file mode 100644 index 0000000..ec490d0 Binary files /dev/null and b/PdfView/build/intermediates/classes/release/net/sf/andpdf/utils/VectorF.class differ diff --git a/PdfView/build/intermediates/exploded-aar/Android-Pdf-Viewer-Library/gestureimageview/unspecified/AndroidManifest.xml b/PdfView/build/intermediates/exploded-aar/Android-Pdf-Viewer-Library/gestureimageview/unspecified/AndroidManifest.xml new file mode 100644 index 0000000..a4e05e6 --- /dev/null +++ b/PdfView/build/intermediates/exploded-aar/Android-Pdf-Viewer-Library/gestureimageview/unspecified/AndroidManifest.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/PdfView/build/intermediates/exploded-aar/Android-Pdf-Viewer-Library/gestureimageview/unspecified/aapt/AndroidManifest.xml b/PdfView/build/intermediates/exploded-aar/Android-Pdf-Viewer-Library/gestureimageview/unspecified/aapt/AndroidManifest.xml new file mode 100644 index 0000000..a4e05e6 --- /dev/null +++ b/PdfView/build/intermediates/exploded-aar/Android-Pdf-Viewer-Library/gestureimageview/unspecified/aapt/AndroidManifest.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/PdfView/build/intermediates/exploded-aar/Android-Pdf-Viewer-Library/gestureimageview/unspecified/jars/classes.jar b/PdfView/build/intermediates/exploded-aar/Android-Pdf-Viewer-Library/gestureimageview/unspecified/jars/classes.jar new file mode 100644 index 0000000..8662373 Binary files /dev/null and b/PdfView/build/intermediates/exploded-aar/Android-Pdf-Viewer-Library/gestureimageview/unspecified/jars/classes.jar differ diff --git a/PdfView/build/intermediates/incremental/mergeResourcesrelease/merger.xml b/PdfView/build/intermediates/incremental/mergeResourcesrelease/merger.xml new file mode 100644 index 0000000..4156877 --- /dev/null +++ b/PdfView/build/intermediates/incremental/mergeResourcesrelease/merger.xml @@ -0,0 +1,2 @@ + +#9370DB#FFFFFFFF#000000#000000FFHello World, PdfViewerActivity!PdfViewer \ No newline at end of file diff --git a/PdfView/build/intermediates/res/merged/release/anim/slide_in.xml b/PdfView/build/intermediates/res/merged/release/anim/slide_in.xml new file mode 100644 index 0000000..425217b --- /dev/null +++ b/PdfView/build/intermediates/res/merged/release/anim/slide_in.xml @@ -0,0 +1,28 @@ + + + + + + + + \ No newline at end of file diff --git a/PdfView/build/intermediates/res/merged/release/anim/slide_out.xml b/PdfView/build/intermediates/res/merged/release/anim/slide_out.xml new file mode 100644 index 0000000..1569072 --- /dev/null +++ b/PdfView/build/intermediates/res/merged/release/anim/slide_out.xml @@ -0,0 +1,28 @@ + + + + + + + + \ No newline at end of file diff --git a/PdfView/build/intermediates/res/merged/release/drawable-hdpi/icon.png b/PdfView/build/intermediates/res/merged/release/drawable-hdpi/icon.png new file mode 100644 index 0000000..882eb14 Binary files /dev/null and b/PdfView/build/intermediates/res/merged/release/drawable-hdpi/icon.png differ diff --git a/PdfView/build/intermediates/res/merged/release/drawable-ldpi/icon.png b/PdfView/build/intermediates/res/merged/release/drawable-ldpi/icon.png new file mode 100644 index 0000000..18689f6 Binary files /dev/null and b/PdfView/build/intermediates/res/merged/release/drawable-ldpi/icon.png differ diff --git a/PdfView/build/intermediates/res/merged/release/drawable-mdpi/icon.png b/PdfView/build/intermediates/res/merged/release/drawable-mdpi/icon.png new file mode 100644 index 0000000..02e96b9 Binary files /dev/null and b/PdfView/build/intermediates/res/merged/release/drawable-mdpi/icon.png differ diff --git a/PdfView/build/intermediates/res/merged/release/drawable/back01.png b/PdfView/build/intermediates/res/merged/release/drawable/back01.png new file mode 100644 index 0000000..cfc029b Binary files /dev/null and b/PdfView/build/intermediates/res/merged/release/drawable/back01.png differ diff --git a/PdfView/build/intermediates/res/merged/release/drawable/back02.png b/PdfView/build/intermediates/res/merged/release/drawable/back02.png new file mode 100644 index 0000000..7a3b8c1 Binary files /dev/null and b/PdfView/build/intermediates/res/merged/release/drawable/back02.png differ diff --git a/PdfView/build/intermediates/res/merged/release/drawable/doc.png b/PdfView/build/intermediates/res/merged/release/drawable/doc.png new file mode 100644 index 0000000..42d8213 Binary files /dev/null and b/PdfView/build/intermediates/res/merged/release/drawable/doc.png differ diff --git a/PdfView/build/intermediates/res/merged/release/drawable/folder.png b/PdfView/build/intermediates/res/merged/release/drawable/folder.png new file mode 100644 index 0000000..13b0189 Binary files /dev/null and b/PdfView/build/intermediates/res/merged/release/drawable/folder.png differ diff --git a/PdfView/build/intermediates/res/merged/release/drawable/icon.png b/PdfView/build/intermediates/res/merged/release/drawable/icon.png new file mode 100644 index 0000000..3285856 Binary files /dev/null and b/PdfView/build/intermediates/res/merged/release/drawable/icon.png differ diff --git a/PdfView/build/intermediates/res/merged/release/drawable/left_arrow.png b/PdfView/build/intermediates/res/merged/release/drawable/left_arrow.png new file mode 100644 index 0000000..fd14e22 Binary files /dev/null and b/PdfView/build/intermediates/res/merged/release/drawable/left_arrow.png differ diff --git a/PdfView/build/intermediates/res/merged/release/drawable/pdf.png b/PdfView/build/intermediates/res/merged/release/drawable/pdf.png new file mode 100644 index 0000000..1af99f7 Binary files /dev/null and b/PdfView/build/intermediates/res/merged/release/drawable/pdf.png differ diff --git a/PdfView/build/intermediates/res/merged/release/drawable/right_arrow.png b/PdfView/build/intermediates/res/merged/release/drawable/right_arrow.png new file mode 100644 index 0000000..e13abb8 Binary files /dev/null and b/PdfView/build/intermediates/res/merged/release/drawable/right_arrow.png differ diff --git a/PdfView/build/intermediates/res/merged/release/drawable/zoom_in.png b/PdfView/build/intermediates/res/merged/release/drawable/zoom_in.png new file mode 100644 index 0000000..2c80cd4 Binary files /dev/null and b/PdfView/build/intermediates/res/merged/release/drawable/zoom_in.png differ diff --git a/PdfView/build/intermediates/res/merged/release/drawable/zoom_out.png b/PdfView/build/intermediates/res/merged/release/drawable/zoom_out.png new file mode 100644 index 0000000..c26c3fd Binary files /dev/null and b/PdfView/build/intermediates/res/merged/release/drawable/zoom_out.png differ diff --git a/PdfView/build/intermediates/res/merged/release/layout/dialog_pagenumber.xml b/PdfView/build/intermediates/res/merged/release/layout/dialog_pagenumber.xml new file mode 100644 index 0000000..4f51eb5 --- /dev/null +++ b/PdfView/build/intermediates/res/merged/release/layout/dialog_pagenumber.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/PdfView/build/intermediates/res/merged/release/layout/graphics_view.xml b/PdfView/build/intermediates/res/merged/release/layout/graphics_view.xml new file mode 100644 index 0000000..f4c8804 --- /dev/null +++ b/PdfView/build/intermediates/res/merged/release/layout/graphics_view.xml @@ -0,0 +1,15 @@ + + + + + + + \ No newline at end of file diff --git a/PdfView/build/intermediates/res/merged/release/layout/main.xml b/PdfView/build/intermediates/res/merged/release/layout/main.xml new file mode 100644 index 0000000..774162d --- /dev/null +++ b/PdfView/build/intermediates/res/merged/release/layout/main.xml @@ -0,0 +1,13 @@ + + + + + \ No newline at end of file diff --git a/PdfView/build/intermediates/res/merged/release/layout/navigation_overlay.xml b/PdfView/build/intermediates/res/merged/release/layout/navigation_overlay.xml new file mode 100644 index 0000000..74fe032 --- /dev/null +++ b/PdfView/build/intermediates/res/merged/release/layout/navigation_overlay.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/PdfView/build/intermediates/res/merged/release/layout/pdf_file_password.xml b/PdfView/build/intermediates/res/merged/release/layout/pdf_file_password.xml new file mode 100644 index 0000000..8c8d09c --- /dev/null +++ b/PdfView/build/intermediates/res/merged/release/layout/pdf_file_password.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/PdfView/build/intermediates/res/merged/release/layout/scroll_layout.xml b/PdfView/build/intermediates/res/merged/release/layout/scroll_layout.xml new file mode 100644 index 0000000..f066192 --- /dev/null +++ b/PdfView/build/intermediates/res/merged/release/layout/scroll_layout.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/PdfView/build/intermediates/res/merged/release/values/values.xml b/PdfView/build/intermediates/res/merged/release/values/values.xml new file mode 100644 index 0000000..be7cb96 --- /dev/null +++ b/PdfView/build/intermediates/res/merged/release/values/values.xml @@ -0,0 +1,13 @@ + + + + + #000000 + #000000FF + #9370DB + #FFFFFFFF + + + PdfViewer + Hello World, PdfViewerActivity! + \ No newline at end of file diff --git a/PdfView/build/outputs/aar/PdfView-release.aar b/PdfView/build/outputs/aar/PdfView-release.aar index f47b23b..016f94c 100644 Binary files a/PdfView/build/outputs/aar/PdfView-release.aar and b/PdfView/build/outputs/aar/PdfView-release.aar differ diff --git a/PdfView/src/main/java/net/sf/andpdf/pdfviewer/gui/PdfView.java b/PdfView/src/main/java/net/sf/andpdf/pdfviewer/gui/PdfView.java index 6deff8a..faae42d 100644 --- a/PdfView/src/main/java/net/sf/andpdf/pdfviewer/gui/PdfView.java +++ b/PdfView/src/main/java/net/sf/andpdf/pdfviewer/gui/PdfView.java @@ -6,11 +6,14 @@ import android.graphics.Color; import android.graphics.RectF; import android.os.Handler; import android.util.AttributeSet; +import android.util.DisplayMetrics; import android.util.Log; +import android.view.ViewGroup; +import android.view.WindowManager; import android.widget.ImageButton; -import android.widget.ImageView; import android.widget.Toast; +import com.polites.android.GestureImageView; import com.sun.pdfview.PDFFile; import com.sun.pdfview.PDFImage; import com.sun.pdfview.PDFPage; @@ -35,7 +38,7 @@ public class PdfView extends FullScrollView { private static final float ZOOM_INCREMENT = 1.5f; private Bitmap mBi; - private ImageView mImageView; + private GestureImageView mImageView; private Handler uiHandler; ImageButton bZoomOut; ImageButton bZoomIn; @@ -59,11 +62,12 @@ public class PdfView extends FullScrollView { PDFPaint.s_doAntiAlias = true; uiHandler = new Handler(); LayoutParams matchLp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); - mImageView = new ImageView(context); + mImageView = new GestureImageView(context); + setPageBitmap(null); updateImage(); addView(mImageView, matchLp); - setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); + setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); setBackgroundColor(Color.LTGRAY); setHorizontalScrollBarEnabled(true); setHorizontalFadingEdgeEnabled(true); @@ -79,6 +83,21 @@ public class PdfView extends FullScrollView { this.mPdfFile = mPdfFile; } + private int getDeviceWidth() { + DisplayMetrics metric = new DisplayMetrics(); + WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE); + wm.getDefaultDisplay().getMetrics(metric); + return metric.widthPixels; // 屏幕宽度(像素) + + } + + private int getDeviceHeight() { + DisplayMetrics metric = new DisplayMetrics(); + WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE); + wm.getDefaultDisplay().getMetrics(metric); + return metric.heightPixels; // 屏幕高度(像素) + } + public void showPage(int page, float zoom) throws Exception { try { // free memory from previous page @@ -90,6 +109,13 @@ public class PdfView extends FullScrollView { } float width = mPdfPage.getWidth(); float height = mPdfPage.getHeight(); + if (getLayoutParams().height == ViewGroup.LayoutParams.MATCH_PARENT) { + height *= getDeviceWidth() / width; + } + if (getLayoutParams().width == LayoutParams.MATCH_PARENT) { + width = getDeviceWidth(); + } + RectF clip = null; Bitmap bi = mPdfPage.getImage((int) (width * zoom), (int) (height * zoom), clip, true, true); setPageBitmap(bi); diff --git a/PdfView/src/main/java/net/sf/andpdf/utils/MathUtils.java b/PdfView/src/main/java/net/sf/andpdf/utils/MathUtils.java new file mode 100755 index 0000000..9eb9e3c --- /dev/null +++ b/PdfView/src/main/java/net/sf/andpdf/utils/MathUtils.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2012 Jason Polites + * + * 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 net.sf.andpdf.utils; + +import android.graphics.PointF; +import android.util.FloatMath; +import android.view.MotionEvent; + +public class MathUtils { + + public static float distance(MotionEvent event) { + float x = event.getX(0) - event.getX(1); + float y = event.getY(0) - event.getY(1); + return FloatMath.sqrt(x * x + y * y); + } + + public static float distance(PointF p1, PointF p2) { + float x = p1.x - p2.x; + float y = p1.y - p2.y; + return FloatMath.sqrt(x * x + y * y); + } + + public static float distance(float x1, float y1, float x2, float y2) { + float x = x1 - x2; + float y = y1 - y2; + return FloatMath.sqrt(x * x + y * y); + } + + public static void midpoint(MotionEvent event, PointF point) { + float x1 = event.getX(0); + float y1 = event.getY(0); + float x2 = event.getX(1); + float y2 = event.getY(1); + midpoint(x1, y1, x2, y2, point); + } + + public static void midpoint(float x1, float y1, float x2, float y2, PointF point) { + point.x = (x1 + x2) / 2.0f; + point.y = (y1 + y2) / 2.0f; + } + + /** + * Rotates p1 around p2 by angle degrees. + * + * @param p1 + * @param p2 + * @param angle + */ + public void rotate(PointF p1, PointF p2, float angle) { + float px = p1.x; + float py = p1.y; + float ox = p2.x; + float oy = p2.y; + p1.x = (FloatMath.cos(angle) * (px - ox) - FloatMath.sin(angle) * (py - oy) + ox); + p1.y = (FloatMath.sin(angle) * (px - ox) + FloatMath.cos(angle) * (py - oy) + oy); + } + + public static float angle(PointF p1, PointF p2) { + return angle(p1.x, p1.y, p2.x, p2.y); + } + + public static float angle(float x1, float y1, float x2, float y2) { + return (float) Math.atan2(y2 - y1, x2 - x1); + } +} diff --git a/PdfView/src/main/java/net/sf/andpdf/utils/VectorF.java b/PdfView/src/main/java/net/sf/andpdf/utils/VectorF.java new file mode 100644 index 0000000..b0669af --- /dev/null +++ b/PdfView/src/main/java/net/sf/andpdf/utils/VectorF.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2012 Jason Polites + * + * 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 net.sf.andpdf.utils; + +import android.graphics.PointF; +import android.util.FloatMath; +import android.view.MotionEvent; + +public class VectorF { + + public float angle; + public float length; + + public final PointF start = new PointF(); + public final PointF end = new PointF(); + + public void calculateEndPoint() { + end.x = FloatMath.cos(angle) * length + start.x; + end.y = FloatMath.sin(angle) * length + start.y; + } + + public void setStart(PointF p) { + this.start.x = p.x; + this.start.y = p.y; + } + + public void setEnd(PointF p) { + this.end.x = p.x; + this.end.y = p.y; + } + + public void set(MotionEvent event) { + this.start.x = event.getX(0); + this.start.y = event.getY(0); + this.end.x = event.getX(1); + this.end.y = event.getY(1); + } + + public float calculateLength() { + length = MathUtils.distance(start, end); + return length; + } + + public float calculateAngle() { + angle = MathUtils.angle(start, end); + return angle; + } + + +} diff --git a/build/intermediates/dex-cache/cache.xml b/build/intermediates/dex-cache/cache.xml index b75495b..fc4d970 100644 --- a/build/intermediates/dex-cache/cache.xml +++ b/build/intermediates/dex-cache/cache.xml @@ -5,7 +5,7 @@ jar="/Users/winney/git/Android-Pdf-Viewer-Library/pdfviewsample/build/intermediates/exploded-aar/Android-Pdf-Viewer-Library/PdfView/unspecified/jars/classes.jar" jumboMode="false" revision="23.0.2" - sha1="933be2f099767838f02cd4a28fc5ac4c219b327f"> + sha1="e7d6dd07e1cac71ea7611e16c5dcd8b3cba978dc"> diff --git a/gestureimageview/build.gradle b/gestureimageview/build.gradle new file mode 100644 index 0000000..34ad362 --- /dev/null +++ b/gestureimageview/build.gradle @@ -0,0 +1,18 @@ +apply plugin: 'com.android.library' + +android { + compileSdkVersion 19 + buildToolsVersion "19.1.0" + + defaultConfig { + minSdkVersion 7 + targetSdkVersion 7 + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' + } + } +} diff --git a/gestureimageview/build/generated/source/buildConfig/release/com/polites/android/BuildConfig.java b/gestureimageview/build/generated/source/buildConfig/release/com/polites/android/BuildConfig.java new file mode 100644 index 0000000..96b555d --- /dev/null +++ b/gestureimageview/build/generated/source/buildConfig/release/com/polites/android/BuildConfig.java @@ -0,0 +1,13 @@ +/** + * Automatically generated file. DO NOT MODIFY + */ +package com.polites.android; + +public final class BuildConfig { + public static final boolean DEBUG = false; + public static final String APPLICATION_ID = "com.polites.android"; + public static final String BUILD_TYPE = "release"; + public static final String FLAVOR = ""; + public static final int VERSION_CODE = 1; + public static final String VERSION_NAME = ""; +} diff --git a/gestureimageview/build/intermediates/bundles/release/AndroidManifest.xml b/gestureimageview/build/intermediates/bundles/release/AndroidManifest.xml new file mode 100644 index 0000000..a4e05e6 --- /dev/null +++ b/gestureimageview/build/intermediates/bundles/release/AndroidManifest.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/gestureimageview/build/intermediates/bundles/release/aapt/AndroidManifest.xml b/gestureimageview/build/intermediates/bundles/release/aapt/AndroidManifest.xml new file mode 100644 index 0000000..a4e05e6 --- /dev/null +++ b/gestureimageview/build/intermediates/bundles/release/aapt/AndroidManifest.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/gestureimageview/build/intermediates/bundles/release/classes.jar b/gestureimageview/build/intermediates/bundles/release/classes.jar new file mode 100644 index 0000000..8662373 Binary files /dev/null and b/gestureimageview/build/intermediates/bundles/release/classes.jar differ diff --git a/gestureimageview/build/intermediates/classes/release/com/polites/android/Animation.class b/gestureimageview/build/intermediates/classes/release/com/polites/android/Animation.class new file mode 100644 index 0000000..d5aff61 Binary files /dev/null and b/gestureimageview/build/intermediates/classes/release/com/polites/android/Animation.class differ diff --git a/gestureimageview/build/intermediates/classes/release/com/polites/android/Animator.class b/gestureimageview/build/intermediates/classes/release/com/polites/android/Animator.class new file mode 100644 index 0000000..4149aa3 Binary files /dev/null and b/gestureimageview/build/intermediates/classes/release/com/polites/android/Animator.class differ diff --git a/gestureimageview/build/intermediates/classes/release/com/polites/android/BuildConfig.class b/gestureimageview/build/intermediates/classes/release/com/polites/android/BuildConfig.class new file mode 100644 index 0000000..bde5b11 Binary files /dev/null and b/gestureimageview/build/intermediates/classes/release/com/polites/android/BuildConfig.class differ diff --git a/gestureimageview/build/intermediates/classes/release/com/polites/android/FlingAnimation.class b/gestureimageview/build/intermediates/classes/release/com/polites/android/FlingAnimation.class new file mode 100644 index 0000000..40b80fb Binary files /dev/null and b/gestureimageview/build/intermediates/classes/release/com/polites/android/FlingAnimation.class differ diff --git a/gestureimageview/build/intermediates/classes/release/com/polites/android/FlingAnimationListener.class b/gestureimageview/build/intermediates/classes/release/com/polites/android/FlingAnimationListener.class new file mode 100644 index 0000000..9460959 Binary files /dev/null and b/gestureimageview/build/intermediates/classes/release/com/polites/android/FlingAnimationListener.class differ diff --git a/gestureimageview/build/intermediates/classes/release/com/polites/android/FlingListener.class b/gestureimageview/build/intermediates/classes/release/com/polites/android/FlingListener.class new file mode 100644 index 0000000..580f704 Binary files /dev/null and b/gestureimageview/build/intermediates/classes/release/com/polites/android/FlingListener.class differ diff --git a/gestureimageview/build/intermediates/classes/release/com/polites/android/GestureImageView$1.class b/gestureimageview/build/intermediates/classes/release/com/polites/android/GestureImageView$1.class new file mode 100644 index 0000000..8b5775e Binary files /dev/null and b/gestureimageview/build/intermediates/classes/release/com/polites/android/GestureImageView$1.class differ diff --git a/gestureimageview/build/intermediates/classes/release/com/polites/android/GestureImageView$2.class b/gestureimageview/build/intermediates/classes/release/com/polites/android/GestureImageView$2.class new file mode 100644 index 0000000..e28a367 Binary files /dev/null and b/gestureimageview/build/intermediates/classes/release/com/polites/android/GestureImageView$2.class differ diff --git a/gestureimageview/build/intermediates/classes/release/com/polites/android/GestureImageView.class b/gestureimageview/build/intermediates/classes/release/com/polites/android/GestureImageView.class new file mode 100644 index 0000000..de954bb Binary files /dev/null and b/gestureimageview/build/intermediates/classes/release/com/polites/android/GestureImageView.class differ diff --git a/gestureimageview/build/intermediates/classes/release/com/polites/android/GestureImageViewListener.class b/gestureimageview/build/intermediates/classes/release/com/polites/android/GestureImageViewListener.class new file mode 100644 index 0000000..10009d8 Binary files /dev/null and b/gestureimageview/build/intermediates/classes/release/com/polites/android/GestureImageViewListener.class differ diff --git a/gestureimageview/build/intermediates/classes/release/com/polites/android/GestureImageViewTouchListener$1.class b/gestureimageview/build/intermediates/classes/release/com/polites/android/GestureImageViewTouchListener$1.class new file mode 100644 index 0000000..fbe7aa8 Binary files /dev/null and b/gestureimageview/build/intermediates/classes/release/com/polites/android/GestureImageViewTouchListener$1.class differ diff --git a/gestureimageview/build/intermediates/classes/release/com/polites/android/GestureImageViewTouchListener$2.class b/gestureimageview/build/intermediates/classes/release/com/polites/android/GestureImageViewTouchListener$2.class new file mode 100644 index 0000000..c06e0f3 Binary files /dev/null and b/gestureimageview/build/intermediates/classes/release/com/polites/android/GestureImageViewTouchListener$2.class differ diff --git a/gestureimageview/build/intermediates/classes/release/com/polites/android/GestureImageViewTouchListener$3.class b/gestureimageview/build/intermediates/classes/release/com/polites/android/GestureImageViewTouchListener$3.class new file mode 100644 index 0000000..c42b6cd Binary files /dev/null and b/gestureimageview/build/intermediates/classes/release/com/polites/android/GestureImageViewTouchListener$3.class differ diff --git a/gestureimageview/build/intermediates/classes/release/com/polites/android/GestureImageViewTouchListener$4.class b/gestureimageview/build/intermediates/classes/release/com/polites/android/GestureImageViewTouchListener$4.class new file mode 100644 index 0000000..68ec06f Binary files /dev/null and b/gestureimageview/build/intermediates/classes/release/com/polites/android/GestureImageViewTouchListener$4.class differ diff --git a/gestureimageview/build/intermediates/classes/release/com/polites/android/GestureImageViewTouchListener.class b/gestureimageview/build/intermediates/classes/release/com/polites/android/GestureImageViewTouchListener.class new file mode 100644 index 0000000..4e69f0b Binary files /dev/null and b/gestureimageview/build/intermediates/classes/release/com/polites/android/GestureImageViewTouchListener.class differ diff --git a/gestureimageview/build/intermediates/classes/release/com/polites/android/MathUtils.class b/gestureimageview/build/intermediates/classes/release/com/polites/android/MathUtils.class new file mode 100644 index 0000000..e466223 Binary files /dev/null and b/gestureimageview/build/intermediates/classes/release/com/polites/android/MathUtils.class differ diff --git a/gestureimageview/build/intermediates/classes/release/com/polites/android/MoveAnimation.class b/gestureimageview/build/intermediates/classes/release/com/polites/android/MoveAnimation.class new file mode 100644 index 0000000..ddabdfa Binary files /dev/null and b/gestureimageview/build/intermediates/classes/release/com/polites/android/MoveAnimation.class differ diff --git a/gestureimageview/build/intermediates/classes/release/com/polites/android/MoveAnimationListener.class b/gestureimageview/build/intermediates/classes/release/com/polites/android/MoveAnimationListener.class new file mode 100644 index 0000000..3ded8ad Binary files /dev/null and b/gestureimageview/build/intermediates/classes/release/com/polites/android/MoveAnimationListener.class differ diff --git a/gestureimageview/build/intermediates/classes/release/com/polites/android/VectorF.class b/gestureimageview/build/intermediates/classes/release/com/polites/android/VectorF.class new file mode 100644 index 0000000..d5ce5ba Binary files /dev/null and b/gestureimageview/build/intermediates/classes/release/com/polites/android/VectorF.class differ diff --git a/gestureimageview/build/intermediates/classes/release/com/polites/android/ZoomAnimation.class b/gestureimageview/build/intermediates/classes/release/com/polites/android/ZoomAnimation.class new file mode 100644 index 0000000..349c0d3 Binary files /dev/null and b/gestureimageview/build/intermediates/classes/release/com/polites/android/ZoomAnimation.class differ diff --git a/gestureimageview/build/intermediates/classes/release/com/polites/android/ZoomAnimationListener.class b/gestureimageview/build/intermediates/classes/release/com/polites/android/ZoomAnimationListener.class new file mode 100644 index 0000000..1857530 Binary files /dev/null and b/gestureimageview/build/intermediates/classes/release/com/polites/android/ZoomAnimationListener.class differ diff --git a/gestureimageview/build/intermediates/incremental/aidl/release/dependency.store b/gestureimageview/build/intermediates/incremental/aidl/release/dependency.store new file mode 100644 index 0000000..8b8400d Binary files /dev/null and b/gestureimageview/build/intermediates/incremental/aidl/release/dependency.store differ diff --git a/gestureimageview/build/intermediates/incremental/mergeAssets/release/merger.xml b/gestureimageview/build/intermediates/incremental/mergeAssets/release/merger.xml new file mode 100644 index 0000000..6f36452 --- /dev/null +++ b/gestureimageview/build/intermediates/incremental/mergeAssets/release/merger.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/gestureimageview/build/intermediates/incremental/packageResourcesrelease/merger.xml b/gestureimageview/build/intermediates/incremental/packageResourcesrelease/merger.xml new file mode 100644 index 0000000..2a7baaa --- /dev/null +++ b/gestureimageview/build/intermediates/incremental/packageResourcesrelease/merger.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/gestureimageview/build/outputs/aar/gestureimageview-release.aar b/gestureimageview/build/outputs/aar/gestureimageview-release.aar new file mode 100644 index 0000000..280affc Binary files /dev/null and b/gestureimageview/build/outputs/aar/gestureimageview-release.aar differ diff --git a/gestureimageview/build/tmp/packageReleaseJar/MANIFEST.MF b/gestureimageview/build/tmp/packageReleaseJar/MANIFEST.MF new file mode 100644 index 0000000..58630c0 --- /dev/null +++ b/gestureimageview/build/tmp/packageReleaseJar/MANIFEST.MF @@ -0,0 +1,2 @@ +Manifest-Version: 1.0 + diff --git a/gestureimageview/gestureimageview.iml b/gestureimageview/gestureimageview.iml new file mode 100644 index 0000000..079e01b --- /dev/null +++ b/gestureimageview/gestureimageview.iml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/gestureimageview/src/main/AndroidManifest.xml b/gestureimageview/src/main/AndroidManifest.xml new file mode 100644 index 0000000..ceae95b --- /dev/null +++ b/gestureimageview/src/main/AndroidManifest.xml @@ -0,0 +1,9 @@ + + + + + + \ No newline at end of file diff --git a/gestureimageview/src/main/java/com/polites/android/Animation.java b/gestureimageview/src/main/java/com/polites/android/Animation.java new file mode 100644 index 0000000..6e3d3bc --- /dev/null +++ b/gestureimageview/src/main/java/com/polites/android/Animation.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2012 Jason Polites + * + * 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.polites.android; + +/** + * @author Jason Polites + * + */ +public interface Animation { + + /** + * Transforms the view. + * @param view + * @param diffTime + * @return true if this animation should remain active. False otherwise. + */ + public boolean update(GestureImageView view, long time); + +} diff --git a/gestureimageview/src/main/java/com/polites/android/Animator.java b/gestureimageview/src/main/java/com/polites/android/Animator.java new file mode 100644 index 0000000..fbcb7d2 --- /dev/null +++ b/gestureimageview/src/main/java/com/polites/android/Animator.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2012 Jason Polites + * + * 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.polites.android; + + +/** + * @author Jason Polites + * + */ +public class Animator extends Thread { + + private GestureImageView view; + private Animation animation; + private boolean running = false; + private boolean active = false; + private long lastTime = -1L; + + public Animator(GestureImageView view, String threadName) { + super(threadName); + this.view = view; + } + + @Override + public void run() { + + running = true; + + while(running) { + + while(active && animation != null) { + long time = System.currentTimeMillis(); + active = animation.update(view, time - lastTime); + view.redraw(); + lastTime = time; + + while(active) { + try { + if(view.waitForDraw(32)) { // 30Htz + break; + } + } + catch (InterruptedException ignore) { + active = false; + } + } + } + + synchronized(this) { + if(running) { + try { + wait(); + } + catch (InterruptedException ignore) {} + } + } + } + } + + public synchronized void finish() { + running = false; + active = false; + notifyAll(); + } + + public void play(Animation transformer) { + if(active) { + cancel(); + } + this.animation = transformer; + + activate(); + } + + public synchronized void activate() { + lastTime = System.currentTimeMillis(); + active = true; + notifyAll(); + } + + public void cancel() { + active = false; + } +} diff --git a/gestureimageview/src/main/java/com/polites/android/FlingAnimation.java b/gestureimageview/src/main/java/com/polites/android/FlingAnimation.java new file mode 100644 index 0000000..66cdca5 --- /dev/null +++ b/gestureimageview/src/main/java/com/polites/android/FlingAnimation.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2012 Jason Polites + * + * 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.polites.android; + +/** + * @author Jason Polites + * + */ +public class FlingAnimation implements Animation { + + private float velocityX; + private float velocityY; + + private float factor = 0.95f; + + private float threshold = 10; + + private FlingAnimationListener listener; + + /* (non-Javadoc) + * @see com.polites.android.Transformer#update(com.polites.android.GestureImageView, long) + */ + @Override + public boolean update(GestureImageView view, long time) { + float seconds = (float) time / 1000.0f; + + float dx = velocityX * seconds; + float dy = velocityY * seconds; + + velocityX *= factor; + velocityY *= factor; + + boolean active = (Math.abs(velocityX) > threshold && Math.abs(velocityY) > threshold); + + if(listener != null) { + listener.onMove(dx, dy); + + if(!active) { + listener.onComplete(); + } + } + + return active; + } + + public void setVelocityX(float velocityX) { + this.velocityX = velocityX; + } + + public void setVelocityY(float velocityY) { + this.velocityY = velocityY; + } + + public void setFactor(float factor) { + this.factor = factor; + } + + public void setListener(FlingAnimationListener listener) { + this.listener = listener; + } +} diff --git a/gestureimageview/src/main/java/com/polites/android/FlingAnimationListener.java b/gestureimageview/src/main/java/com/polites/android/FlingAnimationListener.java new file mode 100644 index 0000000..b1b38e3 --- /dev/null +++ b/gestureimageview/src/main/java/com/polites/android/FlingAnimationListener.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2012 Jason Polites + * + * 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.polites.android; + + +/** + * @author Jason Polites + * + */ +public interface FlingAnimationListener { + + public void onMove(float x, float y); + + public void onComplete(); + +} diff --git a/gestureimageview/src/main/java/com/polites/android/FlingListener.java b/gestureimageview/src/main/java/com/polites/android/FlingListener.java new file mode 100644 index 0000000..1b9b3dc --- /dev/null +++ b/gestureimageview/src/main/java/com/polites/android/FlingListener.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2012 Jason Polites + * + * 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.polites.android; + +import android.view.GestureDetector.SimpleOnGestureListener; +import android.view.MotionEvent; + + +/** + * @author Jason Polites + * + */ +public class FlingListener extends SimpleOnGestureListener { + + private float velocityX; + private float velocityY; + + @Override + public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { + this.velocityX = velocityX; + this.velocityY = velocityY; + return true; + } + + public float getVelocityX() { + return velocityX; + } + + public float getVelocityY() { + return velocityY; + } +} diff --git a/gestureimageview/src/main/java/com/polites/android/GestureImageView.java b/gestureimageview/src/main/java/com/polites/android/GestureImageView.java new file mode 100644 index 0000000..05d4b81 --- /dev/null +++ b/gestureimageview/src/main/java/com/polites/android/GestureImageView.java @@ -0,0 +1,713 @@ +/* + * Copyright (c) 2012 Jason Polites + * + * 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.polites.android; + +import android.content.Context; +import android.content.res.Configuration; +import android.database.Cursor; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.Matrix; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.net.Uri; +import android.provider.MediaStore; +import android.util.AttributeSet; +import android.util.Log; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup.LayoutParams; +import android.widget.ImageView; + +import java.io.InputStream; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; + +public class GestureImageView extends ImageView { + + public static final String GLOBAL_NS = "http://schemas.android.com/apk/res/android"; + public static final String LOCAL_NS = "http://schemas.polites.com/android"; + + private final Semaphore drawLock = new Semaphore(0); + private Animator animator; + + private Drawable drawable; + + private float x = 0, y = 0; + + private boolean layout = false; + + private float scaleAdjust = 1.0f; + private float startingScale = -1.0f; + + private float scale = 1.0f; + private float maxScale = 5.0f; + private float minScale = 0.75f; + private float fitScaleHorizontal = 1.0f; + private float fitScaleVertical = 1.0f; + private float rotation = 0.0f; + + private float centerX; + private float centerY; + + private Float startX, startY; + + private int hWidth; + private int hHeight; + + private int resId = -1; + private boolean recycle = false; + private boolean strict = false; + + private int displayHeight; + private int displayWidth; + + private int alpha = 255; + private ColorFilter colorFilter; + + private int deviceOrientation = -1; + private int imageOrientation; + + private GestureImageViewListener gestureImageViewListener; + private GestureImageViewTouchListener gestureImageViewTouchListener; + + private OnTouchListener customOnTouchListener; + private OnClickListener onClickListener; + + public GestureImageView(Context context, AttributeSet attrs, int defStyle) { + this(context, attrs); + } + + public GestureImageView(Context context, AttributeSet attrs) { + super(context, attrs); + + String scaleType = attrs.getAttributeValue(GLOBAL_NS, "scaleType"); + + if (scaleType == null || scaleType.trim().length() == 0) { + setScaleType(ScaleType.CENTER_INSIDE); + } + + String strStartX = attrs.getAttributeValue(LOCAL_NS, "start-x"); + String strStartY = attrs.getAttributeValue(LOCAL_NS, "start-y"); + + if (strStartX != null && strStartX.trim().length() > 0) { + startX = Float.parseFloat(strStartX); + } + + if (strStartY != null && strStartY.trim().length() > 0) { + startY = Float.parseFloat(strStartY); + } + + setStartingScale(attrs.getAttributeFloatValue(LOCAL_NS, "start-scale", startingScale)); + setMinScale(attrs.getAttributeFloatValue(LOCAL_NS, "min-scale", minScale)); + setMaxScale(attrs.getAttributeFloatValue(LOCAL_NS, "max-scale", maxScale)); + setStrict(attrs.getAttributeBooleanValue(LOCAL_NS, "strict", strict)); + setRecycle(attrs.getAttributeBooleanValue(LOCAL_NS, "recycle", recycle)); + + initImage(); + } + + public GestureImageView(Context context) { + super(context); + setScaleType(ScaleType.CENTER_INSIDE); + initImage(); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + + if (drawable != null) { + int orientation = getResources().getConfiguration().orientation; + if (orientation == Configuration.ORIENTATION_LANDSCAPE) { + displayHeight = MeasureSpec.getSize(heightMeasureSpec); + + if (getLayoutParams().width == LayoutParams.WRAP_CONTENT) { + float ratio = (float) getImageWidth() / (float) getImageHeight(); + displayWidth = Math.round((float) displayHeight * ratio); + } else { + displayWidth = MeasureSpec.getSize(widthMeasureSpec); + } + } else { + displayWidth = MeasureSpec.getSize(widthMeasureSpec); + if (getLayoutParams().height == LayoutParams.WRAP_CONTENT) { + float ratio = (float) getImageHeight() / (float) getImageWidth(); + displayHeight = Math.round((float) displayWidth * ratio); + } else { + displayHeight = MeasureSpec.getSize(heightMeasureSpec); + } + } + } else { + displayHeight = MeasureSpec.getSize(heightMeasureSpec); + displayWidth = MeasureSpec.getSize(widthMeasureSpec); + } + + setMeasuredDimension(displayWidth, displayHeight); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + if (changed || !layout) { + setupCanvas(displayWidth, displayHeight, getResources().getConfiguration().orientation); + } + } + + protected void setupCanvas(int measuredWidth, int measuredHeight, int orientation) { + + if (deviceOrientation != orientation) { + layout = false; + deviceOrientation = orientation; + } + + if (drawable != null && !layout) { + int imageWidth = getImageWidth(); + int imageHeight = getImageHeight(); + + hWidth = Math.round(((float) imageWidth / 2.0f)); + hHeight = Math.round(((float) imageHeight / 2.0f)); + + measuredWidth -= (getPaddingLeft() + getPaddingRight()); + measuredHeight -= (getPaddingTop() + getPaddingBottom()); + + computeCropScale(imageWidth, imageHeight, measuredWidth, measuredHeight); + + if (startingScale <= 0.0f) { + computeStartingScale(imageWidth, imageHeight, measuredWidth, measuredHeight); + } + + scaleAdjust = startingScale; + + this.centerX = (float) measuredWidth / 2.0f; + this.centerY = (float) measuredHeight / 2.0f; + + if (startX == null) { + x = centerX; + } else { + x = startX; + } + + if (startY == null) { + y = centerY; + } else { + y = startY; + } + + gestureImageViewTouchListener = new GestureImageViewTouchListener(this, measuredWidth, measuredHeight); + + if (isLandscape()) { + gestureImageViewTouchListener.setMinScale(minScale * fitScaleHorizontal); + } else { + gestureImageViewTouchListener.setMinScale(minScale * fitScaleVertical); + } + + + gestureImageViewTouchListener.setMaxScale(maxScale * startingScale); + + gestureImageViewTouchListener.setFitScaleHorizontal(fitScaleHorizontal); + gestureImageViewTouchListener.setFitScaleVertical(fitScaleVertical); + gestureImageViewTouchListener.setCanvasWidth(measuredWidth); + gestureImageViewTouchListener.setCanvasHeight(measuredHeight); + gestureImageViewTouchListener.setOnClickListener(onClickListener); + + drawable.setBounds(-hWidth, -hHeight, hWidth, hHeight); + + super.setOnTouchListener(new OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + if (customOnTouchListener != null) { + customOnTouchListener.onTouch(v, event); + } + return gestureImageViewTouchListener.onTouch(v, event); + } + }); + + layout = true; + } + } + + protected void computeCropScale(int imageWidth, int imageHeight, int measuredWidth, int measuredHeight) { + fitScaleHorizontal = (float) measuredWidth / (float) imageWidth; + fitScaleVertical = (float) measuredHeight / (float) imageHeight; + } + + protected void computeStartingScale(int imageWidth, int imageHeight, int measuredWidth, int measuredHeight) { + switch (getScaleType()) { + case CENTER: + // Center the image in the view, but perform no scaling. + startingScale = 1.0f; + break; + + case CENTER_CROP: + // Scale the image uniformly (maintain the image's aspect ratio) so that both dimensions + // (width and height) of the image will be equal to or larger than the corresponding dimension of the view (minus padding). + startingScale = Math.max((float) measuredHeight / (float) imageHeight, (float) measuredWidth / (float) imageWidth); + break; + + case CENTER_INSIDE: + + // Scale the image uniformly (maintain the image's aspect ratio) so that both dimensions + // (width and height) of the image will be equal to or less than the corresponding dimension of the view (minus padding). + float wRatio = (float) imageWidth / (float) measuredWidth; + float hRatio = (float) imageHeight / (float) measuredHeight; + + if (wRatio > hRatio) { + startingScale = fitScaleHorizontal; + } else { + startingScale = fitScaleVertical; + } + + break; + } + } + + protected boolean isRecycled() { + if (drawable != null && drawable instanceof BitmapDrawable) { + Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap(); + if (bitmap != null) { + return bitmap.isRecycled(); + } + } + return false; + } + + protected void recycle() { + if (recycle && drawable != null && drawable instanceof BitmapDrawable) { + Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap(); + if (bitmap != null) { + bitmap.recycle(); + } + } + } + + @Override + protected void onDraw(Canvas canvas) { + if (layout) { + if (drawable != null && !isRecycled()) { + canvas.save(); + + float adjustedScale = scale * scaleAdjust; + + canvas.translate(x, y); + + if (rotation != 0.0f) { + canvas.rotate(rotation); + } + + if (adjustedScale != 1.0f) { + canvas.scale(adjustedScale, adjustedScale); + } + + drawable.draw(canvas); + + canvas.restore(); + } + + if (drawLock.availablePermits() <= 0) { + drawLock.release(); + } + } + } + + /** + * Waits for a draw + * + * @param max time to wait for draw (ms) + * @throws InterruptedException + */ + public boolean waitForDraw(long timeout) throws InterruptedException { + return drawLock.tryAcquire(timeout, TimeUnit.MILLISECONDS); + } + + @Override + protected void onAttachedToWindow() { + animator = new Animator(this, "GestureImageViewAnimator"); + animator.start(); + + if (resId >= 0 && drawable == null) { + setImageResource(resId); + } + + super.onAttachedToWindow(); + } + + public void animationStart(Animation animation) { + if (animator != null) { + animator.play(animation); + } + } + + public void animationStop() { + if (animator != null) { + animator.cancel(); + } + } + + @Override + protected void onDetachedFromWindow() { + if (animator != null) { + animator.finish(); + } + if (recycle && drawable != null && !isRecycled()) { + recycle(); + drawable = null; + } + super.onDetachedFromWindow(); + } + + protected void initImage() { + if (this.drawable != null) { + this.drawable.setAlpha(alpha); + this.drawable.setFilterBitmap(true); + if (colorFilter != null) { + this.drawable.setColorFilter(colorFilter); + } + } + + if (!layout) { + requestLayout(); + redraw(); + } + } + + public void setImageBitmap(Bitmap image) { + this.drawable = new BitmapDrawable(getResources(), image); + initImage(); + } + + @Override + public void setImageDrawable(Drawable drawable) { + this.drawable = drawable; + initImage(); + } + + public void setImageResource(int id) { + if (this.drawable != null) { + this.recycle(); + } + if (id >= 0) { + this.resId = id; + setImageDrawable(getContext().getResources().getDrawable(id)); + } + } + + public int getScaledWidth() { + return Math.round(getImageWidth() * getScale()); + } + + public int getScaledHeight() { + return Math.round(getImageHeight() * getScale()); + } + + public int getImageWidth() { + if (drawable != null) { + return drawable.getIntrinsicWidth(); + } + return 0; + } + + public int getImageHeight() { + if (drawable != null) { + return drawable.getIntrinsicHeight(); + } + return 0; + } + + public void moveBy(float x, float y) { + this.x += x; + this.y += y; + } + + public void setPosition(float x, float y) { + this.x = x; + this.y = y; + } + + public void redraw() { + postInvalidate(); + } + + public void setMinScale(float min) { + this.minScale = min; + if (gestureImageViewTouchListener != null) { + gestureImageViewTouchListener.setMinScale(min * fitScaleHorizontal); + } + } + + public void setMaxScale(float max) { + this.maxScale = max; + if (gestureImageViewTouchListener != null) { + gestureImageViewTouchListener.setMaxScale(max * startingScale); + } + } + + public void setScale(float scale) { + scaleAdjust = scale; + } + + public float getScale() { + return scaleAdjust; + } + + public float getImageX() { + return x; + } + + public float getImageY() { + return y; + } + + public boolean isStrict() { + return strict; + } + + public void setStrict(boolean strict) { + this.strict = strict; + } + + public boolean isRecycle() { + return recycle; + } + + public void setRecycle(boolean recycle) { + this.recycle = recycle; + } + + public void reset() { + x = centerX; + y = centerY; + scaleAdjust = startingScale; + if (gestureImageViewTouchListener != null) { + gestureImageViewTouchListener.reset(); + } + redraw(); + } + + public void setRotation(float rotation) { + this.rotation = rotation; + } + + public void setGestureImageViewListener(GestureImageViewListener pinchImageViewListener) { + this.gestureImageViewListener = pinchImageViewListener; + } + + public GestureImageViewListener getGestureImageViewListener() { + return gestureImageViewListener; + } + + @Override + public Drawable getDrawable() { + return drawable; + } + + @Override + public void setAlpha(int alpha) { + this.alpha = alpha; + if (drawable != null) { + drawable.setAlpha(alpha); + } + } + + @Override + public void setColorFilter(ColorFilter cf) { + this.colorFilter = cf; + if (drawable != null) { + drawable.setColorFilter(cf); + } + } + + @Override + public void setImageURI(Uri mUri) { + if ("content".equals(mUri.getScheme())) { + try { + String[] orientationColumn = {MediaStore.Images.Media.ORIENTATION}; + + Cursor cur = getContext().getContentResolver().query(mUri, orientationColumn, null, null, null); + + if (cur != null && cur.moveToFirst()) { + imageOrientation = cur.getInt(cur.getColumnIndex(orientationColumn[0])); + } + + InputStream in = null; + + try { + in = getContext().getContentResolver().openInputStream(mUri); + Bitmap bmp = BitmapFactory.decodeStream(in); + + if (imageOrientation != 0) { + Matrix m = new Matrix(); + m.postRotate(imageOrientation); + Bitmap rotated = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), m, true); + bmp.recycle(); + setImageDrawable(new BitmapDrawable(getResources(), rotated)); + } else { + setImageDrawable(new BitmapDrawable(getResources(), bmp)); + } + } finally { + if (in != null) { + in.close(); + } + + if (cur != null) { + cur.close(); + } + } + } catch (Exception e) { + Log.w("GestureImageView", "Unable to open content: " + mUri, e); + } + } else { + setImageDrawable(Drawable.createFromPath(mUri.toString())); + } + + if (drawable == null) { + Log.e("GestureImageView", "resolveUri failed on bad bitmap uri: " + mUri); + // Don't try again. + mUri = null; + } + } + + @Override + public Matrix getImageMatrix() { + if (strict) { + throw new UnsupportedOperationException("Not supported"); + } + return super.getImageMatrix(); + } + + @Override + public void setScaleType(ScaleType scaleType) { + if (scaleType == ScaleType.CENTER || + scaleType == ScaleType.CENTER_CROP || + scaleType == ScaleType.CENTER_INSIDE) { + + super.setScaleType(scaleType); + } else if (strict) { + throw new UnsupportedOperationException("Not supported"); + } + } + + @Override + public void invalidateDrawable(Drawable dr) { + if (strict) { + throw new UnsupportedOperationException("Not supported"); + } + super.invalidateDrawable(dr); + } + + @Override + public int[] onCreateDrawableState(int extraSpace) { + if (strict) { + throw new UnsupportedOperationException("Not supported"); + } + return super.onCreateDrawableState(extraSpace); + } + + @Override + public void setAdjustViewBounds(boolean adjustViewBounds) { + if (strict) { + throw new UnsupportedOperationException("Not supported"); + } + super.setAdjustViewBounds(adjustViewBounds); + } + + @Override + public void setImageLevel(int level) { + if (strict) { + throw new UnsupportedOperationException("Not supported"); + } + super.setImageLevel(level); + } + + @Override + public void setImageMatrix(Matrix matrix) { + if (strict) { + throw new UnsupportedOperationException("Not supported"); + } + } + + @Override + public void setImageState(int[] state, boolean merge) { + if (strict) { + throw new UnsupportedOperationException("Not supported"); + } + } + + @Override + public void setSelected(boolean selected) { + if (strict) { + throw new UnsupportedOperationException("Not supported"); + } + super.setSelected(selected); + } + + @Override + public void setOnTouchListener(OnTouchListener l) { + this.customOnTouchListener = l; + } + + public float getCenterX() { + return centerX; + } + + public float getCenterY() { + return centerY; + } + + public boolean isLandscape() { + return getImageWidth() >= getImageHeight(); + } + + public boolean isPortrait() { + return getImageWidth() <= getImageHeight(); + } + + public void setStartingScale(float startingScale) { + this.startingScale = startingScale; + } + + public void setStartingPosition(float x, float y) { + this.startX = x; + this.startY = y; + } + + @Override + public void setOnClickListener(OnClickListener l) { + this.onClickListener = l; + + if (gestureImageViewTouchListener != null) { + gestureImageViewTouchListener.setOnClickListener(l); + } + } + + /** + * Returns true if the image dimensions are aligned with the orientation of the device. + * + * @return + */ + public boolean isOrientationAligned() { + if (deviceOrientation == Configuration.ORIENTATION_LANDSCAPE) { + return isLandscape(); + } else if (deviceOrientation == Configuration.ORIENTATION_PORTRAIT) { + return isPortrait(); + } + return true; + } + + public int getDeviceOrientation() { + return deviceOrientation; + } +} diff --git a/gestureimageview/src/main/java/com/polites/android/GestureImageViewListener.java b/gestureimageview/src/main/java/com/polites/android/GestureImageViewListener.java new file mode 100644 index 0000000..ad5df10 --- /dev/null +++ b/gestureimageview/src/main/java/com/polites/android/GestureImageViewListener.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2012 Jason Polites + * + * 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.polites.android; + +/** + * @author jasonpolites + * + */ +public interface GestureImageViewListener { + + public void onTouch(float x, float y); + + public void onScale(float scale); + + public void onPosition(float x, float y); + +} diff --git a/gestureimageview/src/main/java/com/polites/android/GestureImageViewTouchListener.java b/gestureimageview/src/main/java/com/polites/android/GestureImageViewTouchListener.java new file mode 100644 index 0000000..05945f5 --- /dev/null +++ b/gestureimageview/src/main/java/com/polites/android/GestureImageViewTouchListener.java @@ -0,0 +1,540 @@ +/* + * Copyright (c) 2012 Jason Polites + * + * 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.polites.android; + +import android.content.res.Configuration; +import android.graphics.PointF; +import android.view.GestureDetector; +import android.view.GestureDetector.SimpleOnGestureListener; +import android.view.MotionEvent; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.View.OnTouchListener; + +public class GestureImageViewTouchListener implements OnTouchListener { + + private GestureImageView image; + private OnClickListener onClickListener; + + private final PointF current = new PointF(); + private final PointF last = new PointF(); + private final PointF next = new PointF(); + private final PointF midpoint = new PointF(); + + private final VectorF scaleVector = new VectorF(); + private final VectorF pinchVector = new VectorF(); + + private boolean touched = false; + private boolean inZoom = false; + + private float initialDistance; + private float lastScale = 1.0f; + private float currentScale = 1.0f; + + private float boundaryLeft = 0; + private float boundaryTop = 0; + private float boundaryRight = 0; + private float boundaryBottom = 0; + + private float maxScale = 5.0f; + private float minScale = 0.25f; + private float fitScaleHorizontal = 1.0f; + private float fitScaleVertical = 1.0f; + + private int canvasWidth = 0; + private int canvasHeight = 0; + + private float centerX = 0; + private float centerY = 0; + + private float startingScale = 0; + + private boolean canDragX = false; + private boolean canDragY = false; + + private boolean multiTouch = false; + + private int displayWidth; + private int displayHeight; + + private int imageWidth; + private int imageHeight; + + private FlingListener flingListener; + private FlingAnimation flingAnimation; + private ZoomAnimation zoomAnimation; + private MoveAnimation moveAnimation; + private GestureDetector tapDetector; + private GestureDetector flingDetector; + private GestureImageViewListener imageListener; + + public GestureImageViewTouchListener(final GestureImageView image, int displayWidth, int displayHeight) { + super(); + + this.image = image; + + this.displayWidth = displayWidth; + this.displayHeight = displayHeight; + + this.centerX = (float) displayWidth / 2.0f; + this.centerY = (float) displayHeight / 2.0f; + + this.imageWidth = image.getImageWidth(); + this.imageHeight = image.getImageHeight(); + + startingScale = image.getScale(); + + currentScale = startingScale; + lastScale = startingScale; + + boundaryRight = displayWidth; + boundaryBottom = displayHeight; + boundaryLeft = 0; + boundaryTop = 0; + + next.x = image.getImageX(); + next.y = image.getImageY(); + + flingListener = new FlingListener(); + flingAnimation = new FlingAnimation(); + zoomAnimation = new ZoomAnimation(); + moveAnimation = new MoveAnimation(); + + flingAnimation.setListener(new FlingAnimationListener() { + @Override + public void onMove(float x, float y) { + handleDrag(current.x + x, current.y + y); + } + + @Override + public void onComplete() {} + }); + + zoomAnimation.setZoom(2.0f); + zoomAnimation.setZoomAnimationListener(new ZoomAnimationListener() { + @Override + public void onZoom(float scale, float x, float y) { + if(scale <= maxScale && scale >= minScale) { + handleScale(scale, x, y); + } + } + + @Override + public void onComplete() { + inZoom = false; + handleUp(); + } + }); + + moveAnimation.setMoveAnimationListener(new MoveAnimationListener() { + + @Override + public void onMove(float x, float y) { + image.setPosition(x, y); + image.redraw(); + } + }); + + tapDetector = new GestureDetector(image.getContext(), new SimpleOnGestureListener() { + @Override + public boolean onDoubleTap(MotionEvent e) { + startZoom(e); + return true; + } + + @Override + public boolean onSingleTapConfirmed(MotionEvent e) { + if(!inZoom) { + if(onClickListener != null) { + onClickListener.onClick(image); + return true; + } + } + + return false; + } + }); + + flingDetector = new GestureDetector(image.getContext(), flingListener); + imageListener = image.getGestureImageViewListener(); + + calculateBoundaries(); + } + + private void startFling() { + flingAnimation.setVelocityX(flingListener.getVelocityX()); + flingAnimation.setVelocityY(flingListener.getVelocityY()); + image.animationStart(flingAnimation); + } + + private void startZoom(MotionEvent e) { + inZoom = true; + zoomAnimation.reset(); + + float zoomTo; + + if(image.isLandscape()) { + if(image.getDeviceOrientation() == Configuration.ORIENTATION_PORTRAIT) { + int scaledHeight = image.getScaledHeight(); + + if(scaledHeight < canvasHeight) { + zoomTo = fitScaleVertical / currentScale; + zoomAnimation.setTouchX(e.getX()); + zoomAnimation.setTouchY(image.getCenterY()); + } + else { + zoomTo = fitScaleHorizontal / currentScale; + zoomAnimation.setTouchX(image.getCenterX()); + zoomAnimation.setTouchY(image.getCenterY()); + } + } + else { + int scaledWidth = image.getScaledWidth(); + + if(scaledWidth == canvasWidth) { + zoomTo = currentScale*4.0f; + zoomAnimation.setTouchX(e.getX()); + zoomAnimation.setTouchY(e.getY()); + } + else if(scaledWidth < canvasWidth) { + zoomTo = fitScaleHorizontal / currentScale; + zoomAnimation.setTouchX(image.getCenterX()); + zoomAnimation.setTouchY(e.getY()); + } + else { + zoomTo = fitScaleHorizontal / currentScale; + zoomAnimation.setTouchX(image.getCenterX()); + zoomAnimation.setTouchY(image.getCenterY()); + } + } + } + else { + if(image.getDeviceOrientation() == Configuration.ORIENTATION_PORTRAIT) { + + int scaledHeight = image.getScaledHeight(); + + if(scaledHeight == canvasHeight) { + zoomTo = currentScale*4.0f; + zoomAnimation.setTouchX(e.getX()); + zoomAnimation.setTouchY(e.getY()); + } + else if(scaledHeight < canvasHeight) { + zoomTo = fitScaleVertical / currentScale; + zoomAnimation.setTouchX(e.getX()); + zoomAnimation.setTouchY(image.getCenterY()); + } + else { + zoomTo = fitScaleVertical / currentScale; + zoomAnimation.setTouchX(image.getCenterX()); + zoomAnimation.setTouchY(image.getCenterY()); + } + } + else { + int scaledWidth = image.getScaledWidth(); + + if(scaledWidth < canvasWidth) { + zoomTo = fitScaleHorizontal / currentScale; + zoomAnimation.setTouchX(image.getCenterX()); + zoomAnimation.setTouchY(e.getY()); + } + else { + zoomTo = fitScaleVertical / currentScale; + zoomAnimation.setTouchX(image.getCenterX()); + zoomAnimation.setTouchY(image.getCenterY()); + } + } + } + + zoomAnimation.setZoom(zoomTo); + image.animationStart(zoomAnimation); + } + + + private void stopAnimations() { + image.animationStop(); + } + + @Override + public boolean onTouch(View v, MotionEvent event) { + + if(!inZoom) { + + if(!tapDetector.onTouchEvent(event)) { + if(event.getPointerCount() == 1 && flingDetector.onTouchEvent(event)) { + startFling(); + } + + if(event.getAction() == MotionEvent.ACTION_UP) { + handleUp(); + } + else if(event.getAction() == MotionEvent.ACTION_DOWN) { + stopAnimations(); + + last.x = event.getX(); + last.y = event.getY(); + + if(imageListener != null) { + imageListener.onTouch(last.x, last.y); + } + + touched = true; + } + else if(event.getAction() == MotionEvent.ACTION_MOVE) { + if(event.getPointerCount() > 1) { + multiTouch = true; + if(initialDistance > 0) { + + pinchVector.set(event); + pinchVector.calculateLength(); + + float distance = pinchVector.length; + + if(initialDistance != distance) { + + float newScale = (distance / initialDistance) * lastScale; + + if(newScale <= maxScale) { + scaleVector.length *= newScale; + + scaleVector.calculateEndPoint(); + + scaleVector.length /= newScale; + + float newX = scaleVector.end.x; + float newY = scaleVector.end.y; + + handleScale(newScale, newX, newY); + } + } + } + else { + initialDistance = MathUtils.distance(event); + + MathUtils.midpoint(event, midpoint); + + scaleVector.setStart(midpoint); + scaleVector.setEnd(next); + + scaleVector.calculateLength(); + scaleVector.calculateAngle(); + + scaleVector.length /= lastScale; + } + } + else { + if(!touched) { + touched = true; + last.x = event.getX(); + last.y = event.getY(); + next.x = image.getImageX(); + next.y = image.getImageY(); + } + else if(!multiTouch) { + if(handleDrag(event.getX(), event.getY())) { + image.redraw(); + } + } + } + } + } + } + + return true; + } + + protected void handleUp() { + + multiTouch = false; + + initialDistance = 0; + lastScale = currentScale; + + if(!canDragX) { + next.x = centerX; + } + + if(!canDragY) { + next.y = centerY; + } + + boundCoordinates(); + + if(!canDragX && !canDragY) { + + if(image.isLandscape()) { + currentScale = fitScaleHorizontal; + lastScale = fitScaleHorizontal; + } + else { + currentScale = fitScaleVertical; + lastScale = fitScaleVertical; + } + } + + image.setScale(currentScale); + image.setPosition(next.x, next.y); + + if(imageListener != null) { + imageListener.onScale(currentScale); + imageListener.onPosition(next.x, next.y); + } + + image.redraw(); + } + + protected void handleScale(float scale, float x, float y) { + + currentScale = scale; + + if(currentScale > maxScale) { + currentScale = maxScale; + } + else if (currentScale < minScale) { + currentScale = minScale; + } + else { + next.x = x; + next.y = y; + } + + calculateBoundaries(); + + image.setScale(currentScale); + image.setPosition(next.x, next.y); + + if(imageListener != null) { + imageListener.onScale(currentScale); + imageListener.onPosition(next.x, next.y); + } + + image.redraw(); + } + + protected boolean handleDrag(float x, float y) { + current.x = x; + current.y = y; + + float diffX = (current.x - last.x); + float diffY = (current.y - last.y); + + if(diffX != 0 || diffY != 0) { + + if(canDragX) next.x += diffX; + if(canDragY) next.y += diffY; + + boundCoordinates(); + + last.x = current.x; + last.y = current.y; + + if(canDragX || canDragY) { + image.setPosition(next.x, next.y); + + if(imageListener != null) { + imageListener.onPosition(next.x, next.y); + } + + return true; + } + } + + return false; + } + + public void reset() { + currentScale = startingScale; + next.x = centerX; + next.y = centerY; + calculateBoundaries(); + image.setScale(currentScale); + image.setPosition(next.x, next.y); + image.redraw(); + } + + + public float getMaxScale() { + return maxScale; + } + + public void setMaxScale(float maxScale) { + this.maxScale = maxScale; + } + + public float getMinScale() { + return minScale; + } + + public void setMinScale(float minScale) { + this.minScale = minScale; + } + + public void setOnClickListener(OnClickListener onClickListener) { + this.onClickListener = onClickListener; + } + + protected void setCanvasWidth(int canvasWidth) { + this.canvasWidth = canvasWidth; + } + + protected void setCanvasHeight(int canvasHeight) { + this.canvasHeight = canvasHeight; + } + + protected void setFitScaleHorizontal(float fitScale) { + this.fitScaleHorizontal = fitScale; + } + + protected void setFitScaleVertical(float fitScaleVertical) { + this.fitScaleVertical = fitScaleVertical; + } + + protected void boundCoordinates() { + if(next.x < boundaryLeft) { + next.x = boundaryLeft; + } + else if(next.x > boundaryRight) { + next.x = boundaryRight; + } + + if(next.y < boundaryTop) { + next.y = boundaryTop; + } + else if(next.y > boundaryBottom) { + next.y = boundaryBottom; + } + } + + protected void calculateBoundaries() { + + int effectiveWidth = Math.round( (float) imageWidth * currentScale ); + int effectiveHeight = Math.round( (float) imageHeight * currentScale ); + + canDragX = effectiveWidth > displayWidth; + canDragY = effectiveHeight > displayHeight; + + if(canDragX) { + float diff = (float)(effectiveWidth - displayWidth) / 2.0f; + boundaryLeft = centerX - diff; + boundaryRight = centerX + diff; + } + + if(canDragY) { + float diff = (float)(effectiveHeight - displayHeight) / 2.0f; + boundaryTop = centerY - diff; + boundaryBottom = centerY + diff; + } + } +} diff --git a/gestureimageview/src/main/java/com/polites/android/MathUtils.java b/gestureimageview/src/main/java/com/polites/android/MathUtils.java new file mode 100644 index 0000000..187f78e --- /dev/null +++ b/gestureimageview/src/main/java/com/polites/android/MathUtils.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2012 Jason Polites + * + * 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.polites.android; + +import android.graphics.PointF; +import android.util.FloatMath; +import android.view.MotionEvent; + +public class MathUtils { + + public static float distance(MotionEvent event) { + float x = event.getX(0) - event.getX(1); + float y = event.getY(0) - event.getY(1); + return FloatMath.sqrt(x * x + y * y); + } + + public static float distance(PointF p1, PointF p2) { + float x = p1.x - p2.x; + float y = p1.y - p2.y; + return FloatMath.sqrt(x * x + y * y); + } + + public static float distance(float x1, float y1, float x2, float y2) { + float x = x1 - x2; + float y = y1 - y2; + return FloatMath.sqrt(x * x + y * y); + } + + public static void midpoint(MotionEvent event, PointF point) { + float x1 = event.getX(0); + float y1 = event.getY(0); + float x2 = event.getX(1); + float y2 = event.getY(1); + midpoint(x1, y1, x2, y2, point); + } + + public static void midpoint(float x1, float y1, float x2, float y2, PointF point) { + point.x = (x1 + x2) / 2.0f; + point.y = (y1 + y2) / 2.0f; + } + + /** + * Rotates p1 around p2 by angle degrees. + * + * @param p1 + * @param p2 + * @param angle + */ + public void rotate(PointF p1, PointF p2, float angle) { + float px = p1.x; + float py = p1.y; + float ox = p2.x; + float oy = p2.y; + p1.x = (FloatMath.cos(angle) * (px - ox) - FloatMath.sin(angle) * (py - oy) + ox); + p1.y = (FloatMath.sin(angle) * (px - ox) + FloatMath.cos(angle) * (py - oy) + oy); + } + + public static float angle(PointF p1, PointF p2) { + return angle(p1.x, p1.y, p2.x, p2.y); + } + + public static float angle(float x1, float y1, float x2, float y2) { + return (float) Math.atan2(y2 - y1, x2 - x1); + } +} diff --git a/gestureimageview/src/main/java/com/polites/android/MoveAnimation.java b/gestureimageview/src/main/java/com/polites/android/MoveAnimation.java new file mode 100644 index 0000000..ccb8812 --- /dev/null +++ b/gestureimageview/src/main/java/com/polites/android/MoveAnimation.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2012 Jason Polites + * + * 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.polites.android; + + +/** + * @author Jason Polites + * + */ +public class MoveAnimation implements Animation { + + private boolean firstFrame = true; + + private float startX; + private float startY; + + private float targetX; + private float targetY; + private long animationTimeMS = 100; + private long totalTime = 0; + + private MoveAnimationListener moveAnimationListener; + + /* (non-Javadoc) + * @see com.polites.android.Animation#update(com.polites.android.GestureImageView, long) + */ + @Override + public boolean update(GestureImageView view, long time) { + totalTime += time; + + if(firstFrame) { + firstFrame = false; + startX = view.getImageX(); + startY = view.getImageY(); + } + + if(totalTime < animationTimeMS) { + + float ratio = (float) totalTime / animationTimeMS; + + float newX = ((targetX - startX) * ratio) + startX; + float newY = ((targetY - startY) * ratio) + startY; + + if(moveAnimationListener != null) { + moveAnimationListener.onMove(newX, newY); + } + + return true; + } + else { + if(moveAnimationListener != null) { + moveAnimationListener.onMove(targetX, targetY); + } + } + + return false; + } + + public void reset() { + firstFrame = true; + totalTime = 0; + } + + + public float getTargetX() { + return targetX; + } + + + public void setTargetX(float targetX) { + this.targetX = targetX; + } + + + public float getTargetY() { + return targetY; + } + + public void setTargetY(float targetY) { + this.targetY = targetY; + } + + public long getAnimationTimeMS() { + return animationTimeMS; + } + + public void setAnimationTimeMS(long animationTimeMS) { + this.animationTimeMS = animationTimeMS; + } + + public void setMoveAnimationListener(MoveAnimationListener moveAnimationListener) { + this.moveAnimationListener = moveAnimationListener; + } +} diff --git a/gestureimageview/src/main/java/com/polites/android/MoveAnimationListener.java b/gestureimageview/src/main/java/com/polites/android/MoveAnimationListener.java new file mode 100644 index 0000000..cb570b2 --- /dev/null +++ b/gestureimageview/src/main/java/com/polites/android/MoveAnimationListener.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2012 Jason Polites + * + * 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.polites.android; + + +/** + * @author Jason Polites + * + */ +public interface MoveAnimationListener { + + public void onMove(float x, float y); + +} diff --git a/gestureimageview/src/main/java/com/polites/android/VectorF.java b/gestureimageview/src/main/java/com/polites/android/VectorF.java new file mode 100644 index 0000000..ce23663 --- /dev/null +++ b/gestureimageview/src/main/java/com/polites/android/VectorF.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2012 Jason Polites + * + * 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.polites.android; + +import android.graphics.PointF; +import android.util.FloatMath; +import android.view.MotionEvent; + +public class VectorF { + + public float angle; + public float length; + + public final PointF start = new PointF(); + public final PointF end = new PointF(); + + public void calculateEndPoint() { + end.x = FloatMath.cos(angle) * length + start.x; + end.y = FloatMath.sin(angle) * length + start.y; + } + + public void setStart(PointF p) { + this.start.x = p.x; + this.start.y = p.y; + } + + public void setEnd(PointF p) { + this.end.x = p.x; + this.end.y = p.y; + } + + public void set(MotionEvent event) { + this.start.x = event.getX(0); + this.start.y = event.getY(0); + this.end.x = event.getX(1); + this.end.y = event.getY(1); + } + + public float calculateLength() { + length = MathUtils.distance(start, end); + return length; + } + + public float calculateAngle() { + angle = MathUtils.angle(start, end); + return angle; + } + + +} diff --git a/gestureimageview/src/main/java/com/polites/android/ZoomAnimation.java b/gestureimageview/src/main/java/com/polites/android/ZoomAnimation.java new file mode 100644 index 0000000..5cceeb0 --- /dev/null +++ b/gestureimageview/src/main/java/com/polites/android/ZoomAnimation.java @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2012 Jason Polites + * + * 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.polites.android; + +import android.graphics.PointF; + + +/** + * @author Jason Polites + * + */ +public class ZoomAnimation implements Animation { + + private boolean firstFrame = true; + + private float touchX; + private float touchY; + + private float zoom; + + private float startX; + private float startY; + private float startScale; + + private float xDiff; + private float yDiff; + private float scaleDiff; + + private long animationLengthMS = 200; + private long totalTime = 0; + + private ZoomAnimationListener zoomAnimationListener; + + /* (non-Javadoc) + * @see com.polites.android.Animation#update(com.polites.android.GestureImageView, long) + */ + @Override + public boolean update(GestureImageView view, long time) { + if(firstFrame) { + firstFrame = false; + + startX = view.getImageX(); + startY = view.getImageY(); + startScale = view.getScale(); + scaleDiff = (zoom * startScale) - startScale; + + if(scaleDiff > 0) { + // Calculate destination for midpoint + VectorF vector = new VectorF(); + + // Set the touch point as start because we want to move the end + vector.setStart(new PointF(touchX, touchY)); + vector.setEnd(new PointF(startX, startY)); + + vector.calculateAngle(); + + // Get the current length + float length = vector.calculateLength(); + + // Multiply length by zoom to get the new length + vector.length = length*zoom; + + // Now deduce the new endpoint + vector.calculateEndPoint(); + + xDiff = vector.end.x - startX; + yDiff = vector.end.y - startY; + } + else { + // Zoom out to center + xDiff = view.getCenterX() - startX; + yDiff = view.getCenterY() - startY; + } + } + + totalTime += time; + + float ratio = (float) totalTime / (float) animationLengthMS; + + if(ratio < 1) { + + if(ratio > 0) { + // we still have time left + float newScale = (ratio * scaleDiff) + startScale; + float newX = (ratio * xDiff) + startX; + float newY = (ratio * yDiff) + startY; + + if(zoomAnimationListener != null) { + zoomAnimationListener.onZoom(newScale, newX, newY); + } + } + + return true; + } + else { + + float newScale = scaleDiff + startScale; + float newX = xDiff + startX; + float newY = yDiff + startY; + + if(zoomAnimationListener != null) { + zoomAnimationListener.onZoom(newScale, newX, newY); + zoomAnimationListener.onComplete(); + } + + return false; + } + } + + public void reset() { + firstFrame = true; + totalTime = 0; + } + + public float getZoom() { + return zoom; + } + + public void setZoom(float zoom) { + this.zoom = zoom; + } + + public float getTouchX() { + return touchX; + } + + public void setTouchX(float touchX) { + this.touchX = touchX; + } + + public float getTouchY() { + return touchY; + } + + public void setTouchY(float touchY) { + this.touchY = touchY; + } + + public long getAnimationLengthMS() { + return animationLengthMS; + } + + public void setAnimationLengthMS(long animationLengthMS) { + this.animationLengthMS = animationLengthMS; + } + + public ZoomAnimationListener getZoomAnimationListener() { + return zoomAnimationListener; + } + + public void setZoomAnimationListener(ZoomAnimationListener zoomAnimationListener) { + this.zoomAnimationListener = zoomAnimationListener; + } +} diff --git a/gestureimageview/src/main/java/com/polites/android/ZoomAnimationListener.java b/gestureimageview/src/main/java/com/polites/android/ZoomAnimationListener.java new file mode 100644 index 0000000..4d50898 --- /dev/null +++ b/gestureimageview/src/main/java/com/polites/android/ZoomAnimationListener.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2012 Jason Polites + * + * 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.polites.android; + + +/** + * @author Jason Polites + * + */ +public interface ZoomAnimationListener { + public void onZoom(float scale, float x, float y); + public void onComplete(); +} diff --git a/import-summary.txt b/import-summary.txt index 36146c6..a66c6fd 100644 --- a/import-summary.txt +++ b/import-summary.txt @@ -7,22 +7,10 @@ The following files were *not* copied into the new Gradle project; you should evaluate whether these are still needed in your project and if so manually move them: -* .idea/ -* .idea/.name -* .idea/compiler.xml -* .idea/copyright/ -* .idea/copyright/profiles_settings.xml -* .idea/libraries/ -* .idea/libraries/PdfViewer.xml -* .idea/misc.xml -* .idea/modules.xml -* .idea/vcs.xml -* .idea/workspace.xml -* Android-Pdf-Viewer-Library.iml -* PdfViewer.jar -* README.txt +* .DS_Store +* .gitignore * build.xml -* default.properties +* gesture-imageview.iml * proguard.cfg Moved Files: @@ -30,28 +18,11 @@ Moved Files: Android Gradle projects use a different directory structure than ADT Eclipse projects. Here's how the projects were restructured: -* AndroidManifest.xml => app/src/main/AndroidManifest.xml -* crypto-src/ => app/src/main/java/ -* res/ => app/src/main/res/ -* src/ => app/src/main/java/ -* src/com/sun/pdfview/.cvsignore => app/src/main/resources/com/sun/pdfview/.cvsignore -* src/com/sun/pdfview/decode/CCITTCodes => app/src/main/resources/com/sun/pdfview/decode/CCITTCodes -* src/com/sun/pdfview/font/res/BaseFonts.properties => app/src/main/resources/com/sun/pdfview/font/res/BaseFonts.properties -* src/com/sun/pdfview/font/res/d050000l.pfb => app/src/main/resources/com/sun/pdfview/font/res/d050000l.pfb -* src/com/sun/pdfview/font/res/n019003l.pfb => app/src/main/resources/com/sun/pdfview/font/res/n019003l.pfb -* src/com/sun/pdfview/font/res/n019004l.pfb => app/src/main/resources/com/sun/pdfview/font/res/n019004l.pfb -* src/com/sun/pdfview/font/res/n019023l.pfb => app/src/main/resources/com/sun/pdfview/font/res/n019023l.pfb -* src/com/sun/pdfview/font/res/n019024l.pfb => app/src/main/resources/com/sun/pdfview/font/res/n019024l.pfb -* src/com/sun/pdfview/font/res/n021003l.pfb => app/src/main/resources/com/sun/pdfview/font/res/n021003l.pfb -* src/com/sun/pdfview/font/res/n021004l.pfb => app/src/main/resources/com/sun/pdfview/font/res/n021004l.pfb -* src/com/sun/pdfview/font/res/n021023l.pfb => app/src/main/resources/com/sun/pdfview/font/res/n021023l.pfb -* src/com/sun/pdfview/font/res/n021024l.pfb => app/src/main/resources/com/sun/pdfview/font/res/n021024l.pfb -* src/com/sun/pdfview/font/res/n022003l.pfb => app/src/main/resources/com/sun/pdfview/font/res/n022003l.pfb -* src/com/sun/pdfview/font/res/n022004l.pfb => app/src/main/resources/com/sun/pdfview/font/res/n022004l.pfb -* src/com/sun/pdfview/font/res/n022023l.pfb => app/src/main/resources/com/sun/pdfview/font/res/n022023l.pfb -* src/com/sun/pdfview/font/res/n022024l.pfb => app/src/main/resources/com/sun/pdfview/font/res/n022024l.pfb -* src/com/sun/pdfview/font/res/s050000l.pfb => app/src/main/resources/com/sun/pdfview/font/res/s050000l.pfb -* src/com/sun/pdfview/font/ttf/resource/glyphlist.txt => app/src/main/resources/com/sun/pdfview/font/ttf/resource/glyphlist.txt +* AndroidManifest.xml => gestureimageview/src/main/AndroidManifest.xml +* src/ => gestureimageview/src/main/java/ +* src/.DS_Store => gestureimageview/src/main/resources/.DS_Store +* src/com/.DS_Store => gestureimageview/src/main/resources/com/.DS_Store +* src/com/polites/.DS_Store => gestureimageview/src/main/resources/com/polites/.DS_Store Next Steps: ----------- diff --git a/pdfviewsample/src/main/res/layout/activity_main2.xml b/pdfviewsample/src/main/res/layout/activity_main2.xml index 6a3c4d7..fc0e60a 100644 --- a/pdfviewsample/src/main/res/layout/activity_main2.xml +++ b/pdfviewsample/src/main/res/layout/activity_main2.xml @@ -7,8 +7,8 @@ diff --git a/settings.gradle b/settings.gradle index 0dbb0ca..8f90eb5 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1,2 @@ include ':PdfView', ':pdfviewsample' +include ':gestureimageview'