summaryrefslogtreecommitdiffstats
path: root/WallpaperPicker/src/com/android/gallery3d
diff options
context:
space:
mode:
Diffstat (limited to 'WallpaperPicker/src/com/android/gallery3d')
-rw-r--r--WallpaperPicker/src/com/android/gallery3d/common/BitmapCropTask.java405
-rw-r--r--WallpaperPicker/src/com/android/gallery3d/common/BitmapUtils.java253
-rw-r--r--WallpaperPicker/src/com/android/gallery3d/common/Utils.java271
-rw-r--r--WallpaperPicker/src/com/android/gallery3d/exif/ExifInterface.java6
-rw-r--r--WallpaperPicker/src/com/android/gallery3d/glrenderer/BasicTexture.java1
-rw-r--r--WallpaperPicker/src/com/android/gallery3d/glrenderer/BitmapTexture.java4
-rw-r--r--WallpaperPicker/src/com/android/gallery3d/glrenderer/GLES20Canvas.java3
-rw-r--r--WallpaperPicker/src/com/android/gallery3d/glrenderer/GLPaint.java4
-rw-r--r--WallpaperPicker/src/com/android/gallery3d/glrenderer/IntArray.java (renamed from WallpaperPicker/src/com/android/gallery3d/util/IntArray.java)2
-rw-r--r--WallpaperPicker/src/com/android/gallery3d/glrenderer/UploadedTexture.java9
10 files changed, 486 insertions, 472 deletions
diff --git a/WallpaperPicker/src/com/android/gallery3d/common/BitmapCropTask.java b/WallpaperPicker/src/com/android/gallery3d/common/BitmapCropTask.java
new file mode 100644
index 000000000..45118bf45
--- /dev/null
+++ b/WallpaperPicker/src/com/android/gallery3d/common/BitmapCropTask.java
@@ -0,0 +1,405 @@
+/**
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * 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.android.gallery3d.common;
+
+import android.app.WallpaperManager;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.CompressFormat;
+import android.graphics.BitmapFactory;
+import android.graphics.BitmapRegionDecoder;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.util.Log;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class BitmapCropTask extends AsyncTask<Void, Void, Boolean> {
+
+ public interface OnBitmapCroppedHandler {
+ public void onBitmapCropped(byte[] imageBytes);
+ }
+
+ private static final int DEFAULT_COMPRESS_QUALITY = 90;
+ private static final String LOGTAG = "BitmapCropTask";
+
+ Uri mInUri = null;
+ Context mContext;
+ String mInFilePath;
+ byte[] mInImageBytes;
+ int mInResId = 0;
+ RectF mCropBounds = null;
+ int mOutWidth, mOutHeight;
+ int mRotation;
+ boolean mSetWallpaper;
+ boolean mSaveCroppedBitmap;
+ Bitmap mCroppedBitmap;
+ Runnable mOnEndRunnable;
+ Resources mResources;
+ BitmapCropTask.OnBitmapCroppedHandler mOnBitmapCroppedHandler;
+ boolean mNoCrop;
+
+ public BitmapCropTask(Context c, String filePath,
+ RectF cropBounds, int rotation, int outWidth, int outHeight,
+ boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
+ mContext = c;
+ mInFilePath = filePath;
+ init(cropBounds, rotation,
+ outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
+ }
+
+ public BitmapCropTask(byte[] imageBytes,
+ RectF cropBounds, int rotation, int outWidth, int outHeight,
+ boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
+ mInImageBytes = imageBytes;
+ init(cropBounds, rotation,
+ outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
+ }
+
+ public BitmapCropTask(Context c, Uri inUri,
+ RectF cropBounds, int rotation, int outWidth, int outHeight,
+ boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
+ mContext = c;
+ mInUri = inUri;
+ init(cropBounds, rotation,
+ outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
+ }
+
+ public BitmapCropTask(Context c, Resources res, int inResId,
+ RectF cropBounds, int rotation, int outWidth, int outHeight,
+ boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
+ mContext = c;
+ mInResId = inResId;
+ mResources = res;
+ init(cropBounds, rotation,
+ outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
+ }
+
+ private void init(RectF cropBounds, int rotation, int outWidth, int outHeight,
+ boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
+ mCropBounds = cropBounds;
+ mRotation = rotation;
+ mOutWidth = outWidth;
+ mOutHeight = outHeight;
+ mSetWallpaper = setWallpaper;
+ mSaveCroppedBitmap = saveCroppedBitmap;
+ mOnEndRunnable = onEndRunnable;
+ }
+
+ public void setOnBitmapCropped(BitmapCropTask.OnBitmapCroppedHandler handler) {
+ mOnBitmapCroppedHandler = handler;
+ }
+
+ public void setNoCrop(boolean value) {
+ mNoCrop = value;
+ }
+
+ public void setOnEndRunnable(Runnable onEndRunnable) {
+ mOnEndRunnable = onEndRunnable;
+ }
+
+ // Helper to setup input stream
+ private InputStream regenerateInputStream() {
+ if (mInUri == null && mInResId == 0 && mInFilePath == null && mInImageBytes == null) {
+ Log.w(LOGTAG, "cannot read original file, no input URI, resource ID, or " +
+ "image byte array given");
+ } else {
+ try {
+ if (mInUri != null) {
+ return new BufferedInputStream(
+ mContext.getContentResolver().openInputStream(mInUri));
+ } else if (mInFilePath != null) {
+ return mContext.openFileInput(mInFilePath);
+ } else if (mInImageBytes != null) {
+ return new BufferedInputStream(new ByteArrayInputStream(mInImageBytes));
+ } else {
+ return new BufferedInputStream(mResources.openRawResource(mInResId));
+ }
+ } catch (FileNotFoundException e) {
+ Log.w(LOGTAG, "cannot read file: " + mInUri.toString(), e);
+ }
+ }
+ return null;
+ }
+
+ public Point getImageBounds() {
+ InputStream is = regenerateInputStream();
+ if (is != null) {
+ BitmapFactory.Options options = new BitmapFactory.Options();
+ options.inJustDecodeBounds = true;
+ BitmapFactory.decodeStream(is, null, options);
+ Utils.closeSilently(is);
+ if (options.outWidth != 0 && options.outHeight != 0) {
+ return new Point(options.outWidth, options.outHeight);
+ }
+ }
+ return null;
+ }
+
+ public void setCropBounds(RectF cropBounds) {
+ mCropBounds = cropBounds;
+ }
+
+ public Bitmap getCroppedBitmap() {
+ return mCroppedBitmap;
+ }
+ public boolean cropBitmap() {
+ boolean failure = false;
+
+
+ WallpaperManager wallpaperManager = null;
+ if (mSetWallpaper) {
+ wallpaperManager = WallpaperManager.getInstance(mContext.getApplicationContext());
+ }
+
+
+ if (mSetWallpaper && mNoCrop) {
+ try {
+ InputStream is = regenerateInputStream();
+ if (is != null) {
+ wallpaperManager.setStream(is);
+ Utils.closeSilently(is);
+ }
+ } catch (IOException e) {
+ Log.w(LOGTAG, "cannot write stream to wallpaper", e);
+ failure = true;
+ }
+ return !failure;
+ } else {
+ // Find crop bounds (scaled to original image size)
+ Rect roundedTrueCrop = new Rect();
+ Matrix rotateMatrix = new Matrix();
+ Matrix inverseRotateMatrix = new Matrix();
+
+ Point bounds = getImageBounds();
+ if (mRotation > 0) {
+ rotateMatrix.setRotate(mRotation);
+ inverseRotateMatrix.setRotate(-mRotation);
+
+ mCropBounds.roundOut(roundedTrueCrop);
+ mCropBounds = new RectF(roundedTrueCrop);
+
+ if (bounds == null) {
+ Log.w(LOGTAG, "cannot get bounds for image");
+ failure = true;
+ return false;
+ }
+
+ float[] rotatedBounds = new float[] { bounds.x, bounds.y };
+ rotateMatrix.mapPoints(rotatedBounds);
+ rotatedBounds[0] = Math.abs(rotatedBounds[0]);
+ rotatedBounds[1] = Math.abs(rotatedBounds[1]);
+
+ mCropBounds.offset(-rotatedBounds[0]/2, -rotatedBounds[1]/2);
+ inverseRotateMatrix.mapRect(mCropBounds);
+ mCropBounds.offset(bounds.x/2, bounds.y/2);
+
+ }
+
+ mCropBounds.roundOut(roundedTrueCrop);
+
+ if (roundedTrueCrop.width() <= 0 || roundedTrueCrop.height() <= 0) {
+ Log.w(LOGTAG, "crop has bad values for full size image");
+ failure = true;
+ return false;
+ }
+
+ // See how much we're reducing the size of the image
+ int scaleDownSampleSize = Math.max(1, Math.min(roundedTrueCrop.width() / mOutWidth,
+ roundedTrueCrop.height() / mOutHeight));
+ // Attempt to open a region decoder
+ BitmapRegionDecoder decoder = null;
+ InputStream is = null;
+ try {
+ is = regenerateInputStream();
+ if (is == null) {
+ Log.w(LOGTAG, "cannot get input stream for uri=" + mInUri.toString());
+ failure = true;
+ return false;
+ }
+ decoder = BitmapRegionDecoder.newInstance(is, false);
+ Utils.closeSilently(is);
+ } catch (IOException e) {
+ Log.w(LOGTAG, "cannot open region decoder for file: " + mInUri.toString(), e);
+ } finally {
+ Utils.closeSilently(is);
+ is = null;
+ }
+
+ Bitmap crop = null;
+ if (decoder != null) {
+ // Do region decoding to get crop bitmap
+ BitmapFactory.Options options = new BitmapFactory.Options();
+ if (scaleDownSampleSize > 1) {
+ options.inSampleSize = scaleDownSampleSize;
+ }
+ crop = decoder.decodeRegion(roundedTrueCrop, options);
+ decoder.recycle();
+ }
+
+ if (crop == null) {
+ // BitmapRegionDecoder has failed, try to crop in-memory
+ is = regenerateInputStream();
+ Bitmap fullSize = null;
+ if (is != null) {
+ BitmapFactory.Options options = new BitmapFactory.Options();
+ if (scaleDownSampleSize > 1) {
+ options.inSampleSize = scaleDownSampleSize;
+ }
+ fullSize = BitmapFactory.decodeStream(is, null, options);
+ Utils.closeSilently(is);
+ }
+ if (fullSize != null) {
+ // Find out the true sample size that was used by the decoder
+ scaleDownSampleSize = bounds.x / fullSize.getWidth();
+ mCropBounds.left /= scaleDownSampleSize;
+ mCropBounds.top /= scaleDownSampleSize;
+ mCropBounds.bottom /= scaleDownSampleSize;
+ mCropBounds.right /= scaleDownSampleSize;
+ mCropBounds.roundOut(roundedTrueCrop);
+
+ // Adjust values to account for issues related to rounding
+ if (roundedTrueCrop.width() > fullSize.getWidth()) {
+ // Adjust the width
+ roundedTrueCrop.right = roundedTrueCrop.left + fullSize.getWidth();
+ }
+ if (roundedTrueCrop.right > fullSize.getWidth()) {
+ // Adjust the left value
+ int adjustment = roundedTrueCrop.left -
+ Math.max(0, roundedTrueCrop.right - roundedTrueCrop.width());
+ roundedTrueCrop.left -= adjustment;
+ roundedTrueCrop.right -= adjustment;
+ }
+ if (roundedTrueCrop.height() > fullSize.getHeight()) {
+ // Adjust the height
+ roundedTrueCrop.bottom = roundedTrueCrop.top + fullSize.getHeight();
+ }
+ if (roundedTrueCrop.bottom > fullSize.getHeight()) {
+ // Adjust the top value
+ int adjustment = roundedTrueCrop.top -
+ Math.max(0, roundedTrueCrop.bottom - roundedTrueCrop.height());
+ roundedTrueCrop.top -= adjustment;
+ roundedTrueCrop.bottom -= adjustment;
+ }
+
+ crop = Bitmap.createBitmap(fullSize, roundedTrueCrop.left,
+ roundedTrueCrop.top, roundedTrueCrop.width(),
+ roundedTrueCrop.height());
+ }
+ }
+
+ if (crop == null) {
+ Log.w(LOGTAG, "cannot decode file: " + mInUri.toString());
+ failure = true;
+ return false;
+ }
+ if (mOutWidth > 0 && mOutHeight > 0 || mRotation > 0) {
+ float[] dimsAfter = new float[] { crop.getWidth(), crop.getHeight() };
+ rotateMatrix.mapPoints(dimsAfter);
+ dimsAfter[0] = Math.abs(dimsAfter[0]);
+ dimsAfter[1] = Math.abs(dimsAfter[1]);
+
+ if (!(mOutWidth > 0 && mOutHeight > 0)) {
+ mOutWidth = Math.round(dimsAfter[0]);
+ mOutHeight = Math.round(dimsAfter[1]);
+ }
+
+ RectF cropRect = new RectF(0, 0, dimsAfter[0], dimsAfter[1]);
+ RectF returnRect = new RectF(0, 0, mOutWidth, mOutHeight);
+
+ Matrix m = new Matrix();
+ if (mRotation == 0) {
+ m.setRectToRect(cropRect, returnRect, Matrix.ScaleToFit.FILL);
+ } else {
+ Matrix m1 = new Matrix();
+ m1.setTranslate(-crop.getWidth() / 2f, -crop.getHeight() / 2f);
+ Matrix m2 = new Matrix();
+ m2.setRotate(mRotation);
+ Matrix m3 = new Matrix();
+ m3.setTranslate(dimsAfter[0] / 2f, dimsAfter[1] / 2f);
+ Matrix m4 = new Matrix();
+ m4.setRectToRect(cropRect, returnRect, Matrix.ScaleToFit.FILL);
+
+ Matrix c1 = new Matrix();
+ c1.setConcat(m2, m1);
+ Matrix c2 = new Matrix();
+ c2.setConcat(m4, m3);
+ m.setConcat(c2, c1);
+ }
+
+ Bitmap tmp = Bitmap.createBitmap((int) returnRect.width(),
+ (int) returnRect.height(), Bitmap.Config.ARGB_8888);
+ if (tmp != null) {
+ Canvas c = new Canvas(tmp);
+ Paint p = new Paint();
+ p.setFilterBitmap(true);
+ c.drawBitmap(crop, m, p);
+ crop = tmp;
+ }
+ }
+
+ if (mSaveCroppedBitmap) {
+ mCroppedBitmap = crop;
+ }
+
+ // Compress to byte array
+ ByteArrayOutputStream tmpOut = new ByteArrayOutputStream(2048);
+ if (crop.compress(CompressFormat.JPEG, DEFAULT_COMPRESS_QUALITY, tmpOut)) {
+ // If we need to set to the wallpaper, set it
+ if (mSetWallpaper && wallpaperManager != null) {
+ try {
+ byte[] outByteArray = tmpOut.toByteArray();
+ wallpaperManager.setStream(new ByteArrayInputStream(outByteArray));
+ if (mOnBitmapCroppedHandler != null) {
+ mOnBitmapCroppedHandler.onBitmapCropped(outByteArray);
+ }
+ } catch (IOException e) {
+ Log.w(LOGTAG, "cannot write stream to wallpaper", e);
+ failure = true;
+ }
+ }
+ } else {
+ Log.w(LOGTAG, "cannot compress bitmap");
+ failure = true;
+ }
+ }
+ return !failure; // True if any of the operations failed
+ }
+
+ @Override
+ protected Boolean doInBackground(Void... params) {
+ return cropBitmap();
+ }
+
+ @Override
+ protected void onPostExecute(Boolean result) {
+ if (mOnEndRunnable != null) {
+ mOnEndRunnable.run();
+ }
+ }
+} \ No newline at end of file
diff --git a/WallpaperPicker/src/com/android/gallery3d/common/BitmapUtils.java b/WallpaperPicker/src/com/android/gallery3d/common/BitmapUtils.java
index a671ed2b9..9ac5c1bf7 100644
--- a/WallpaperPicker/src/com/android/gallery3d/common/BitmapUtils.java
+++ b/WallpaperPicker/src/com/android/gallery3d/common/BitmapUtils.java
@@ -16,87 +16,24 @@
package com.android.gallery3d.common;
-import android.graphics.Bitmap;
-import android.graphics.Bitmap.CompressFormat;
-import android.graphics.BitmapFactory;
-import android.graphics.Canvas;
-import android.graphics.Matrix;
-import android.graphics.Paint;
-import android.os.Build;
-import android.util.FloatMath;
+import android.content.Context;
+import android.content.res.Resources;
+import android.net.Uri;
import android.util.Log;
-import java.io.ByteArrayOutputStream;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
+import com.android.gallery3d.exif.ExifInterface;
-public class BitmapUtils {
- private static final String TAG = "BitmapUtils";
- private static final int DEFAULT_JPEG_QUALITY = 90;
- public static final int UNCONSTRAINED = -1;
-
- private BitmapUtils(){}
-
- /*
- * Compute the sample size as a function of minSideLength
- * and maxNumOfPixels.
- * minSideLength is used to specify that minimal width or height of a
- * bitmap.
- * maxNumOfPixels is used to specify the maximal size in pixels that is
- * tolerable in terms of memory usage.
- *
- * The function returns a sample size based on the constraints.
- * Both size and minSideLength can be passed in as UNCONSTRAINED,
- * which indicates no care of the corresponding constraint.
- * The functions prefers returning a sample size that
- * generates a smaller bitmap, unless minSideLength = UNCONSTRAINED.
- *
- * Also, the function rounds up the sample size to a power of 2 or multiple
- * of 8 because BitmapFactory only honors sample size this way.
- * For example, BitmapFactory downsamples an image by 2 even though the
- * request is 3. So we round up the sample size to avoid OOM.
- */
- public static int computeSampleSize(int width, int height,
- int minSideLength, int maxNumOfPixels) {
- int initialSize = computeInitialSampleSize(
- width, height, minSideLength, maxNumOfPixels);
-
- return initialSize <= 8
- ? Utils.nextPowerOf2(initialSize)
- : (initialSize + 7) / 8 * 8;
- }
-
- private static int computeInitialSampleSize(int w, int h,
- int minSideLength, int maxNumOfPixels) {
- if (maxNumOfPixels == UNCONSTRAINED
- && minSideLength == UNCONSTRAINED) return 1;
-
- int lowerBound = (maxNumOfPixels == UNCONSTRAINED) ? 1 :
- (int) FloatMath.ceil(FloatMath.sqrt((float) (w * h) / maxNumOfPixels));
-
- if (minSideLength == UNCONSTRAINED) {
- return lowerBound;
- } else {
- int sampleSize = Math.min(w / minSideLength, h / minSideLength);
- return Math.max(sampleSize, lowerBound);
- }
- }
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
- // This computes a sample size which makes the longer side at least
- // minSideLength long. If that's not possible, return 1.
- public static int computeSampleSizeLarger(int w, int h,
- int minSideLength) {
- int initialSize = Math.max(w / minSideLength, h / minSideLength);
- if (initialSize <= 1) return 1;
+public class BitmapUtils {
- return initialSize <= 8
- ? Utils.prevPowerOf2(initialSize)
- : initialSize / 8 * 8;
- }
+ private static final String TAG = "BitmapUtils";
// Find the min x that 1 / x >= scale
public static int computeSampleSizeLarger(float scale) {
- int initialSize = (int) FloatMath.floor(1f / scale);
+ int initialSize = (int) Math.floor(1f / scale);
if (initialSize <= 1) return 1;
return initialSize <= 8
@@ -104,157 +41,41 @@ public class BitmapUtils {
: initialSize / 8 * 8;
}
- // Find the max x that 1 / x <= scale.
- public static int computeSampleSize(float scale) {
- Utils.assertTrue(scale > 0);
- int initialSize = Math.max(1, (int) FloatMath.ceil(1 / scale));
- return initialSize <= 8
- ? Utils.nextPowerOf2(initialSize)
- : (initialSize + 7) / 8 * 8;
- }
-
- public static Bitmap resizeBitmapByScale(
- Bitmap bitmap, float scale, boolean recycle) {
- int width = Math.round(bitmap.getWidth() * scale);
- int height = Math.round(bitmap.getHeight() * scale);
- if (width == bitmap.getWidth()
- && height == bitmap.getHeight()) return bitmap;
- Bitmap target = Bitmap.createBitmap(width, height, getConfig(bitmap));
- Canvas canvas = new Canvas(target);
- canvas.scale(scale, scale);
- Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG);
- canvas.drawBitmap(bitmap, 0, 0, paint);
- if (recycle) bitmap.recycle();
- return target;
+ public static int getRotationFromExif(Context context, Uri uri) {
+ return BitmapUtils.getRotationFromExifHelper(null, 0, context, uri);
}
- private static Bitmap.Config getConfig(Bitmap bitmap) {
- Bitmap.Config config = bitmap.getConfig();
- if (config == null) {
- config = Bitmap.Config.ARGB_8888;
- }
- return config;
+ public static int getRotationFromExif(Resources res, int resId) {
+ return BitmapUtils.getRotationFromExifHelper(res, resId, null, null);
}
- public static Bitmap resizeDownBySideLength(
- Bitmap bitmap, int maxLength, boolean recycle) {
- int srcWidth = bitmap.getWidth();
- int srcHeight = bitmap.getHeight();
- float scale = Math.min(
- (float) maxLength / srcWidth, (float) maxLength / srcHeight);
- if (scale >= 1.0f) return bitmap;
- return resizeBitmapByScale(bitmap, scale, recycle);
- }
-
- public static Bitmap resizeAndCropCenter(Bitmap bitmap, int size, boolean recycle) {
- int w = bitmap.getWidth();
- int h = bitmap.getHeight();
- if (w == size && h == size) return bitmap;
-
- // scale the image so that the shorter side equals to the target;
- // the longer side will be center-cropped.
- float scale = (float) size / Math.min(w, h);
-
- Bitmap target = Bitmap.createBitmap(size, size, getConfig(bitmap));
- int width = Math.round(scale * bitmap.getWidth());
- int height = Math.round(scale * bitmap.getHeight());
- Canvas canvas = new Canvas(target);
- canvas.translate((size - width) / 2f, (size - height) / 2f);
- canvas.scale(scale, scale);
- Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG);
- canvas.drawBitmap(bitmap, 0, 0, paint);
- if (recycle) bitmap.recycle();
- return target;
- }
-
- public static void recycleSilently(Bitmap bitmap) {
- if (bitmap == null) return;
- try {
- bitmap.recycle();
- } catch (Throwable t) {
- Log.w(TAG, "unable recycle bitmap", t);
- }
- }
-
- public static Bitmap rotateBitmap(Bitmap source, int rotation, boolean recycle) {
- if (rotation == 0) return source;
- int w = source.getWidth();
- int h = source.getHeight();
- Matrix m = new Matrix();
- m.postRotate(rotation);
- Bitmap bitmap = Bitmap.createBitmap(source, 0, 0, w, h, m, true);
- if (recycle) source.recycle();
- return bitmap;
- }
-
- public static Bitmap createVideoThumbnail(String filePath) {
- // MediaMetadataRetriever is available on API Level 8
- // but is hidden until API Level 10
- Class<?> clazz = null;
- Object instance = null;
+ private static int getRotationFromExifHelper(Resources res, int resId, Context context, Uri uri) {
+ ExifInterface ei = new ExifInterface();
+ InputStream is = null;
+ BufferedInputStream bis = null;
try {
- clazz = Class.forName("android.media.MediaMetadataRetriever");
- instance = clazz.newInstance();
-
- Method method = clazz.getMethod("setDataSource", String.class);
- method.invoke(instance, filePath);
-
- // The method name changes between API Level 9 and 10.
- if (Build.VERSION.SDK_INT <= 9) {
- return (Bitmap) clazz.getMethod("captureFrame").invoke(instance);
+ if (uri != null) {
+ is = context.getContentResolver().openInputStream(uri);
+ bis = new BufferedInputStream(is);
+ ei.readExif(bis);
} else {
- byte[] data = (byte[]) clazz.getMethod("getEmbeddedPicture").invoke(instance);
- if (data != null) {
- Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
- if (bitmap != null) return bitmap;
- }
- return (Bitmap) clazz.getMethod("getFrameAtTime").invoke(instance);
+ is = res.openRawResource(resId);
+ bis = new BufferedInputStream(is);
+ ei.readExif(bis);
}
- } catch (IllegalArgumentException ex) {
- // Assume this is a corrupt video file
- } catch (RuntimeException ex) {
- // Assume this is a corrupt video file.
- } catch (InstantiationException e) {
- Log.e(TAG, "createVideoThumbnail", e);
- } catch (InvocationTargetException e) {
- Log.e(TAG, "createVideoThumbnail", e);
- } catch (ClassNotFoundException e) {
- Log.e(TAG, "createVideoThumbnail", e);
- } catch (NoSuchMethodException e) {
- Log.e(TAG, "createVideoThumbnail", e);
- } catch (IllegalAccessException e) {
- Log.e(TAG, "createVideoThumbnail", e);
- } finally {
- try {
- if (instance != null) {
- clazz.getMethod("release").invoke(instance);
- }
- } catch (Exception ignored) {
+ Integer ori = ei.getTagIntValue(ExifInterface.TAG_ORIENTATION);
+ if (ori != null) {
+ return ExifInterface.getRotationForOrientationValue(ori.shortValue());
}
+ } catch (IOException e) {
+ Log.w(TAG, "Getting exif data failed", e);
+ } catch (NullPointerException e) {
+ // Sometimes the ExifInterface has an internal NPE if Exif data isn't valid
+ Log.w(TAG, "Getting exif data failed", e);
+ } finally {
+ Utils.closeSilently(bis);
+ Utils.closeSilently(is);
}
- return null;
- }
-
- public static byte[] compressToBytes(Bitmap bitmap) {
- return compressToBytes(bitmap, DEFAULT_JPEG_QUALITY);
- }
-
- public static byte[] compressToBytes(Bitmap bitmap, int quality) {
- ByteArrayOutputStream baos = new ByteArrayOutputStream(65536);
- bitmap.compress(CompressFormat.JPEG, quality, baos);
- return baos.toByteArray();
- }
-
- public static boolean isSupportedByRegionDecoder(String mimeType) {
- if (mimeType == null) return false;
- mimeType = mimeType.toLowerCase();
- return mimeType.startsWith("image/") &&
- (!mimeType.equals("image/gif") && !mimeType.endsWith("bmp"));
- }
-
- public static boolean isRotationSupported(String mimeType) {
- if (mimeType == null) return false;
- mimeType = mimeType.toLowerCase();
- return mimeType.equals("image/jpeg");
+ return 0;
}
}
diff --git a/WallpaperPicker/src/com/android/gallery3d/common/Utils.java b/WallpaperPicker/src/com/android/gallery3d/common/Utils.java
index 614a081c8..8466c22cb 100644
--- a/WallpaperPicker/src/com/android/gallery3d/common/Utils.java
+++ b/WallpaperPicker/src/com/android/gallery3d/common/Utils.java
@@ -16,32 +16,16 @@
package com.android.gallery3d.common;
-import android.content.Context;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager.NameNotFoundException;
import android.database.Cursor;
-import android.os.Build;
+import android.graphics.RectF;
import android.os.ParcelFileDescriptor;
-import android.text.TextUtils;
import android.util.Log;
import java.io.Closeable;
import java.io.IOException;
-import java.io.InterruptedIOException;
public class Utils {
private static final String TAG = "Utils";
- private static final String DEBUG_TAG = "GalleryDebug";
-
- private static final long POLY64REV = 0x95AC9329AC4BC9B5L;
- private static final long INITIALCRC = 0xFFFFFFFFFFFFFFFFL;
-
- private static long[] sCrcTable = new long[256];
-
- private static final boolean IS_DEBUG_BUILD =
- Build.TYPE.equals("eng") || Build.TYPE.equals("userdebug");
-
- private static final String MASK_STRING = "********************************";
// Throws AssertionError if the input is false.
public static void assertTrue(boolean cond) {
@@ -50,28 +34,6 @@ public class Utils {
}
}
- // Throws AssertionError with the message. We had a method having the form
- // assertTrue(boolean cond, String message, Object ... args);
- // However a call to that method will cause memory allocation even if the
- // condition is false (due to autoboxing generated by "Object ... args"),
- // so we don't use that anymore.
- public static void fail(String message, Object ... args) {
- throw new AssertionError(
- args.length == 0 ? message : String.format(message, args));
- }
-
- // Throws NullPointerException if the input is null.
- public static <T> T checkNotNull(T object) {
- if (object == null) throw new NullPointerException();
- return object;
- }
-
- // Returns true if two input Object are both null or equal
- // to each other.
- public static boolean equals(Object a, Object b) {
- return (a == b) || (a == null ? false : a.equals(b));
- }
-
// Returns the next power of two.
// Returns the input if it is already power of 2.
// Throws IllegalArgumentException if the input is <= 0 or
@@ -102,87 +64,6 @@ public class Utils {
return x;
}
- // Returns the input value x clamped to the range [min, max].
- public static float clamp(float x, float min, float max) {
- if (x > max) return max;
- if (x < min) return min;
- return x;
- }
-
- // Returns the input value x clamped to the range [min, max].
- public static long clamp(long x, long min, long max) {
- if (x > max) return max;
- if (x < min) return min;
- return x;
- }
-
- public static boolean isOpaque(int color) {
- return color >>> 24 == 0xFF;
- }
-
- public static void swap(int[] array, int i, int j) {
- int temp = array[i];
- array[i] = array[j];
- array[j] = temp;
- }
-
- /**
- * A function thats returns a 64-bit crc for string
- *
- * @param in input string
- * @return a 64-bit crc value
- */
- public static final long crc64Long(String in) {
- if (in == null || in.length() == 0) {
- return 0;
- }
- return crc64Long(getBytes(in));
- }
-
- static {
- // http://bioinf.cs.ucl.ac.uk/downloads/crc64/crc64.c
- long part;
- for (int i = 0; i < 256; i++) {
- part = i;
- for (int j = 0; j < 8; j++) {
- long x = ((int) part & 1) != 0 ? POLY64REV : 0;
- part = (part >> 1) ^ x;
- }
- sCrcTable[i] = part;
- }
- }
-
- public static final long crc64Long(byte[] buffer) {
- long crc = INITIALCRC;
- for (int k = 0, n = buffer.length; k < n; ++k) {
- crc = sCrcTable[(((int) crc) ^ buffer[k]) & 0xff] ^ (crc >> 8);
- }
- return crc;
- }
-
- public static byte[] getBytes(String in) {
- byte[] result = new byte[in.length() * 2];
- int output = 0;
- for (char ch : in.toCharArray()) {
- result[output++] = (byte) (ch & 0xFF);
- result[output++] = (byte) (ch >> 8);
- }
- return result;
- }
-
- public static void closeSilently(Closeable c) {
- if (c == null) return;
- try {
- c.close();
- } catch (IOException t) {
- Log.w(TAG, "close fail ", t);
- }
- }
-
- public static int compare(long a, long b) {
- return a < b ? -1 : a == b ? 0 : 1;
- }
-
public static int ceilLog2(float value) {
int i;
for (i = 0; i < 31; i++) {
@@ -199,6 +80,15 @@ public class Utils {
return i - 1;
}
+ public static void closeSilently(Closeable c) {
+ if (c == null) return;
+ try {
+ c.close();
+ } catch (IOException t) {
+ Log.w(TAG, "close fail ", t);
+ }
+ }
+
public static void closeSilently(ParcelFileDescriptor fd) {
try {
if (fd != null) fd.close();
@@ -215,126 +105,25 @@ public class Utils {
}
}
- public static float interpolateAngle(
- float source, float target, float progress) {
- // interpolate the angle from source to target
- // We make the difference in the range of [-179, 180], this is the
- // shortest path to change source to target.
- float diff = target - source;
- if (diff < 0) diff += 360f;
- if (diff > 180) diff -= 360f;
-
- float result = source + diff * progress;
- return result < 0 ? result + 360f : result;
- }
-
- public static float interpolateScale(
- float source, float target, float progress) {
- return source + progress * (target - source);
- }
-
- public static String ensureNotNull(String value) {
- return value == null ? "" : value;
- }
-
- public static float parseFloatSafely(String content, float defaultValue) {
- if (content == null) return defaultValue;
- try {
- return Float.parseFloat(content);
- } catch (NumberFormatException e) {
- return defaultValue;
- }
- }
-
- public static int parseIntSafely(String content, int defaultValue) {
- if (content == null) return defaultValue;
- try {
- return Integer.parseInt(content);
- } catch (NumberFormatException e) {
- return defaultValue;
- }
- }
-
- public static boolean isNullOrEmpty(String exifMake) {
- return TextUtils.isEmpty(exifMake);
- }
-
- public static void waitWithoutInterrupt(Object object) {
- try {
- object.wait();
- } catch (InterruptedException e) {
- Log.w(TAG, "unexpected interrupt: " + object);
- }
- }
-
- public static boolean handleInterrruptedException(Throwable e) {
- // A helper to deal with the interrupt exception
- // If an interrupt detected, we will setup the bit again.
- if (e instanceof InterruptedIOException
- || e instanceof InterruptedException) {
- Thread.currentThread().interrupt();
- return true;
- }
- return false;
- }
-
- /**
- * @return String with special XML characters escaped.
- */
- public static String escapeXml(String s) {
- StringBuilder sb = new StringBuilder();
- for (int i = 0, len = s.length(); i < len; ++i) {
- char c = s.charAt(i);
- switch (c) {
- case '<': sb.append("&lt;"); break;
- case '>': sb.append("&gt;"); break;
- case '\"': sb.append("&quot;"); break;
- case '\'': sb.append("&#039;"); break;
- case '&': sb.append("&amp;"); break;
- default: sb.append(c);
- }
- }
- return sb.toString();
- }
-
- public static String getUserAgent(Context context) {
- PackageInfo packageInfo;
- try {
- packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
- } catch (NameNotFoundException e) {
- throw new IllegalStateException("getPackageInfo failed");
- }
- return String.format("%s/%s; %s/%s/%s/%s; %s/%s/%s",
- packageInfo.packageName,
- packageInfo.versionName,
- Build.BRAND,
- Build.DEVICE,
- Build.MODEL,
- Build.ID,
- Build.VERSION.SDK_INT,
- Build.VERSION.RELEASE,
- Build.VERSION.INCREMENTAL);
- }
-
- public static String[] copyOf(String[] source, int newSize) {
- String[] result = new String[newSize];
- newSize = Math.min(source.length, newSize);
- System.arraycopy(source, 0, result, 0, newSize);
- return result;
- }
-
- // Mask information for debugging only. It returns <code>info.toString()</code> directly
- // for debugging build (i.e., 'eng' and 'userdebug') and returns a mask ("****")
- // in release build to protect the information (e.g. for privacy issue).
- public static String maskDebugInfo(Object info) {
- if (info == null) return null;
- String s = info.toString();
- int length = Math.min(s.length(), MASK_STRING.length());
- return IS_DEBUG_BUILD ? s : MASK_STRING.substring(0, length);
- }
-
- // This method should be ONLY used for debugging.
- public static void debug(String message, Object ... args) {
- Log.v(DEBUG_TAG, String.format(message, args));
+ public static RectF getMaxCropRect(
+ int inWidth, int inHeight, int outWidth, int outHeight, boolean leftAligned) {
+ RectF cropRect = new RectF();
+ // Get a crop rect that will fit this
+ if (inWidth / (float) inHeight > outWidth / (float) outHeight) {
+ cropRect.top = 0;
+ cropRect.bottom = inHeight;
+ cropRect.left = (inWidth - (outWidth / (float) outHeight) * inHeight) / 2;
+ cropRect.right = inWidth - cropRect.left;
+ if (leftAligned) {
+ cropRect.right -= cropRect.left;
+ cropRect.left = 0;
+ }
+ } else {
+ cropRect.left = 0;
+ cropRect.right = inWidth;
+ cropRect.top = (inHeight - (outHeight / (float) outWidth) * inWidth) / 2;
+ cropRect.bottom = inHeight - cropRect.top;
+ }
+ return cropRect;
}
}
diff --git a/WallpaperPicker/src/com/android/gallery3d/exif/ExifInterface.java b/WallpaperPicker/src/com/android/gallery3d/exif/ExifInterface.java
index a1cf0fc85..9247e879f 100644
--- a/WallpaperPicker/src/com/android/gallery3d/exif/ExifInterface.java
+++ b/WallpaperPicker/src/com/android/gallery3d/exif/ExifInterface.java
@@ -1247,7 +1247,7 @@ public class ExifInterface {
if (l == null || l.length <= 0) {
return null;
}
- return new Long(l[0]);
+ return Long.valueOf(l[0]);
}
/**
@@ -1266,7 +1266,7 @@ public class ExifInterface {
if (l == null || l.length <= 0) {
return null;
}
- return new Integer(l[0]);
+ return Integer.valueOf(l[0]);
}
/**
@@ -1285,7 +1285,7 @@ public class ExifInterface {
if (l == null || l.length <= 0) {
return null;
}
- return new Byte(l[0]);
+ return Byte.valueOf(l[0]);
}
/**
diff --git a/WallpaperPicker/src/com/android/gallery3d/glrenderer/BasicTexture.java b/WallpaperPicker/src/com/android/gallery3d/glrenderer/BasicTexture.java
index 2e77b903f..0f3efb727 100644
--- a/WallpaperPicker/src/com/android/gallery3d/glrenderer/BasicTexture.java
+++ b/WallpaperPicker/src/com/android/gallery3d/glrenderer/BasicTexture.java
@@ -27,7 +27,6 @@ import java.util.WeakHashMap;
// If a BasicTexture is loaded into GL memory, it has a GL texture id.
public abstract class BasicTexture implements Texture {
- @SuppressWarnings("unused")
private static final String TAG = "BasicTexture";
protected static final int UNSPECIFIED = -1;
diff --git a/WallpaperPicker/src/com/android/gallery3d/glrenderer/BitmapTexture.java b/WallpaperPicker/src/com/android/gallery3d/glrenderer/BitmapTexture.java
index 100b0b3b9..f8b01cb42 100644
--- a/WallpaperPicker/src/com/android/gallery3d/glrenderer/BitmapTexture.java
+++ b/WallpaperPicker/src/com/android/gallery3d/glrenderer/BitmapTexture.java
@@ -18,7 +18,7 @@ package com.android.gallery3d.glrenderer;
import android.graphics.Bitmap;
-import junit.framework.Assert;
+import com.android.gallery3d.common.Utils;
// BitmapTexture is a texture whose content is specified by a fixed Bitmap.
//
@@ -34,7 +34,7 @@ public class BitmapTexture extends UploadedTexture {
public BitmapTexture(Bitmap bitmap, boolean hasBorder) {
super(hasBorder);
- Assert.assertTrue(bitmap != null && !bitmap.isRecycled());
+ Utils.assertTrue(bitmap != null && !bitmap.isRecycled());
mContentBitmap = bitmap;
}
diff --git a/WallpaperPicker/src/com/android/gallery3d/glrenderer/GLES20Canvas.java b/WallpaperPicker/src/com/android/gallery3d/glrenderer/GLES20Canvas.java
index 4ead1315e..933260b48 100644
--- a/WallpaperPicker/src/com/android/gallery3d/glrenderer/GLES20Canvas.java
+++ b/WallpaperPicker/src/com/android/gallery3d/glrenderer/GLES20Canvas.java
@@ -23,8 +23,6 @@ import android.opengl.GLUtils;
import android.opengl.Matrix;
import android.util.Log;
-import com.android.gallery3d.util.IntArray;
-
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
@@ -698,6 +696,7 @@ public class GLES20Canvas implements GLCanvas {
}
private void prepareTexture(BasicTexture texture, int program, ShaderParameter[] params) {
+ deleteRecycledResources();
GLES20.glUseProgram(program);
checkError();
enableBlending(!texture.isOpaque() || getAlpha() < OPAQUE_ALPHA);
diff --git a/WallpaperPicker/src/com/android/gallery3d/glrenderer/GLPaint.java b/WallpaperPicker/src/com/android/gallery3d/glrenderer/GLPaint.java
index 16b220690..b26e9ab29 100644
--- a/WallpaperPicker/src/com/android/gallery3d/glrenderer/GLPaint.java
+++ b/WallpaperPicker/src/com/android/gallery3d/glrenderer/GLPaint.java
@@ -16,7 +16,7 @@
package com.android.gallery3d.glrenderer;
-import junit.framework.Assert;
+import com.android.gallery3d.common.Utils;
public class GLPaint {
private float mLineWidth = 1f;
@@ -31,7 +31,7 @@ public class GLPaint {
}
public void setLineWidth(float width) {
- Assert.assertTrue(width >= 0);
+ Utils.assertTrue(width >= 0);
mLineWidth = width;
}
diff --git a/WallpaperPicker/src/com/android/gallery3d/util/IntArray.java b/WallpaperPicker/src/com/android/gallery3d/glrenderer/IntArray.java
index 2c4dc2c83..f123624d6 100644
--- a/WallpaperPicker/src/com/android/gallery3d/util/IntArray.java
+++ b/WallpaperPicker/src/com/android/gallery3d/glrenderer/IntArray.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.gallery3d.util;
+package com.android.gallery3d.glrenderer;
public class IntArray {
private static final int INIT_CAPACITY = 8;
diff --git a/WallpaperPicker/src/com/android/gallery3d/glrenderer/UploadedTexture.java b/WallpaperPicker/src/com/android/gallery3d/glrenderer/UploadedTexture.java
index f41a979b7..8075bf868 100644
--- a/WallpaperPicker/src/com/android/gallery3d/glrenderer/UploadedTexture.java
+++ b/WallpaperPicker/src/com/android/gallery3d/glrenderer/UploadedTexture.java
@@ -20,7 +20,8 @@ import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.opengl.GLUtils;
-import junit.framework.Assert;
+import com.android.gallery3d.common.Utils;
+import com.android.launcher3.util.Thunk;
import java.util.HashMap;
@@ -82,7 +83,7 @@ public abstract class UploadedTexture extends BasicTexture {
return mIsUploading;
}
- private static class BorderKey implements Cloneable {
+ @Thunk static class BorderKey implements Cloneable {
public boolean vertical;
public Config config;
public int length;
@@ -144,7 +145,7 @@ public abstract class UploadedTexture extends BasicTexture {
}
private void freeBitmap() {
- Assert.assertTrue(mBitmap != null);
+ Utils.assertTrue(mBitmap != null);
onFreeBitmap(mBitmap);
mBitmap = null;
}
@@ -219,7 +220,7 @@ public abstract class UploadedTexture extends BasicTexture {
int texWidth = getTextureWidth();
int texHeight = getTextureHeight();
- Assert.assertTrue(bWidth <= texWidth && bHeight <= texHeight);
+ Utils.assertTrue(bWidth <= texWidth && bHeight <= texHeight);
// Upload the bitmap to a new texture.
mId = canvas.getGLId().generateTexture();