summaryrefslogtreecommitdiffstats
path: root/WallpaperPicker/src
diff options
context:
space:
mode:
Diffstat (limited to 'WallpaperPicker/src')
-rw-r--r--WallpaperPicker/src/com/android/gallery3d/common/BitmapCropTask.java2
-rw-r--r--WallpaperPicker/src/com/android/gallery3d/common/BitmapUtils.java28
-rw-r--r--WallpaperPicker/src/com/android/gallery3d/common/ExifOrientation.java145
-rw-r--r--WallpaperPicker/src/com/android/gallery3d/exif/ByteBufferInputStream.java48
-rw-r--r--WallpaperPicker/src/com/android/gallery3d/exif/CountedDataInputStream.java136
-rw-r--r--WallpaperPicker/src/com/android/gallery3d/exif/ExifData.java348
-rw-r--r--WallpaperPicker/src/com/android/gallery3d/exif/ExifInterface.java2407
-rw-r--r--WallpaperPicker/src/com/android/gallery3d/exif/ExifInvalidFormatException.java23
-rw-r--r--WallpaperPicker/src/com/android/gallery3d/exif/ExifModifier.java195
-rw-r--r--WallpaperPicker/src/com/android/gallery3d/exif/ExifOutputStream.java518
-rw-r--r--WallpaperPicker/src/com/android/gallery3d/exif/ExifParser.java916
-rw-r--r--WallpaperPicker/src/com/android/gallery3d/exif/ExifReader.java92
-rw-r--r--WallpaperPicker/src/com/android/gallery3d/exif/ExifTag.java1008
-rw-r--r--WallpaperPicker/src/com/android/gallery3d/exif/IfdData.java152
-rw-r--r--WallpaperPicker/src/com/android/gallery3d/exif/IfdId.java31
-rw-r--r--WallpaperPicker/src/com/android/gallery3d/exif/JpegHeader.java39
-rw-r--r--WallpaperPicker/src/com/android/gallery3d/exif/OrderedDataOutputStream.java56
-rw-r--r--WallpaperPicker/src/com/android/gallery3d/exif/Rational.java88
-rw-r--r--WallpaperPicker/src/com/android/gallery3d/glrenderer/BasicTexture.java35
-rw-r--r--WallpaperPicker/src/com/android/gallery3d/glrenderer/BitmapTexture.java6
-rw-r--r--WallpaperPicker/src/com/android/gallery3d/glrenderer/GLCanvas.java94
-rw-r--r--WallpaperPicker/src/com/android/gallery3d/glrenderer/GLES20Canvas.java537
-rw-r--r--WallpaperPicker/src/com/android/gallery3d/glrenderer/GLPaint.java41
-rw-r--r--WallpaperPicker/src/com/android/gallery3d/glrenderer/RawTexture.java73
-rw-r--r--WallpaperPicker/src/com/android/gallery3d/glrenderer/Texture.java7
-rw-r--r--WallpaperPicker/src/com/android/gallery3d/glrenderer/UploadedTexture.java138
-rw-r--r--WallpaperPicker/src/com/android/launcher3/CropView.java2
-rw-r--r--WallpaperPicker/src/com/android/launcher3/LiveWallpaperListAdapter.java203
-rw-r--r--WallpaperPicker/src/com/android/launcher3/SavedWallpaperImages.java95
-rw-r--r--WallpaperPicker/src/com/android/launcher3/ThirdPartyWallpaperPickerListAdapter.java138
-rw-r--r--WallpaperPicker/src/com/android/launcher3/ToggleOnTapCallback.java67
-rw-r--r--WallpaperPicker/src/com/android/launcher3/WallpaperCropActivity.java217
-rw-r--r--WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java972
-rw-r--r--WallpaperPicker/src/com/android/launcher3/wallpapertileinfo/DefaultWallpaperInfo.java164
-rw-r--r--WallpaperPicker/src/com/android/launcher3/wallpapertileinfo/DrawableThumbWallpaperInfo.java37
-rw-r--r--WallpaperPicker/src/com/android/launcher3/wallpapertileinfo/FileWallpaperInfo.java52
-rw-r--r--WallpaperPicker/src/com/android/launcher3/wallpapertileinfo/LiveWallpaperInfo.java118
-rw-r--r--WallpaperPicker/src/com/android/launcher3/wallpapertileinfo/PickImageInfo.java74
-rw-r--r--WallpaperPicker/src/com/android/launcher3/wallpapertileinfo/ResourceWallpaperInfo.java65
-rw-r--r--WallpaperPicker/src/com/android/launcher3/wallpapertileinfo/ThirdPartyWallpaperInfo.java78
-rw-r--r--WallpaperPicker/src/com/android/launcher3/wallpapertileinfo/UriWallpaperInfo.java109
-rw-r--r--WallpaperPicker/src/com/android/launcher3/wallpapertileinfo/WallpaperTileInfo.java87
-rw-r--r--WallpaperPicker/src/com/android/photos/BitmapRegionTileSource.java66
-rw-r--r--WallpaperPicker/src/com/android/photos/views/TiledImageView.java68
44 files changed, 1405 insertions, 8370 deletions
diff --git a/WallpaperPicker/src/com/android/gallery3d/common/BitmapCropTask.java b/WallpaperPicker/src/com/android/gallery3d/common/BitmapCropTask.java
index 8b5144748..212fb84ea 100644
--- a/WallpaperPicker/src/com/android/gallery3d/common/BitmapCropTask.java
+++ b/WallpaperPicker/src/com/android/gallery3d/common/BitmapCropTask.java
@@ -126,7 +126,7 @@ public class BitmapCropTask extends AsyncTask<Void, Void, Boolean> {
mNoCrop = value;
}
- public void setOnEndRunnable(OnEndCropHandler onEndCropHandler) {
+ public void setOnEndCropHandler(OnEndCropHandler onEndCropHandler) {
mOnEndCropHandler = onEndCropHandler;
}
diff --git a/WallpaperPicker/src/com/android/gallery3d/common/BitmapUtils.java b/WallpaperPicker/src/com/android/gallery3d/common/BitmapUtils.java
index 9ac5c1bf7..6ddda87b5 100644
--- a/WallpaperPicker/src/com/android/gallery3d/common/BitmapUtils.java
+++ b/WallpaperPicker/src/com/android/gallery3d/common/BitmapUtils.java
@@ -21,8 +21,6 @@ import android.content.res.Resources;
import android.net.Uri;
import android.util.Log;
-import com.android.gallery3d.exif.ExifInterface;
-
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -42,38 +40,26 @@ public class BitmapUtils {
}
public static int getRotationFromExif(Context context, Uri uri) {
- return BitmapUtils.getRotationFromExifHelper(null, 0, context, uri);
+ return BitmapUtils.getRotationFromExifHelper(null, 0, uri, context);
}
- public static int getRotationFromExif(Resources res, int resId) {
- return BitmapUtils.getRotationFromExifHelper(res, resId, null, null);
+ public static int getRotationFromExif(Resources res, int resId, Context context) {
+ return BitmapUtils.getRotationFromExifHelper(res, resId, null, context);
}
- private static int getRotationFromExifHelper(Resources res, int resId, Context context, Uri uri) {
- ExifInterface ei = new ExifInterface();
+ private static int getRotationFromExifHelper(Resources res, int resId,
+ Uri uri, Context context) {
InputStream is = null;
- BufferedInputStream bis = null;
try {
if (uri != null) {
is = context.getContentResolver().openInputStream(uri);
- bis = new BufferedInputStream(is);
- ei.readExif(bis);
} else {
is = res.openRawResource(resId);
- bis = new BufferedInputStream(is);
- ei.readExif(bis);
- }
- 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
+ return ExifOrientation.readRotation(new BufferedInputStream(is), context);
+ } catch (IOException | NullPointerException e) {
Log.w(TAG, "Getting exif data failed", e);
} finally {
- Utils.closeSilently(bis);
Utils.closeSilently(is);
}
return 0;
diff --git a/WallpaperPicker/src/com/android/gallery3d/common/ExifOrientation.java b/WallpaperPicker/src/com/android/gallery3d/common/ExifOrientation.java
new file mode 100644
index 000000000..ad4370c37
--- /dev/null
+++ b/WallpaperPicker/src/com/android/gallery3d/common/ExifOrientation.java
@@ -0,0 +1,145 @@
+/**
+ * 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.content.Context;
+import android.media.ExifInterface;
+import android.util.Log;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class ExifOrientation {
+ private static final String TAG = "ExifOrientation";
+ private static final boolean DEBUG = false;
+
+ private static final short SOI = (short) 0xFFD8; // start of input
+ private static final short APP0 = (short) 0xFFE0;
+ private static final short APPF = (short) 0xFFEF;
+ private static final short APP1 = (short) 0xFFE1;
+ private static final short SOS = (short) 0xFFDA; // start of stream
+ private static final short EOI = (short) 0xFFD9; // end of input
+
+ // The header is available in first 64 bytes, so reading upto 128 bytes
+ // should be more than enough.
+ private static final int MAX_BYTES_TO_READ = 128 * 1024;
+
+ /**
+ * Parses the rotation of the JPEG image from the input stream.
+ */
+ public static final int readRotation(InputStream in, Context context) {
+ // Since the platform implementation only takes file input, create a temporary file
+ // with just the image header.
+ File tempFile = null;
+ DataOutputStream tempOut = null;
+
+ try {
+ DataInputStream din = new DataInputStream(in);
+ int pos = 0;
+ if (din.readShort() == SOI) {
+ pos += 2;
+
+ short marker = din.readShort();
+ pos += 2;
+
+ while ((marker >= APP0 && marker <= APPF) && pos < MAX_BYTES_TO_READ) {
+ int length = din.readUnsignedShort();
+ if (length < 2) {
+ throw new IOException("Invalid header size");
+ }
+
+ // We only want APP1 headers
+ if (length > 2) {
+ if (marker == APP1) {
+ // Copy the header
+ if (tempFile == null) {
+ tempFile = File.createTempFile(TAG, ".jpg", context.getCacheDir());
+ tempOut = new DataOutputStream(new FileOutputStream(tempFile));
+ tempOut.writeShort(SOI);
+ }
+
+ tempOut.writeShort(marker);
+ tempOut.writeShort(length);
+
+ byte[] header = new byte[length - 2];
+ din.read(header);
+ tempOut.write(header);
+ } else {
+ din.skip(length - 2);
+ }
+ }
+ pos += length;
+
+ marker = din.readShort();
+ pos += 2;
+ }
+
+ if (tempOut != null) {
+ // Write empty image data.
+ tempOut.writeShort(SOS);
+ // Write the frame size as 2. Since this includes the size bytes as well
+ // (short = 2 bytes), it implies there is 0 byte of image data.
+ tempOut.writeShort(2);
+
+ // End of input
+ tempOut.writeShort(EOI);
+ tempOut.close();
+
+ return readRotation(tempFile.getAbsolutePath());
+ }
+ }
+ } catch (IOException e) {
+ if (DEBUG) {
+ Log.d(TAG, "Error parsing input stream", e);
+ }
+ } finally {
+ Utils.closeSilently(in);
+ Utils.closeSilently(tempOut);
+ if (tempFile != null) {
+ tempFile.delete();
+ }
+ }
+ return 0;
+ }
+
+ /**
+ * Parses the rotation of the JPEG image.
+ */
+ public static final int readRotation(String filePath) {
+ try {
+ ExifInterface exif = new ExifInterface(filePath);
+ switch (exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 0)) {
+ case ExifInterface.ORIENTATION_ROTATE_90:
+ return 90;
+ case ExifInterface.ORIENTATION_ROTATE_270:
+ return 270;
+ case ExifInterface.ORIENTATION_ROTATE_180:
+ return 180;
+ default:
+ return 0;
+ }
+ } catch (IOException e) {
+ if (DEBUG) {
+ Log.d(TAG, "Error reading file", e);
+ }
+ }
+ return 0;
+ }
+}
diff --git a/WallpaperPicker/src/com/android/gallery3d/exif/ByteBufferInputStream.java b/WallpaperPicker/src/com/android/gallery3d/exif/ByteBufferInputStream.java
deleted file mode 100644
index 7fb9f22cc..000000000
--- a/WallpaperPicker/src/com/android/gallery3d/exif/ByteBufferInputStream.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2012 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.exif;
-
-import java.io.InputStream;
-import java.nio.ByteBuffer;
-
-class ByteBufferInputStream extends InputStream {
-
- private ByteBuffer mBuf;
-
- public ByteBufferInputStream(ByteBuffer buf) {
- mBuf = buf;
- }
-
- @Override
- public int read() {
- if (!mBuf.hasRemaining()) {
- return -1;
- }
- return mBuf.get() & 0xFF;
- }
-
- @Override
- public int read(byte[] bytes, int off, int len) {
- if (!mBuf.hasRemaining()) {
- return -1;
- }
-
- len = Math.min(len, mBuf.remaining());
- mBuf.get(bytes, off, len);
- return len;
- }
-}
diff --git a/WallpaperPicker/src/com/android/gallery3d/exif/CountedDataInputStream.java b/WallpaperPicker/src/com/android/gallery3d/exif/CountedDataInputStream.java
deleted file mode 100644
index dfd4a1a10..000000000
--- a/WallpaperPicker/src/com/android/gallery3d/exif/CountedDataInputStream.java
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright (C) 2012 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.exif;
-
-import java.io.EOFException;
-import java.io.FilterInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.charset.Charset;
-
-class CountedDataInputStream extends FilterInputStream {
-
- private int mCount = 0;
-
- // allocate a byte buffer for a long value;
- private final byte mByteArray[] = new byte[8];
- private final ByteBuffer mByteBuffer = ByteBuffer.wrap(mByteArray);
-
- protected CountedDataInputStream(InputStream in) {
- super(in);
- }
-
- public int getReadByteCount() {
- return mCount;
- }
-
- @Override
- public int read(byte[] b) throws IOException {
- int r = in.read(b);
- mCount += (r >= 0) ? r : 0;
- return r;
- }
-
- @Override
- public int read(byte[] b, int off, int len) throws IOException {
- int r = in.read(b, off, len);
- mCount += (r >= 0) ? r : 0;
- return r;
- }
-
- @Override
- public int read() throws IOException {
- int r = in.read();
- mCount += (r >= 0) ? 1 : 0;
- return r;
- }
-
- @Override
- public long skip(long length) throws IOException {
- long skip = in.skip(length);
- mCount += skip;
- return skip;
- }
-
- public void skipOrThrow(long length) throws IOException {
- if (skip(length) != length) throw new EOFException();
- }
-
- public void skipTo(long target) throws IOException {
- long cur = mCount;
- long diff = target - cur;
- assert(diff >= 0);
- skipOrThrow(diff);
- }
-
- public void readOrThrow(byte[] b, int off, int len) throws IOException {
- int r = read(b, off, len);
- if (r != len) throw new EOFException();
- }
-
- public void readOrThrow(byte[] b) throws IOException {
- readOrThrow(b, 0, b.length);
- }
-
- public void setByteOrder(ByteOrder order) {
- mByteBuffer.order(order);
- }
-
- public ByteOrder getByteOrder() {
- return mByteBuffer.order();
- }
-
- public short readShort() throws IOException {
- readOrThrow(mByteArray, 0 ,2);
- mByteBuffer.rewind();
- return mByteBuffer.getShort();
- }
-
- public int readUnsignedShort() throws IOException {
- return readShort() & 0xffff;
- }
-
- public int readInt() throws IOException {
- readOrThrow(mByteArray, 0 , 4);
- mByteBuffer.rewind();
- return mByteBuffer.getInt();
- }
-
- public long readUnsignedInt() throws IOException {
- return readInt() & 0xffffffffL;
- }
-
- public long readLong() throws IOException {
- readOrThrow(mByteArray, 0 , 8);
- mByteBuffer.rewind();
- return mByteBuffer.getLong();
- }
-
- public String readString(int n) throws IOException {
- byte buf[] = new byte[n];
- readOrThrow(buf);
- return new String(buf, "UTF8");
- }
-
- public String readString(int n, Charset charset) throws IOException {
- byte buf[] = new byte[n];
- readOrThrow(buf);
- return new String(buf, charset);
- }
-} \ No newline at end of file
diff --git a/WallpaperPicker/src/com/android/gallery3d/exif/ExifData.java b/WallpaperPicker/src/com/android/gallery3d/exif/ExifData.java
deleted file mode 100644
index 8422382bb..000000000
--- a/WallpaperPicker/src/com/android/gallery3d/exif/ExifData.java
+++ /dev/null
@@ -1,348 +0,0 @@
-/*
- * Copyright (C) 2012 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.exif;
-
-import android.util.Log;
-
-import java.io.UnsupportedEncodingException;
-import java.nio.ByteOrder;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * This class stores the EXIF header in IFDs according to the JPEG
- * specification. It is the result produced by {@link ExifReader}.
- *
- * @see ExifReader
- * @see IfdData
- */
-class ExifData {
- private static final String TAG = "ExifData";
- private static final byte[] USER_COMMENT_ASCII = {
- 0x41, 0x53, 0x43, 0x49, 0x49, 0x00, 0x00, 0x00
- };
- private static final byte[] USER_COMMENT_JIS = {
- 0x4A, 0x49, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00
- };
- private static final byte[] USER_COMMENT_UNICODE = {
- 0x55, 0x4E, 0x49, 0x43, 0x4F, 0x44, 0x45, 0x00
- };
-
- private final IfdData[] mIfdDatas = new IfdData[IfdId.TYPE_IFD_COUNT];
- private byte[] mThumbnail;
- private ArrayList<byte[]> mStripBytes = new ArrayList<byte[]>();
- private final ByteOrder mByteOrder;
-
- ExifData(ByteOrder order) {
- mByteOrder = order;
- }
-
- /**
- * Gets the compressed thumbnail. Returns null if there is no compressed
- * thumbnail.
- *
- * @see #hasCompressedThumbnail()
- */
- protected byte[] getCompressedThumbnail() {
- return mThumbnail;
- }
-
- /**
- * Sets the compressed thumbnail.
- */
- protected void setCompressedThumbnail(byte[] thumbnail) {
- mThumbnail = thumbnail;
- }
-
- /**
- * Returns true it this header contains a compressed thumbnail.
- */
- protected boolean hasCompressedThumbnail() {
- return mThumbnail != null;
- }
-
- /**
- * Adds an uncompressed strip.
- */
- protected void setStripBytes(int index, byte[] strip) {
- if (index < mStripBytes.size()) {
- mStripBytes.set(index, strip);
- } else {
- for (int i = mStripBytes.size(); i < index; i++) {
- mStripBytes.add(null);
- }
- mStripBytes.add(strip);
- }
- }
-
- /**
- * Gets the strip count.
- */
- protected int getStripCount() {
- return mStripBytes.size();
- }
-
- /**
- * Gets the strip at the specified index.
- *
- * @exceptions #IndexOutOfBoundException
- */
- protected byte[] getStrip(int index) {
- return mStripBytes.get(index);
- }
-
- /**
- * Returns true if this header contains uncompressed strip.
- */
- protected boolean hasUncompressedStrip() {
- return mStripBytes.size() != 0;
- }
-
- /**
- * Gets the byte order.
- */
- protected ByteOrder getByteOrder() {
- return mByteOrder;
- }
-
- /**
- * Returns the {@link IfdData} object corresponding to a given IFD if it
- * exists or null.
- */
- protected IfdData getIfdData(int ifdId) {
- if (ExifTag.isValidIfd(ifdId)) {
- return mIfdDatas[ifdId];
- }
- return null;
- }
-
- /**
- * Adds IFD data. If IFD data of the same type already exists, it will be
- * replaced by the new data.
- */
- protected void addIfdData(IfdData data) {
- mIfdDatas[data.getId()] = data;
- }
-
- /**
- * Returns the {@link IfdData} object corresponding to a given IFD or
- * generates one if none exist.
- */
- protected IfdData getOrCreateIfdData(int ifdId) {
- IfdData ifdData = mIfdDatas[ifdId];
- if (ifdData == null) {
- ifdData = new IfdData(ifdId);
- mIfdDatas[ifdId] = ifdData;
- }
- return ifdData;
- }
-
- /**
- * Returns the tag with a given TID in the given IFD if the tag exists.
- * Otherwise returns null.
- */
- protected ExifTag getTag(short tag, int ifd) {
- IfdData ifdData = mIfdDatas[ifd];
- return (ifdData == null) ? null : ifdData.getTag(tag);
- }
-
- /**
- * Adds the given ExifTag to its default IFD and returns an existing ExifTag
- * with the same TID or null if none exist.
- */
- protected ExifTag addTag(ExifTag tag) {
- if (tag != null) {
- int ifd = tag.getIfd();
- return addTag(tag, ifd);
- }
- return null;
- }
-
- /**
- * Adds the given ExifTag to the given IFD and returns an existing ExifTag
- * with the same TID or null if none exist.
- */
- protected ExifTag addTag(ExifTag tag, int ifdId) {
- if (tag != null && ExifTag.isValidIfd(ifdId)) {
- IfdData ifdData = getOrCreateIfdData(ifdId);
- return ifdData.setTag(tag);
- }
- return null;
- }
-
- protected void clearThumbnailAndStrips() {
- mThumbnail = null;
- mStripBytes.clear();
- }
-
- /**
- * Removes the thumbnail and its related tags. IFD1 will be removed.
- */
- protected void removeThumbnailData() {
- clearThumbnailAndStrips();
- mIfdDatas[IfdId.TYPE_IFD_1] = null;
- }
-
- /**
- * Removes the tag with a given TID and IFD.
- */
- protected void removeTag(short tagId, int ifdId) {
- IfdData ifdData = mIfdDatas[ifdId];
- if (ifdData == null) {
- return;
- }
- ifdData.removeTag(tagId);
- }
-
- /**
- * Decodes the user comment tag into string as specified in the EXIF
- * standard. Returns null if decoding failed.
- */
- protected String getUserComment() {
- IfdData ifdData = mIfdDatas[IfdId.TYPE_IFD_0];
- if (ifdData == null) {
- return null;
- }
- ExifTag tag = ifdData.getTag(ExifInterface.getTrueTagKey(ExifInterface.TAG_USER_COMMENT));
- if (tag == null) {
- return null;
- }
- if (tag.getComponentCount() < 8) {
- return null;
- }
-
- byte[] buf = new byte[tag.getComponentCount()];
- tag.getBytes(buf);
-
- byte[] code = new byte[8];
- System.arraycopy(buf, 0, code, 0, 8);
-
- try {
- if (Arrays.equals(code, USER_COMMENT_ASCII)) {
- return new String(buf, 8, buf.length - 8, "US-ASCII");
- } else if (Arrays.equals(code, USER_COMMENT_JIS)) {
- return new String(buf, 8, buf.length - 8, "EUC-JP");
- } else if (Arrays.equals(code, USER_COMMENT_UNICODE)) {
- return new String(buf, 8, buf.length - 8, "UTF-16");
- } else {
- return null;
- }
- } catch (UnsupportedEncodingException e) {
- Log.w(TAG, "Failed to decode the user comment");
- return null;
- }
- }
-
- /**
- * Returns a list of all {@link ExifTag}s in the ExifData or null if there
- * are none.
- */
- protected List<ExifTag> getAllTags() {
- ArrayList<ExifTag> ret = new ArrayList<ExifTag>();
- for (IfdData d : mIfdDatas) {
- if (d != null) {
- ExifTag[] tags = d.getAllTags();
- if (tags != null) {
- for (ExifTag t : tags) {
- ret.add(t);
- }
- }
- }
- }
- if (ret.size() == 0) {
- return null;
- }
- return ret;
- }
-
- /**
- * Returns a list of all {@link ExifTag}s in a given IFD or null if there
- * are none.
- */
- protected List<ExifTag> getAllTagsForIfd(int ifd) {
- IfdData d = mIfdDatas[ifd];
- if (d == null) {
- return null;
- }
- ExifTag[] tags = d.getAllTags();
- if (tags == null) {
- return null;
- }
- ArrayList<ExifTag> ret = new ArrayList<ExifTag>(tags.length);
- for (ExifTag t : tags) {
- ret.add(t);
- }
- if (ret.size() == 0) {
- return null;
- }
- return ret;
- }
-
- /**
- * Returns a list of all {@link ExifTag}s with a given TID or null if there
- * are none.
- */
- protected List<ExifTag> getAllTagsForTagId(short tag) {
- ArrayList<ExifTag> ret = new ArrayList<ExifTag>();
- for (IfdData d : mIfdDatas) {
- if (d != null) {
- ExifTag t = d.getTag(tag);
- if (t != null) {
- ret.add(t);
- }
- }
- }
- if (ret.size() == 0) {
- return null;
- }
- return ret;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null) {
- return false;
- }
- if (obj instanceof ExifData) {
- ExifData data = (ExifData) obj;
- if (data.mByteOrder != mByteOrder ||
- data.mStripBytes.size() != mStripBytes.size() ||
- !Arrays.equals(data.mThumbnail, mThumbnail)) {
- return false;
- }
- for (int i = 0; i < mStripBytes.size(); i++) {
- if (!Arrays.equals(data.mStripBytes.get(i), mStripBytes.get(i))) {
- return false;
- }
- }
- for (int i = 0; i < IfdId.TYPE_IFD_COUNT; i++) {
- IfdData ifd1 = data.getIfdData(i);
- IfdData ifd2 = getIfdData(i);
- if (ifd1 != ifd2 && ifd1 != null && !ifd1.equals(ifd2)) {
- return false;
- }
- }
- return true;
- }
- return false;
- }
-
-}
diff --git a/WallpaperPicker/src/com/android/gallery3d/exif/ExifInterface.java b/WallpaperPicker/src/com/android/gallery3d/exif/ExifInterface.java
deleted file mode 100644
index 9247e879f..000000000
--- a/WallpaperPicker/src/com/android/gallery3d/exif/ExifInterface.java
+++ /dev/null
@@ -1,2407 +0,0 @@
-/*
- * Copyright (C) 2013 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.exif;
-
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.util.SparseIntArray;
-
-import java.io.BufferedInputStream;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.Closeable;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.RandomAccessFile;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.channels.FileChannel.MapMode;
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Calendar;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.List;
-import java.util.TimeZone;
-
-/**
- * This class provides methods and constants for reading and writing jpeg file
- * metadata. It contains a collection of ExifTags, and a collection of
- * definitions for creating valid ExifTags. The collection of ExifTags can be
- * updated by: reading new ones from a file, deleting or adding existing ones,
- * or building new ExifTags from a tag definition. These ExifTags can be written
- * to a valid jpeg image as exif metadata.
- * <p>
- * Each ExifTag has a tag ID (TID) and is stored in a specific image file
- * directory (IFD) as specified by the exif standard. A tag definition can be
- * looked up with a constant that is a combination of TID and IFD. This
- * definition has information about the type, number of components, and valid
- * IFDs for a tag.
- *
- * @see ExifTag
- */
-public class ExifInterface {
- public static final int TAG_NULL = -1;
- public static final int IFD_NULL = -1;
- public static final int DEFINITION_NULL = 0;
-
- /**
- * Tag constants for Jeita EXIF 2.2
- */
-
- // IFD 0
- public static final int TAG_IMAGE_WIDTH =
- defineTag(IfdId.TYPE_IFD_0, (short) 0x0100);
- public static final int TAG_IMAGE_LENGTH =
- defineTag(IfdId.TYPE_IFD_0, (short) 0x0101); // Image height
- public static final int TAG_BITS_PER_SAMPLE =
- defineTag(IfdId.TYPE_IFD_0, (short) 0x0102);
- public static final int TAG_COMPRESSION =
- defineTag(IfdId.TYPE_IFD_0, (short) 0x0103);
- public static final int TAG_PHOTOMETRIC_INTERPRETATION =
- defineTag(IfdId.TYPE_IFD_0, (short) 0x0106);
- public static final int TAG_IMAGE_DESCRIPTION =
- defineTag(IfdId.TYPE_IFD_0, (short) 0x010E);
- public static final int TAG_MAKE =
- defineTag(IfdId.TYPE_IFD_0, (short) 0x010F);
- public static final int TAG_MODEL =
- defineTag(IfdId.TYPE_IFD_0, (short) 0x0110);
- public static final int TAG_STRIP_OFFSETS =
- defineTag(IfdId.TYPE_IFD_0, (short) 0x0111);
- public static final int TAG_ORIENTATION =
- defineTag(IfdId.TYPE_IFD_0, (short) 0x0112);
- public static final int TAG_SAMPLES_PER_PIXEL =
- defineTag(IfdId.TYPE_IFD_0, (short) 0x0115);
- public static final int TAG_ROWS_PER_STRIP =
- defineTag(IfdId.TYPE_IFD_0, (short) 0x0116);
- public static final int TAG_STRIP_BYTE_COUNTS =
- defineTag(IfdId.TYPE_IFD_0, (short) 0x0117);
- public static final int TAG_X_RESOLUTION =
- defineTag(IfdId.TYPE_IFD_0, (short) 0x011A);
- public static final int TAG_Y_RESOLUTION =
- defineTag(IfdId.TYPE_IFD_0, (short) 0x011B);
- public static final int TAG_PLANAR_CONFIGURATION =
- defineTag(IfdId.TYPE_IFD_0, (short) 0x011C);
- public static final int TAG_RESOLUTION_UNIT =
- defineTag(IfdId.TYPE_IFD_0, (short) 0x0128);
- public static final int TAG_TRANSFER_FUNCTION =
- defineTag(IfdId.TYPE_IFD_0, (short) 0x012D);
- public static final int TAG_SOFTWARE =
- defineTag(IfdId.TYPE_IFD_0, (short) 0x0131);
- public static final int TAG_DATE_TIME =
- defineTag(IfdId.TYPE_IFD_0, (short) 0x0132);
- public static final int TAG_ARTIST =
- defineTag(IfdId.TYPE_IFD_0, (short) 0x013B);
- public static final int TAG_WHITE_POINT =
- defineTag(IfdId.TYPE_IFD_0, (short) 0x013E);
- public static final int TAG_PRIMARY_CHROMATICITIES =
- defineTag(IfdId.TYPE_IFD_0, (short) 0x013F);
- public static final int TAG_Y_CB_CR_COEFFICIENTS =
- defineTag(IfdId.TYPE_IFD_0, (short) 0x0211);
- public static final int TAG_Y_CB_CR_SUB_SAMPLING =
- defineTag(IfdId.TYPE_IFD_0, (short) 0x0212);
- public static final int TAG_Y_CB_CR_POSITIONING =
- defineTag(IfdId.TYPE_IFD_0, (short) 0x0213);
- public static final int TAG_REFERENCE_BLACK_WHITE =
- defineTag(IfdId.TYPE_IFD_0, (short) 0x0214);
- public static final int TAG_COPYRIGHT =
- defineTag(IfdId.TYPE_IFD_0, (short) 0x8298);
- public static final int TAG_EXIF_IFD =
- defineTag(IfdId.TYPE_IFD_0, (short) 0x8769);
- public static final int TAG_GPS_IFD =
- defineTag(IfdId.TYPE_IFD_0, (short) 0x8825);
- // IFD 1
- public static final int TAG_JPEG_INTERCHANGE_FORMAT =
- defineTag(IfdId.TYPE_IFD_1, (short) 0x0201);
- public static final int TAG_JPEG_INTERCHANGE_FORMAT_LENGTH =
- defineTag(IfdId.TYPE_IFD_1, (short) 0x0202);
- // IFD Exif Tags
- public static final int TAG_EXPOSURE_TIME =
- defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x829A);
- public static final int TAG_F_NUMBER =
- defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x829D);
- public static final int TAG_EXPOSURE_PROGRAM =
- defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x8822);
- public static final int TAG_SPECTRAL_SENSITIVITY =
- defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x8824);
- public static final int TAG_ISO_SPEED_RATINGS =
- defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x8827);
- public static final int TAG_OECF =
- defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x8828);
- public static final int TAG_EXIF_VERSION =
- defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9000);
- public static final int TAG_DATE_TIME_ORIGINAL =
- defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9003);
- public static final int TAG_DATE_TIME_DIGITIZED =
- defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9004);
- public static final int TAG_COMPONENTS_CONFIGURATION =
- defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9101);
- public static final int TAG_COMPRESSED_BITS_PER_PIXEL =
- defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9102);
- public static final int TAG_SHUTTER_SPEED_VALUE =
- defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9201);
- public static final int TAG_APERTURE_VALUE =
- defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9202);
- public static final int TAG_BRIGHTNESS_VALUE =
- defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9203);
- public static final int TAG_EXPOSURE_BIAS_VALUE =
- defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9204);
- public static final int TAG_MAX_APERTURE_VALUE =
- defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9205);
- public static final int TAG_SUBJECT_DISTANCE =
- defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9206);
- public static final int TAG_METERING_MODE =
- defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9207);
- public static final int TAG_LIGHT_SOURCE =
- defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9208);
- public static final int TAG_FLASH =
- defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9209);
- public static final int TAG_FOCAL_LENGTH =
- defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x920A);
- public static final int TAG_SUBJECT_AREA =
- defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9214);
- public static final int TAG_MAKER_NOTE =
- defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x927C);
- public static final int TAG_USER_COMMENT =
- defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9286);
- public static final int TAG_SUB_SEC_TIME =
- defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9290);
- public static final int TAG_SUB_SEC_TIME_ORIGINAL =
- defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9291);
- public static final int TAG_SUB_SEC_TIME_DIGITIZED =
- defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9292);
- public static final int TAG_FLASHPIX_VERSION =
- defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA000);
- public static final int TAG_COLOR_SPACE =
- defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA001);
- public static final int TAG_PIXEL_X_DIMENSION =
- defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA002);
- public static final int TAG_PIXEL_Y_DIMENSION =
- defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA003);
- public static final int TAG_RELATED_SOUND_FILE =
- defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA004);
- public static final int TAG_INTEROPERABILITY_IFD =
- defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA005);
- public static final int TAG_FLASH_ENERGY =
- defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA20B);
- public static final int TAG_SPATIAL_FREQUENCY_RESPONSE =
- defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA20C);
- public static final int TAG_FOCAL_PLANE_X_RESOLUTION =
- defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA20E);
- public static final int TAG_FOCAL_PLANE_Y_RESOLUTION =
- defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA20F);
- public static final int TAG_FOCAL_PLANE_RESOLUTION_UNIT =
- defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA210);
- public static final int TAG_SUBJECT_LOCATION =
- defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA214);
- public static final int TAG_EXPOSURE_INDEX =
- defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA215);
- public static final int TAG_SENSING_METHOD =
- defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA217);
- public static final int TAG_FILE_SOURCE =
- defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA300);
- public static final int TAG_SCENE_TYPE =
- defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA301);
- public static final int TAG_CFA_PATTERN =
- defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA302);
- public static final int TAG_CUSTOM_RENDERED =
- defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA401);
- public static final int TAG_EXPOSURE_MODE =
- defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA402);
- public static final int TAG_WHITE_BALANCE =
- defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA403);
- public static final int TAG_DIGITAL_ZOOM_RATIO =
- defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA404);
- public static final int TAG_FOCAL_LENGTH_IN_35_MM_FILE =
- defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA405);
- public static final int TAG_SCENE_CAPTURE_TYPE =
- defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA406);
- public static final int TAG_GAIN_CONTROL =
- defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA407);
- public static final int TAG_CONTRAST =
- defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA408);
- public static final int TAG_SATURATION =
- defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA409);
- public static final int TAG_SHARPNESS =
- defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA40A);
- public static final int TAG_DEVICE_SETTING_DESCRIPTION =
- defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA40B);
- public static final int TAG_SUBJECT_DISTANCE_RANGE =
- defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA40C);
- public static final int TAG_IMAGE_UNIQUE_ID =
- defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA420);
- // IFD GPS tags
- public static final int TAG_GPS_VERSION_ID =
- defineTag(IfdId.TYPE_IFD_GPS, (short) 0);
- public static final int TAG_GPS_LATITUDE_REF =
- defineTag(IfdId.TYPE_IFD_GPS, (short) 1);
- public static final int TAG_GPS_LATITUDE =
- defineTag(IfdId.TYPE_IFD_GPS, (short) 2);
- public static final int TAG_GPS_LONGITUDE_REF =
- defineTag(IfdId.TYPE_IFD_GPS, (short) 3);
- public static final int TAG_GPS_LONGITUDE =
- defineTag(IfdId.TYPE_IFD_GPS, (short) 4);
- public static final int TAG_GPS_ALTITUDE_REF =
- defineTag(IfdId.TYPE_IFD_GPS, (short) 5);
- public static final int TAG_GPS_ALTITUDE =
- defineTag(IfdId.TYPE_IFD_GPS, (short) 6);
- public static final int TAG_GPS_TIME_STAMP =
- defineTag(IfdId.TYPE_IFD_GPS, (short) 7);
- public static final int TAG_GPS_SATTELLITES =
- defineTag(IfdId.TYPE_IFD_GPS, (short) 8);
- public static final int TAG_GPS_STATUS =
- defineTag(IfdId.TYPE_IFD_GPS, (short) 9);
- public static final int TAG_GPS_MEASURE_MODE =
- defineTag(IfdId.TYPE_IFD_GPS, (short) 10);
- public static final int TAG_GPS_DOP =
- defineTag(IfdId.TYPE_IFD_GPS, (short) 11);
- public static final int TAG_GPS_SPEED_REF =
- defineTag(IfdId.TYPE_IFD_GPS, (short) 12);
- public static final int TAG_GPS_SPEED =
- defineTag(IfdId.TYPE_IFD_GPS, (short) 13);
- public static final int TAG_GPS_TRACK_REF =
- defineTag(IfdId.TYPE_IFD_GPS, (short) 14);
- public static final int TAG_GPS_TRACK =
- defineTag(IfdId.TYPE_IFD_GPS, (short) 15);
- public static final int TAG_GPS_IMG_DIRECTION_REF =
- defineTag(IfdId.TYPE_IFD_GPS, (short) 16);
- public static final int TAG_GPS_IMG_DIRECTION =
- defineTag(IfdId.TYPE_IFD_GPS, (short) 17);
- public static final int TAG_GPS_MAP_DATUM =
- defineTag(IfdId.TYPE_IFD_GPS, (short) 18);
- public static final int TAG_GPS_DEST_LATITUDE_REF =
- defineTag(IfdId.TYPE_IFD_GPS, (short) 19);
- public static final int TAG_GPS_DEST_LATITUDE =
- defineTag(IfdId.TYPE_IFD_GPS, (short) 20);
- public static final int TAG_GPS_DEST_LONGITUDE_REF =
- defineTag(IfdId.TYPE_IFD_GPS, (short) 21);
- public static final int TAG_GPS_DEST_LONGITUDE =
- defineTag(IfdId.TYPE_IFD_GPS, (short) 22);
- public static final int TAG_GPS_DEST_BEARING_REF =
- defineTag(IfdId.TYPE_IFD_GPS, (short) 23);
- public static final int TAG_GPS_DEST_BEARING =
- defineTag(IfdId.TYPE_IFD_GPS, (short) 24);
- public static final int TAG_GPS_DEST_DISTANCE_REF =
- defineTag(IfdId.TYPE_IFD_GPS, (short) 25);
- public static final int TAG_GPS_DEST_DISTANCE =
- defineTag(IfdId.TYPE_IFD_GPS, (short) 26);
- public static final int TAG_GPS_PROCESSING_METHOD =
- defineTag(IfdId.TYPE_IFD_GPS, (short) 27);
- public static final int TAG_GPS_AREA_INFORMATION =
- defineTag(IfdId.TYPE_IFD_GPS, (short) 28);
- public static final int TAG_GPS_DATE_STAMP =
- defineTag(IfdId.TYPE_IFD_GPS, (short) 29);
- public static final int TAG_GPS_DIFFERENTIAL =
- defineTag(IfdId.TYPE_IFD_GPS, (short) 30);
- // IFD Interoperability tags
- public static final int TAG_INTEROPERABILITY_INDEX =
- defineTag(IfdId.TYPE_IFD_INTEROPERABILITY, (short) 1);
-
- /**
- * Tags that contain offset markers. These are included in the banned
- * defines.
- */
- private static HashSet<Short> sOffsetTags = new HashSet<Short>();
- static {
- sOffsetTags.add(getTrueTagKey(TAG_GPS_IFD));
- sOffsetTags.add(getTrueTagKey(TAG_EXIF_IFD));
- sOffsetTags.add(getTrueTagKey(TAG_JPEG_INTERCHANGE_FORMAT));
- sOffsetTags.add(getTrueTagKey(TAG_INTEROPERABILITY_IFD));
- sOffsetTags.add(getTrueTagKey(TAG_STRIP_OFFSETS));
- }
-
- /**
- * Tags with definitions that cannot be overridden (banned defines).
- */
- protected static HashSet<Short> sBannedDefines = new HashSet<Short>(sOffsetTags);
- static {
- sBannedDefines.add(getTrueTagKey(TAG_NULL));
- sBannedDefines.add(getTrueTagKey(TAG_JPEG_INTERCHANGE_FORMAT_LENGTH));
- sBannedDefines.add(getTrueTagKey(TAG_STRIP_BYTE_COUNTS));
- }
-
- /**
- * Returns the constant representing a tag with a given TID and default IFD.
- */
- public static int defineTag(int ifdId, short tagId) {
- return (tagId & 0x0000ffff) | (ifdId << 16);
- }
-
- /**
- * Returns the TID for a tag constant.
- */
- public static short getTrueTagKey(int tag) {
- // Truncate
- return (short) tag;
- }
-
- /**
- * Returns the default IFD for a tag constant.
- */
- public static int getTrueIfd(int tag) {
- return tag >>> 16;
- }
-
- /**
- * Constants for {@link TAG_ORIENTATION}. They can be interpreted as
- * follows:
- * <ul>
- * <li>TOP_LEFT is the normal orientation.</li>
- * <li>TOP_RIGHT is a left-right mirror.</li>
- * <li>BOTTOM_LEFT is a 180 degree rotation.</li>
- * <li>BOTTOM_RIGHT is a top-bottom mirror.</li>
- * <li>LEFT_TOP is mirrored about the top-left<->bottom-right axis.</li>
- * <li>RIGHT_TOP is a 90 degree clockwise rotation.</li>
- * <li>LEFT_BOTTOM is mirrored about the top-right<->bottom-left axis.</li>
- * <li>RIGHT_BOTTOM is a 270 degree clockwise rotation.</li>
- * </ul>
- */
- public static interface Orientation {
- public static final short TOP_LEFT = 1;
- public static final short TOP_RIGHT = 2;
- public static final short BOTTOM_LEFT = 3;
- public static final short BOTTOM_RIGHT = 4;
- public static final short LEFT_TOP = 5;
- public static final short RIGHT_TOP = 6;
- public static final short LEFT_BOTTOM = 7;
- public static final short RIGHT_BOTTOM = 8;
- }
-
- /**
- * Constants for {@link TAG_Y_CB_CR_POSITIONING}
- */
- public static interface YCbCrPositioning {
- public static final short CENTERED = 1;
- public static final short CO_SITED = 2;
- }
-
- /**
- * Constants for {@link TAG_COMPRESSION}
- */
- public static interface Compression {
- public static final short UNCOMPRESSION = 1;
- public static final short JPEG = 6;
- }
-
- /**
- * Constants for {@link TAG_RESOLUTION_UNIT}
- */
- public static interface ResolutionUnit {
- public static final short INCHES = 2;
- public static final short CENTIMETERS = 3;
- }
-
- /**
- * Constants for {@link TAG_PHOTOMETRIC_INTERPRETATION}
- */
- public static interface PhotometricInterpretation {
- public static final short RGB = 2;
- public static final short YCBCR = 6;
- }
-
- /**
- * Constants for {@link TAG_PLANAR_CONFIGURATION}
- */
- public static interface PlanarConfiguration {
- public static final short CHUNKY = 1;
- public static final short PLANAR = 2;
- }
-
- /**
- * Constants for {@link TAG_EXPOSURE_PROGRAM}
- */
- public static interface ExposureProgram {
- public static final short NOT_DEFINED = 0;
- public static final short MANUAL = 1;
- public static final short NORMAL_PROGRAM = 2;
- public static final short APERTURE_PRIORITY = 3;
- public static final short SHUTTER_PRIORITY = 4;
- public static final short CREATIVE_PROGRAM = 5;
- public static final short ACTION_PROGRAM = 6;
- public static final short PROTRAIT_MODE = 7;
- public static final short LANDSCAPE_MODE = 8;
- }
-
- /**
- * Constants for {@link TAG_METERING_MODE}
- */
- public static interface MeteringMode {
- public static final short UNKNOWN = 0;
- public static final short AVERAGE = 1;
- public static final short CENTER_WEIGHTED_AVERAGE = 2;
- public static final short SPOT = 3;
- public static final short MULTISPOT = 4;
- public static final short PATTERN = 5;
- public static final short PARTAIL = 6;
- public static final short OTHER = 255;
- }
-
- /**
- * Constants for {@link TAG_FLASH} As the definition in Jeita EXIF 2.2
- * standard, we can treat this constant as bitwise flag.
- * <p>
- * e.g.
- * <p>
- * short flash = FIRED | RETURN_STROBE_RETURN_LIGHT_DETECTED |
- * MODE_AUTO_MODE
- */
- public static interface Flash {
- // LSB
- public static final short DID_NOT_FIRED = 0;
- public static final short FIRED = 1;
- // 1st~2nd bits
- public static final short RETURN_NO_STROBE_RETURN_DETECTION_FUNCTION = 0 << 1;
- public static final short RETURN_STROBE_RETURN_LIGHT_NOT_DETECTED = 2 << 1;
- public static final short RETURN_STROBE_RETURN_LIGHT_DETECTED = 3 << 1;
- // 3rd~4th bits
- public static final short MODE_UNKNOWN = 0 << 3;
- public static final short MODE_COMPULSORY_FLASH_FIRING = 1 << 3;
- public static final short MODE_COMPULSORY_FLASH_SUPPRESSION = 2 << 3;
- public static final short MODE_AUTO_MODE = 3 << 3;
- // 5th bit
- public static final short FUNCTION_PRESENT = 0 << 5;
- public static final short FUNCTION_NO_FUNCTION = 1 << 5;
- // 6th bit
- public static final short RED_EYE_REDUCTION_NO_OR_UNKNOWN = 0 << 6;
- public static final short RED_EYE_REDUCTION_SUPPORT = 1 << 6;
- }
-
- /**
- * Constants for {@link TAG_COLOR_SPACE}
- */
- public static interface ColorSpace {
- public static final short SRGB = 1;
- public static final short UNCALIBRATED = (short) 0xFFFF;
- }
-
- /**
- * Constants for {@link TAG_EXPOSURE_MODE}
- */
- public static interface ExposureMode {
- public static final short AUTO_EXPOSURE = 0;
- public static final short MANUAL_EXPOSURE = 1;
- public static final short AUTO_BRACKET = 2;
- }
-
- /**
- * Constants for {@link TAG_WHITE_BALANCE}
- */
- public static interface WhiteBalance {
- public static final short AUTO = 0;
- public static final short MANUAL = 1;
- }
-
- /**
- * Constants for {@link TAG_SCENE_CAPTURE_TYPE}
- */
- public static interface SceneCapture {
- public static final short STANDARD = 0;
- public static final short LANDSCAPE = 1;
- public static final short PROTRAIT = 2;
- public static final short NIGHT_SCENE = 3;
- }
-
- /**
- * Constants for {@link TAG_COMPONENTS_CONFIGURATION}
- */
- public static interface ComponentsConfiguration {
- public static final short NOT_EXIST = 0;
- public static final short Y = 1;
- public static final short CB = 2;
- public static final short CR = 3;
- public static final short R = 4;
- public static final short G = 5;
- public static final short B = 6;
- }
-
- /**
- * Constants for {@link TAG_LIGHT_SOURCE}
- */
- public static interface LightSource {
- public static final short UNKNOWN = 0;
- public static final short DAYLIGHT = 1;
- public static final short FLUORESCENT = 2;
- public static final short TUNGSTEN = 3;
- public static final short FLASH = 4;
- public static final short FINE_WEATHER = 9;
- public static final short CLOUDY_WEATHER = 10;
- public static final short SHADE = 11;
- public static final short DAYLIGHT_FLUORESCENT = 12;
- public static final short DAY_WHITE_FLUORESCENT = 13;
- public static final short COOL_WHITE_FLUORESCENT = 14;
- public static final short WHITE_FLUORESCENT = 15;
- public static final short STANDARD_LIGHT_A = 17;
- public static final short STANDARD_LIGHT_B = 18;
- public static final short STANDARD_LIGHT_C = 19;
- public static final short D55 = 20;
- public static final short D65 = 21;
- public static final short D75 = 22;
- public static final short D50 = 23;
- public static final short ISO_STUDIO_TUNGSTEN = 24;
- public static final short OTHER = 255;
- }
-
- /**
- * Constants for {@link TAG_SENSING_METHOD}
- */
- public static interface SensingMethod {
- public static final short NOT_DEFINED = 1;
- public static final short ONE_CHIP_COLOR = 2;
- public static final short TWO_CHIP_COLOR = 3;
- public static final short THREE_CHIP_COLOR = 4;
- public static final short COLOR_SEQUENTIAL_AREA = 5;
- public static final short TRILINEAR = 7;
- public static final short COLOR_SEQUENTIAL_LINEAR = 8;
- }
-
- /**
- * Constants for {@link TAG_FILE_SOURCE}
- */
- public static interface FileSource {
- public static final short DSC = 3;
- }
-
- /**
- * Constants for {@link TAG_SCENE_TYPE}
- */
- public static interface SceneType {
- public static final short DIRECT_PHOTOGRAPHED = 1;
- }
-
- /**
- * Constants for {@link TAG_GAIN_CONTROL}
- */
- public static interface GainControl {
- public static final short NONE = 0;
- public static final short LOW_UP = 1;
- public static final short HIGH_UP = 2;
- public static final short LOW_DOWN = 3;
- public static final short HIGH_DOWN = 4;
- }
-
- /**
- * Constants for {@link TAG_CONTRAST}
- */
- public static interface Contrast {
- public static final short NORMAL = 0;
- public static final short SOFT = 1;
- public static final short HARD = 2;
- }
-
- /**
- * Constants for {@link TAG_SATURATION}
- */
- public static interface Saturation {
- public static final short NORMAL = 0;
- public static final short LOW = 1;
- public static final short HIGH = 2;
- }
-
- /**
- * Constants for {@link TAG_SHARPNESS}
- */
- public static interface Sharpness {
- public static final short NORMAL = 0;
- public static final short SOFT = 1;
- public static final short HARD = 2;
- }
-
- /**
- * Constants for {@link TAG_SUBJECT_DISTANCE}
- */
- public static interface SubjectDistance {
- public static final short UNKNOWN = 0;
- public static final short MACRO = 1;
- public static final short CLOSE_VIEW = 2;
- public static final short DISTANT_VIEW = 3;
- }
-
- /**
- * Constants for {@link TAG_GPS_LATITUDE_REF},
- * {@link TAG_GPS_DEST_LATITUDE_REF}
- */
- public static interface GpsLatitudeRef {
- public static final String NORTH = "N";
- public static final String SOUTH = "S";
- }
-
- /**
- * Constants for {@link TAG_GPS_LONGITUDE_REF},
- * {@link TAG_GPS_DEST_LONGITUDE_REF}
- */
- public static interface GpsLongitudeRef {
- public static final String EAST = "E";
- public static final String WEST = "W";
- }
-
- /**
- * Constants for {@link TAG_GPS_ALTITUDE_REF}
- */
- public static interface GpsAltitudeRef {
- public static final short SEA_LEVEL = 0;
- public static final short SEA_LEVEL_NEGATIVE = 1;
- }
-
- /**
- * Constants for {@link TAG_GPS_STATUS}
- */
- public static interface GpsStatus {
- public static final String IN_PROGRESS = "A";
- public static final String INTEROPERABILITY = "V";
- }
-
- /**
- * Constants for {@link TAG_GPS_MEASURE_MODE}
- */
- public static interface GpsMeasureMode {
- public static final String MODE_2_DIMENSIONAL = "2";
- public static final String MODE_3_DIMENSIONAL = "3";
- }
-
- /**
- * Constants for {@link TAG_GPS_SPEED_REF},
- * {@link TAG_GPS_DEST_DISTANCE_REF}
- */
- public static interface GpsSpeedRef {
- public static final String KILOMETERS = "K";
- public static final String MILES = "M";
- public static final String KNOTS = "N";
- }
-
- /**
- * Constants for {@link TAG_GPS_TRACK_REF},
- * {@link TAG_GPS_IMG_DIRECTION_REF}, {@link TAG_GPS_DEST_BEARING_REF}
- */
- public static interface GpsTrackRef {
- public static final String TRUE_DIRECTION = "T";
- public static final String MAGNETIC_DIRECTION = "M";
- }
-
- /**
- * Constants for {@link TAG_GPS_DIFFERENTIAL}
- */
- public static interface GpsDifferential {
- public static final short WITHOUT_DIFFERENTIAL_CORRECTION = 0;
- public static final short DIFFERENTIAL_CORRECTION_APPLIED = 1;
- }
-
- private static final String NULL_ARGUMENT_STRING = "Argument is null";
- private ExifData mData = new ExifData(DEFAULT_BYTE_ORDER);
- public static final ByteOrder DEFAULT_BYTE_ORDER = ByteOrder.BIG_ENDIAN;
-
- public ExifInterface() {
- mGPSDateStampFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
- }
-
- /**
- * Reads the exif tags from a byte array, clearing this ExifInterface
- * object's existing exif tags.
- *
- * @param jpeg a byte array containing a jpeg compressed image.
- * @throws IOException
- */
- public void readExif(byte[] jpeg) throws IOException {
- readExif(new ByteArrayInputStream(jpeg));
- }
-
- /**
- * Reads the exif tags from an InputStream, clearing this ExifInterface
- * object's existing exif tags.
- *
- * @param inStream an InputStream containing a jpeg compressed image.
- * @throws IOException
- */
- public void readExif(InputStream inStream) throws IOException {
- if (inStream == null) {
- throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
- }
- ExifData d = null;
- try {
- d = new ExifReader(this).read(inStream);
- } catch (ExifInvalidFormatException e) {
- throw new IOException("Invalid exif format : " + e);
- }
- mData = d;
- }
-
- /**
- * Reads the exif tags from a file, clearing this ExifInterface object's
- * existing exif tags.
- *
- * @param inFileName a string representing the filepath to jpeg file.
- * @throws FileNotFoundException
- * @throws IOException
- */
- public void readExif(String inFileName) throws FileNotFoundException, IOException {
- if (inFileName == null) {
- throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
- }
- InputStream is = null;
- try {
- is = (InputStream) new BufferedInputStream(new FileInputStream(inFileName));
- readExif(is);
- } catch (IOException e) {
- closeSilently(is);
- throw e;
- }
- is.close();
- }
-
- /**
- * Sets the exif tags, clearing this ExifInterface object's existing exif
- * tags.
- *
- * @param tags a collection of exif tags to set.
- */
- public void setExif(Collection<ExifTag> tags) {
- clearExif();
- setTags(tags);
- }
-
- /**
- * Clears this ExifInterface object's existing exif tags.
- */
- public void clearExif() {
- mData = new ExifData(DEFAULT_BYTE_ORDER);
- }
-
- /**
- * Writes the tags from this ExifInterface object into a jpeg image,
- * removing prior exif tags.
- *
- * @param jpeg a byte array containing a jpeg compressed image.
- * @param exifOutStream an OutputStream to which the jpeg image with added
- * exif tags will be written.
- * @throws IOException
- */
- public void writeExif(byte[] jpeg, OutputStream exifOutStream) throws IOException {
- if (jpeg == null || exifOutStream == null) {
- throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
- }
- OutputStream s = getExifWriterStream(exifOutStream);
- s.write(jpeg, 0, jpeg.length);
- s.flush();
- }
-
- /**
- * Writes the tags from this ExifInterface object into a jpeg compressed
- * bitmap, removing prior exif tags.
- *
- * @param bmap a bitmap to compress and write exif into.
- * @param exifOutStream the OutputStream to which the jpeg image with added
- * exif tags will be written.
- * @throws IOException
- */
- public void writeExif(Bitmap bmap, OutputStream exifOutStream) throws IOException {
- if (bmap == null || exifOutStream == null) {
- throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
- }
- OutputStream s = getExifWriterStream(exifOutStream);
- bmap.compress(Bitmap.CompressFormat.JPEG, 90, s);
- s.flush();
- }
-
- /**
- * Writes the tags from this ExifInterface object into a jpeg stream,
- * removing prior exif tags.
- *
- * @param jpegStream an InputStream containing a jpeg compressed image.
- * @param exifOutStream an OutputStream to which the jpeg image with added
- * exif tags will be written.
- * @throws IOException
- */
- public void writeExif(InputStream jpegStream, OutputStream exifOutStream) throws IOException {
- if (jpegStream == null || exifOutStream == null) {
- throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
- }
- OutputStream s = getExifWriterStream(exifOutStream);
- doExifStreamIO(jpegStream, s);
- s.flush();
- }
-
- /**
- * Writes the tags from this ExifInterface object into a jpeg image,
- * removing prior exif tags.
- *
- * @param jpeg a byte array containing a jpeg compressed image.
- * @param exifOutFileName a String containing the filepath to which the jpeg
- * image with added exif tags will be written.
- * @throws FileNotFoundException
- * @throws IOException
- */
- public void writeExif(byte[] jpeg, String exifOutFileName) throws FileNotFoundException,
- IOException {
- if (jpeg == null || exifOutFileName == null) {
- throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
- }
- OutputStream s = null;
- try {
- s = getExifWriterStream(exifOutFileName);
- s.write(jpeg, 0, jpeg.length);
- s.flush();
- } catch (IOException e) {
- closeSilently(s);
- throw e;
- }
- s.close();
- }
-
- /**
- * Writes the tags from this ExifInterface object into a jpeg compressed
- * bitmap, removing prior exif tags.
- *
- * @param bmap a bitmap to compress and write exif into.
- * @param exifOutFileName a String containing the filepath to which the jpeg
- * image with added exif tags will be written.
- * @throws FileNotFoundException
- * @throws IOException
- */
- public void writeExif(Bitmap bmap, String exifOutFileName) throws FileNotFoundException,
- IOException {
- if (bmap == null || exifOutFileName == null) {
- throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
- }
- OutputStream s = null;
- try {
- s = getExifWriterStream(exifOutFileName);
- bmap.compress(Bitmap.CompressFormat.JPEG, 90, s);
- s.flush();
- } catch (IOException e) {
- closeSilently(s);
- throw e;
- }
- s.close();
- }
-
- /**
- * Writes the tags from this ExifInterface object into a jpeg stream,
- * removing prior exif tags.
- *
- * @param jpegStream an InputStream containing a jpeg compressed image.
- * @param exifOutFileName a String containing the filepath to which the jpeg
- * image with added exif tags will be written.
- * @throws FileNotFoundException
- * @throws IOException
- */
- public void writeExif(InputStream jpegStream, String exifOutFileName)
- throws FileNotFoundException, IOException {
- if (jpegStream == null || exifOutFileName == null) {
- throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
- }
- OutputStream s = null;
- try {
- s = getExifWriterStream(exifOutFileName);
- doExifStreamIO(jpegStream, s);
- s.flush();
- } catch (IOException e) {
- closeSilently(s);
- throw e;
- }
- s.close();
- }
-
- /**
- * Writes the tags from this ExifInterface object into a jpeg file, removing
- * prior exif tags.
- *
- * @param jpegFileName a String containing the filepath for a jpeg file.
- * @param exifOutFileName a String containing the filepath to which the jpeg
- * image with added exif tags will be written.
- * @throws FileNotFoundException
- * @throws IOException
- */
- public void writeExif(String jpegFileName, String exifOutFileName)
- throws FileNotFoundException, IOException {
- if (jpegFileName == null || exifOutFileName == null) {
- throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
- }
- InputStream is = null;
- try {
- is = new FileInputStream(jpegFileName);
- writeExif(is, exifOutFileName);
- } catch (IOException e) {
- closeSilently(is);
- throw e;
- }
- is.close();
- }
-
- /**
- * Wraps an OutputStream object with an ExifOutputStream. Exif tags in this
- * ExifInterface object will be added to a jpeg image written to this
- * stream, removing prior exif tags. Other methods of this ExifInterface
- * object should not be called until the returned OutputStream has been
- * closed.
- *
- * @param outStream an OutputStream to wrap.
- * @return an OutputStream that wraps the outStream parameter, and adds exif
- * metadata. A jpeg image should be written to this stream.
- */
- public OutputStream getExifWriterStream(OutputStream outStream) {
- if (outStream == null) {
- throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
- }
- ExifOutputStream eos = new ExifOutputStream(outStream, this);
- eos.setExifData(mData);
- return eos;
- }
-
- /**
- * Returns an OutputStream object that writes to a file. Exif tags in this
- * ExifInterface object will be added to a jpeg image written to this
- * stream, removing prior exif tags. Other methods of this ExifInterface
- * object should not be called until the returned OutputStream has been
- * closed.
- *
- * @param exifOutFileName an String containing a filepath for a jpeg file.
- * @return an OutputStream that writes to the exifOutFileName file, and adds
- * exif metadata. A jpeg image should be written to this stream.
- * @throws FileNotFoundException
- */
- public OutputStream getExifWriterStream(String exifOutFileName) throws FileNotFoundException {
- if (exifOutFileName == null) {
- throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
- }
- OutputStream out = null;
- try {
- out = (OutputStream) new FileOutputStream(exifOutFileName);
- } catch (FileNotFoundException e) {
- closeSilently(out);
- throw e;
- }
- return getExifWriterStream(out);
- }
-
- /**
- * Attempts to do an in-place rewrite the exif metadata in a file for the
- * given tags. If tags do not exist or do not have the same size as the
- * existing exif tags, this method will fail.
- *
- * @param filename a String containing a filepath for a jpeg file with exif
- * tags to rewrite.
- * @param tags tags that will be written into the jpeg file over existing
- * tags if possible.
- * @return true if success, false if could not overwrite. If false, no
- * changes are made to the file.
- * @throws FileNotFoundException
- * @throws IOException
- */
- public boolean rewriteExif(String filename, Collection<ExifTag> tags)
- throws FileNotFoundException, IOException {
- RandomAccessFile file = null;
- InputStream is = null;
- boolean ret;
- try {
- File temp = new File(filename);
- is = new BufferedInputStream(new FileInputStream(temp));
-
- // Parse beginning of APP1 in exif to find size of exif header.
- ExifParser parser = null;
- try {
- parser = ExifParser.parse(is, this);
- } catch (ExifInvalidFormatException e) {
- throw new IOException("Invalid exif format : ", e);
- }
- long exifSize = parser.getOffsetToExifEndFromSOF();
-
- // Free up resources
- is.close();
- is = null;
-
- // Open file for memory mapping.
- file = new RandomAccessFile(temp, "rw");
- long fileLength = file.length();
- if (fileLength < exifSize) {
- throw new IOException("Filesize changed during operation");
- }
-
- // Map only exif header into memory.
- ByteBuffer buf = file.getChannel().map(MapMode.READ_WRITE, 0, exifSize);
-
- // Attempt to overwrite tag values without changing lengths (avoids
- // file copy).
- ret = rewriteExif(buf, tags);
- } catch (IOException e) {
- closeSilently(file);
- throw e;
- } finally {
- closeSilently(is);
- }
- file.close();
- return ret;
- }
-
- /**
- * Attempts to do an in-place rewrite the exif metadata in a ByteBuffer for
- * the given tags. If tags do not exist or do not have the same size as the
- * existing exif tags, this method will fail.
- *
- * @param buf a ByteBuffer containing a jpeg file with existing exif tags to
- * rewrite.
- * @param tags tags that will be written into the jpeg ByteBuffer over
- * existing tags if possible.
- * @return true if success, false if could not overwrite. If false, no
- * changes are made to the ByteBuffer.
- * @throws IOException
- */
- public boolean rewriteExif(ByteBuffer buf, Collection<ExifTag> tags) throws IOException {
- ExifModifier mod = null;
- try {
- mod = new ExifModifier(buf, this);
- for (ExifTag t : tags) {
- mod.modifyTag(t);
- }
- return mod.commit();
- } catch (ExifInvalidFormatException e) {
- throw new IOException("Invalid exif format : " + e);
- }
- }
-
- /**
- * Attempts to do an in-place rewrite of the exif metadata. If this fails,
- * fall back to overwriting file. This preserves tags that are not being
- * rewritten.
- *
- * @param filename a String containing a filepath for a jpeg file.
- * @param tags tags that will be written into the jpeg file over existing
- * tags if possible.
- * @throws FileNotFoundException
- * @throws IOException
- * @see #rewriteExif
- */
- public void forceRewriteExif(String filename, Collection<ExifTag> tags)
- throws FileNotFoundException,
- IOException {
- // Attempt in-place write
- if (!rewriteExif(filename, tags)) {
- // Fall back to doing a copy
- ExifData tempData = mData;
- mData = new ExifData(DEFAULT_BYTE_ORDER);
- FileInputStream is = null;
- ByteArrayOutputStream bytes = null;
- try {
- is = new FileInputStream(filename);
- bytes = new ByteArrayOutputStream();
- doExifStreamIO(is, bytes);
- byte[] imageBytes = bytes.toByteArray();
- readExif(imageBytes);
- setTags(tags);
- writeExif(imageBytes, filename);
- } catch (IOException e) {
- closeSilently(is);
- throw e;
- } finally {
- is.close();
- // Prevent clobbering of mData
- mData = tempData;
- }
- }
- }
-
- /**
- * Attempts to do an in-place rewrite of the exif metadata using the tags in
- * this ExifInterface object. If this fails, fall back to overwriting file.
- * This preserves tags that are not being rewritten.
- *
- * @param filename a String containing a filepath for a jpeg file.
- * @throws FileNotFoundException
- * @throws IOException
- * @see #rewriteExif
- */
- public void forceRewriteExif(String filename) throws FileNotFoundException, IOException {
- forceRewriteExif(filename, getAllTags());
- }
-
- /**
- * Get the exif tags in this ExifInterface object or null if none exist.
- *
- * @return a List of {@link ExifTag}s.
- */
- public List<ExifTag> getAllTags() {
- return mData.getAllTags();
- }
-
- /**
- * Returns a list of ExifTags that share a TID (which can be obtained by
- * calling {@link #getTrueTagKey} on a defined tag constant) or null if none
- * exist.
- *
- * @param tagId a TID as defined in the exif standard (or with
- * {@link #defineTag}).
- * @return a List of {@link ExifTag}s.
- */
- public List<ExifTag> getTagsForTagId(short tagId) {
- return mData.getAllTagsForTagId(tagId);
- }
-
- /**
- * Returns a list of ExifTags that share an IFD (which can be obtained by
- * calling {@link #getTrueIFD} on a defined tag constant) or null if none
- * exist.
- *
- * @param ifdId an IFD as defined in the exif standard (or with
- * {@link #defineTag}).
- * @return a List of {@link ExifTag}s.
- */
- public List<ExifTag> getTagsForIfdId(int ifdId) {
- return mData.getAllTagsForIfd(ifdId);
- }
-
- /**
- * Gets an ExifTag for an IFD other than the tag's default.
- *
- * @see #getTag
- */
- public ExifTag getTag(int tagId, int ifdId) {
- if (!ExifTag.isValidIfd(ifdId)) {
- return null;
- }
- return mData.getTag(getTrueTagKey(tagId), ifdId);
- }
-
- /**
- * Returns the ExifTag in that tag's default IFD for a defined tag constant
- * or null if none exists.
- *
- * @param tagId a defined tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
- * @return an {@link ExifTag} or null if none exists.
- */
- public ExifTag getTag(int tagId) {
- int ifdId = getDefinedTagDefaultIfd(tagId);
- return getTag(tagId, ifdId);
- }
-
- /**
- * Gets a tag value for an IFD other than the tag's default.
- *
- * @see #getTagValue
- */
- public Object getTagValue(int tagId, int ifdId) {
- ExifTag t = getTag(tagId, ifdId);
- return (t == null) ? null : t.getValue();
- }
-
- /**
- * Returns the value of the ExifTag in that tag's default IFD for a defined
- * tag constant or null if none exists or the value could not be cast into
- * the return type.
- *
- * @param tagId a defined tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
- * @return the value of the ExifTag or null if none exists.
- */
- public Object getTagValue(int tagId) {
- int ifdId = getDefinedTagDefaultIfd(tagId);
- return getTagValue(tagId, ifdId);
- }
-
- /*
- * Getter methods that are similar to getTagValue. Null is returned if the
- * tag value cannot be cast into the return type.
- */
-
- /**
- * @see #getTagValue
- */
- public String getTagStringValue(int tagId, int ifdId) {
- ExifTag t = getTag(tagId, ifdId);
- if (t == null) {
- return null;
- }
- return t.getValueAsString();
- }
-
- /**
- * @see #getTagValue
- */
- public String getTagStringValue(int tagId) {
- int ifdId = getDefinedTagDefaultIfd(tagId);
- return getTagStringValue(tagId, ifdId);
- }
-
- /**
- * @see #getTagValue
- */
- public Long getTagLongValue(int tagId, int ifdId) {
- long[] l = getTagLongValues(tagId, ifdId);
- if (l == null || l.length <= 0) {
- return null;
- }
- return Long.valueOf(l[0]);
- }
-
- /**
- * @see #getTagValue
- */
- public Long getTagLongValue(int tagId) {
- int ifdId = getDefinedTagDefaultIfd(tagId);
- return getTagLongValue(tagId, ifdId);
- }
-
- /**
- * @see #getTagValue
- */
- public Integer getTagIntValue(int tagId, int ifdId) {
- int[] l = getTagIntValues(tagId, ifdId);
- if (l == null || l.length <= 0) {
- return null;
- }
- return Integer.valueOf(l[0]);
- }
-
- /**
- * @see #getTagValue
- */
- public Integer getTagIntValue(int tagId) {
- int ifdId = getDefinedTagDefaultIfd(tagId);
- return getTagIntValue(tagId, ifdId);
- }
-
- /**
- * @see #getTagValue
- */
- public Byte getTagByteValue(int tagId, int ifdId) {
- byte[] l = getTagByteValues(tagId, ifdId);
- if (l == null || l.length <= 0) {
- return null;
- }
- return Byte.valueOf(l[0]);
- }
-
- /**
- * @see #getTagValue
- */
- public Byte getTagByteValue(int tagId) {
- int ifdId = getDefinedTagDefaultIfd(tagId);
- return getTagByteValue(tagId, ifdId);
- }
-
- /**
- * @see #getTagValue
- */
- public Rational getTagRationalValue(int tagId, int ifdId) {
- Rational[] l = getTagRationalValues(tagId, ifdId);
- if (l == null || l.length == 0) {
- return null;
- }
- return new Rational(l[0]);
- }
-
- /**
- * @see #getTagValue
- */
- public Rational getTagRationalValue(int tagId) {
- int ifdId = getDefinedTagDefaultIfd(tagId);
- return getTagRationalValue(tagId, ifdId);
- }
-
- /**
- * @see #getTagValue
- */
- public long[] getTagLongValues(int tagId, int ifdId) {
- ExifTag t = getTag(tagId, ifdId);
- if (t == null) {
- return null;
- }
- return t.getValueAsLongs();
- }
-
- /**
- * @see #getTagValue
- */
- public long[] getTagLongValues(int tagId) {
- int ifdId = getDefinedTagDefaultIfd(tagId);
- return getTagLongValues(tagId, ifdId);
- }
-
- /**
- * @see #getTagValue
- */
- public int[] getTagIntValues(int tagId, int ifdId) {
- ExifTag t = getTag(tagId, ifdId);
- if (t == null) {
- return null;
- }
- return t.getValueAsInts();
- }
-
- /**
- * @see #getTagValue
- */
- public int[] getTagIntValues(int tagId) {
- int ifdId = getDefinedTagDefaultIfd(tagId);
- return getTagIntValues(tagId, ifdId);
- }
-
- /**
- * @see #getTagValue
- */
- public byte[] getTagByteValues(int tagId, int ifdId) {
- ExifTag t = getTag(tagId, ifdId);
- if (t == null) {
- return null;
- }
- return t.getValueAsBytes();
- }
-
- /**
- * @see #getTagValue
- */
- public byte[] getTagByteValues(int tagId) {
- int ifdId = getDefinedTagDefaultIfd(tagId);
- return getTagByteValues(tagId, ifdId);
- }
-
- /**
- * @see #getTagValue
- */
- public Rational[] getTagRationalValues(int tagId, int ifdId) {
- ExifTag t = getTag(tagId, ifdId);
- if (t == null) {
- return null;
- }
- return t.getValueAsRationals();
- }
-
- /**
- * @see #getTagValue
- */
- public Rational[] getTagRationalValues(int tagId) {
- int ifdId = getDefinedTagDefaultIfd(tagId);
- return getTagRationalValues(tagId, ifdId);
- }
-
- /**
- * Checks whether a tag has a defined number of elements.
- *
- * @param tagId a defined tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
- * @return true if the tag has a defined number of elements.
- */
- public boolean isTagCountDefined(int tagId) {
- int info = getTagInfo().get(tagId);
- // No value in info can be zero, as all tags have a non-zero type
- if (info == 0) {
- return false;
- }
- return getComponentCountFromInfo(info) != ExifTag.SIZE_UNDEFINED;
- }
-
- /**
- * Gets the defined number of elements for a tag.
- *
- * @param tagId a defined tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
- * @return the number of elements or {@link ExifTag#SIZE_UNDEFINED} if the
- * tag or the number of elements is not defined.
- */
- public int getDefinedTagCount(int tagId) {
- int info = getTagInfo().get(tagId);
- if (info == 0) {
- return ExifTag.SIZE_UNDEFINED;
- }
- return getComponentCountFromInfo(info);
- }
-
- /**
- * Gets the number of elements for an ExifTag in a given IFD.
- *
- * @param tagId a defined tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
- * @param ifdId the IFD containing the ExifTag to check.
- * @return the number of elements in the ExifTag, if the tag's size is
- * undefined this will return the actual number of elements that is
- * in the ExifTag's value.
- */
- public int getActualTagCount(int tagId, int ifdId) {
- ExifTag t = getTag(tagId, ifdId);
- if (t == null) {
- return 0;
- }
- return t.getComponentCount();
- }
-
- /**
- * Gets the default IFD for a tag.
- *
- * @param tagId a defined tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
- * @return the default IFD for a tag definition or {@link #IFD_NULL} if no
- * definition exists.
- */
- public int getDefinedTagDefaultIfd(int tagId) {
- int info = getTagInfo().get(tagId);
- if (info == DEFINITION_NULL) {
- return IFD_NULL;
- }
- return getTrueIfd(tagId);
- }
-
- /**
- * Gets the defined type for a tag.
- *
- * @param tagId a defined tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
- * @return the type.
- * @see ExifTag#getDataType()
- */
- public short getDefinedTagType(int tagId) {
- int info = getTagInfo().get(tagId);
- if (info == 0) {
- return -1;
- }
- return getTypeFromInfo(info);
- }
-
- /**
- * Returns true if tag TID is one of the following: {@link TAG_EXIF_IFD},
- * {@link TAG_GPS_IFD}, {@link TAG_JPEG_INTERCHANGE_FORMAT},
- * {@link TAG_STRIP_OFFSETS}, {@link TAG_INTEROPERABILITY_IFD}
- * <p>
- * Note: defining tags with these TID's is disallowed.
- *
- * @param tag a tag's TID (can be obtained from a defined tag constant with
- * {@link #getTrueTagKey}).
- * @return true if the TID is that of an offset tag.
- */
- protected static boolean isOffsetTag(short tag) {
- return sOffsetTags.contains(tag);
- }
-
- /**
- * Creates a tag for a defined tag constant in a given IFD if that IFD is
- * allowed for the tag. This method will fail anytime the appropriate
- * {@link ExifTag#setValue} for this tag's datatype would fail.
- *
- * @param tagId a tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
- * @param ifdId the IFD that the tag should be in.
- * @param val the value of the tag to set.
- * @return an ExifTag object or null if one could not be constructed.
- * @see #buildTag
- */
- public ExifTag buildTag(int tagId, int ifdId, Object val) {
- int info = getTagInfo().get(tagId);
- if (info == 0 || val == null) {
- return null;
- }
- short type = getTypeFromInfo(info);
- int definedCount = getComponentCountFromInfo(info);
- boolean hasDefinedCount = (definedCount != ExifTag.SIZE_UNDEFINED);
- if (!ExifInterface.isIfdAllowed(info, ifdId)) {
- return null;
- }
- ExifTag t = new ExifTag(getTrueTagKey(tagId), type, definedCount, ifdId, hasDefinedCount);
- if (!t.setValue(val)) {
- return null;
- }
- return t;
- }
-
- /**
- * Creates a tag for a defined tag constant in the tag's default IFD.
- *
- * @param tagId a tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
- * @param val the tag's value.
- * @return an ExifTag object.
- */
- public ExifTag buildTag(int tagId, Object val) {
- int ifdId = getTrueIfd(tagId);
- return buildTag(tagId, ifdId, val);
- }
-
- protected ExifTag buildUninitializedTag(int tagId) {
- int info = getTagInfo().get(tagId);
- if (info == 0) {
- return null;
- }
- short type = getTypeFromInfo(info);
- int definedCount = getComponentCountFromInfo(info);
- boolean hasDefinedCount = (definedCount != ExifTag.SIZE_UNDEFINED);
- int ifdId = getTrueIfd(tagId);
- ExifTag t = new ExifTag(getTrueTagKey(tagId), type, definedCount, ifdId, hasDefinedCount);
- return t;
- }
-
- /**
- * Sets the value of an ExifTag if it exists in the given IFD. The value
- * must be the correct type and length for that ExifTag.
- *
- * @param tagId a tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
- * @param ifdId the IFD that the ExifTag is in.
- * @param val the value to set.
- * @return true if success, false if the ExifTag doesn't exist or the value
- * is the wrong type/length.
- * @see #setTagValue
- */
- public boolean setTagValue(int tagId, int ifdId, Object val) {
- ExifTag t = getTag(tagId, ifdId);
- if (t == null) {
- return false;
- }
- return t.setValue(val);
- }
-
- /**
- * Sets the value of an ExifTag if it exists it's default IFD. The value
- * must be the correct type and length for that ExifTag.
- *
- * @param tagId a tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
- * @param val the value to set.
- * @return true if success, false if the ExifTag doesn't exist or the value
- * is the wrong type/length.
- */
- public boolean setTagValue(int tagId, Object val) {
- int ifdId = getDefinedTagDefaultIfd(tagId);
- return setTagValue(tagId, ifdId, val);
- }
-
- /**
- * Puts an ExifTag into this ExifInterface object's tags, removing a
- * previous ExifTag with the same TID and IFD. The IFD it is put into will
- * be the one the tag was created with in {@link #buildTag}.
- *
- * @param tag an ExifTag to put into this ExifInterface's tags.
- * @return the previous ExifTag with the same TID and IFD or null if none
- * exists.
- */
- public ExifTag setTag(ExifTag tag) {
- return mData.addTag(tag);
- }
-
- /**
- * Puts a collection of ExifTags into this ExifInterface objects's tags. Any
- * previous ExifTags with the same TID and IFDs will be removed.
- *
- * @param tags a Collection of ExifTags.
- * @see #setTag
- */
- public void setTags(Collection<ExifTag> tags) {
- for (ExifTag t : tags) {
- setTag(t);
- }
- }
-
- /**
- * Removes the ExifTag for a tag constant from the given IFD.
- *
- * @param tagId a tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
- * @param ifdId the IFD of the ExifTag to remove.
- */
- public void deleteTag(int tagId, int ifdId) {
- mData.removeTag(getTrueTagKey(tagId), ifdId);
- }
-
- /**
- * Removes the ExifTag for a tag constant from that tag's default IFD.
- *
- * @param tagId a tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
- */
- public void deleteTag(int tagId) {
- int ifdId = getDefinedTagDefaultIfd(tagId);
- deleteTag(tagId, ifdId);
- }
-
- /**
- * Creates a new tag definition in this ExifInterface object for a given TID
- * and default IFD. Creating a definition with the same TID and default IFD
- * as a previous definition will override it.
- *
- * @param tagId the TID for the tag.
- * @param defaultIfd the default IFD for the tag.
- * @param tagType the type of the tag (see {@link ExifTag#getDataType()}).
- * @param defaultComponentCount the number of elements of this tag's type in
- * the tags value.
- * @param allowedIfds the IFD's this tag is allowed to be put in.
- * @return the defined tag constant (e.g. {@link #TAG_IMAGE_WIDTH}) or
- * {@link #TAG_NULL} if the definition could not be made.
- */
- public int setTagDefinition(short tagId, int defaultIfd, short tagType,
- short defaultComponentCount, int[] allowedIfds) {
- if (sBannedDefines.contains(tagId)) {
- return TAG_NULL;
- }
- if (ExifTag.isValidType(tagType) && ExifTag.isValidIfd(defaultIfd)) {
- int tagDef = defineTag(defaultIfd, tagId);
- if (tagDef == TAG_NULL) {
- return TAG_NULL;
- }
- int[] otherDefs = getTagDefinitionsForTagId(tagId);
- SparseIntArray infos = getTagInfo();
- // Make sure defaultIfd is in allowedIfds
- boolean defaultCheck = false;
- for (int i : allowedIfds) {
- if (defaultIfd == i) {
- defaultCheck = true;
- }
- if (!ExifTag.isValidIfd(i)) {
- return TAG_NULL;
- }
- }
- if (!defaultCheck) {
- return TAG_NULL;
- }
-
- int ifdFlags = getFlagsFromAllowedIfds(allowedIfds);
- // Make sure no identical tags can exist in allowedIfds
- if (otherDefs != null) {
- for (int def : otherDefs) {
- int tagInfo = infos.get(def);
- int allowedFlags = getAllowedIfdFlagsFromInfo(tagInfo);
- if ((ifdFlags & allowedFlags) != 0) {
- return TAG_NULL;
- }
- }
- }
- getTagInfo().put(tagDef, ifdFlags << 24 | (tagType << 16) | defaultComponentCount);
- return tagDef;
- }
- return TAG_NULL;
- }
-
- protected int getTagDefinition(short tagId, int defaultIfd) {
- return getTagInfo().get(defineTag(defaultIfd, tagId));
- }
-
- protected int[] getTagDefinitionsForTagId(short tagId) {
- int[] ifds = IfdData.getIfds();
- int[] defs = new int[ifds.length];
- int counter = 0;
- SparseIntArray infos = getTagInfo();
- for (int i : ifds) {
- int def = defineTag(i, tagId);
- if (infos.get(def) != DEFINITION_NULL) {
- defs[counter++] = def;
- }
- }
- if (counter == 0) {
- return null;
- }
-
- return Arrays.copyOfRange(defs, 0, counter);
- }
-
- protected int getTagDefinitionForTag(ExifTag tag) {
- short type = tag.getDataType();
- int count = tag.getComponentCount();
- int ifd = tag.getIfd();
- return getTagDefinitionForTag(tag.getTagId(), type, count, ifd);
- }
-
- protected int getTagDefinitionForTag(short tagId, short type, int count, int ifd) {
- int[] defs = getTagDefinitionsForTagId(tagId);
- if (defs == null) {
- return TAG_NULL;
- }
- SparseIntArray infos = getTagInfo();
- int ret = TAG_NULL;
- for (int i : defs) {
- int info = infos.get(i);
- short def_type = getTypeFromInfo(info);
- int def_count = getComponentCountFromInfo(info);
- int[] def_ifds = getAllowedIfdsFromInfo(info);
- boolean valid_ifd = false;
- for (int j : def_ifds) {
- if (j == ifd) {
- valid_ifd = true;
- break;
- }
- }
- if (valid_ifd && type == def_type
- && (count == def_count || def_count == ExifTag.SIZE_UNDEFINED)) {
- ret = i;
- break;
- }
- }
- return ret;
- }
-
- /**
- * Removes a tag definition for given defined tag constant.
- *
- * @param tagId a defined tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
- */
- public void removeTagDefinition(int tagId) {
- getTagInfo().delete(tagId);
- }
-
- /**
- * Resets tag definitions to the default ones.
- */
- public void resetTagDefinitions() {
- mTagInfo = null;
- }
-
- /**
- * Returns the thumbnail from IFD1 as a bitmap, or null if none exists.
- *
- * @return the thumbnail as a bitmap.
- */
- public Bitmap getThumbnailBitmap() {
- if (mData.hasCompressedThumbnail()) {
- byte[] thumb = mData.getCompressedThumbnail();
- return BitmapFactory.decodeByteArray(thumb, 0, thumb.length);
- } else if (mData.hasUncompressedStrip()) {
- // TODO: implement uncompressed
- }
- return null;
- }
-
- /**
- * Returns the thumbnail from IFD1 as a byte array, or null if none exists.
- * The bytes may either be an uncompressed strip as specified in the exif
- * standard or a jpeg compressed image.
- *
- * @return the thumbnail as a byte array.
- */
- public byte[] getThumbnailBytes() {
- if (mData.hasCompressedThumbnail()) {
- return mData.getCompressedThumbnail();
- } else if (mData.hasUncompressedStrip()) {
- // TODO: implement this
- }
- return null;
- }
-
- /**
- * Returns the thumbnail if it is jpeg compressed, or null if none exists.
- *
- * @return the thumbnail as a byte array.
- */
- public byte[] getThumbnail() {
- return mData.getCompressedThumbnail();
- }
-
- /**
- * Check if thumbnail is compressed.
- *
- * @return true if the thumbnail is compressed.
- */
- public boolean isThumbnailCompressed() {
- return mData.hasCompressedThumbnail();
- }
-
- /**
- * Check if thumbnail exists.
- *
- * @return true if a compressed thumbnail exists.
- */
- public boolean hasThumbnail() {
- // TODO: add back in uncompressed strip
- return mData.hasCompressedThumbnail();
- }
-
- // TODO: uncompressed thumbnail setters
-
- /**
- * Sets the thumbnail to be a jpeg compressed image. Clears any prior
- * thumbnail.
- *
- * @param thumb a byte array containing a jpeg compressed image.
- * @return true if the thumbnail was set.
- */
- public boolean setCompressedThumbnail(byte[] thumb) {
- mData.clearThumbnailAndStrips();
- mData.setCompressedThumbnail(thumb);
- return true;
- }
-
- /**
- * Sets the thumbnail to be a jpeg compressed bitmap. Clears any prior
- * thumbnail.
- *
- * @param thumb a bitmap to compress to a jpeg thumbnail.
- * @return true if the thumbnail was set.
- */
- public boolean setCompressedThumbnail(Bitmap thumb) {
- ByteArrayOutputStream thumbnail = new ByteArrayOutputStream();
- if (!thumb.compress(Bitmap.CompressFormat.JPEG, 90, thumbnail)) {
- return false;
- }
- return setCompressedThumbnail(thumbnail.toByteArray());
- }
-
- /**
- * Clears the compressed thumbnail if it exists.
- */
- public void removeCompressedThumbnail() {
- mData.setCompressedThumbnail(null);
- }
-
- // Convenience methods:
-
- /**
- * Decodes the user comment tag into string as specified in the EXIF
- * standard. Returns null if decoding failed.
- */
- public String getUserComment() {
- return mData.getUserComment();
- }
-
- /**
- * Returns the Orientation ExifTag value for a given number of degrees.
- *
- * @param degrees the amount an image is rotated in degrees.
- */
- public static short getOrientationValueForRotation(int degrees) {
- degrees %= 360;
- if (degrees < 0) {
- degrees += 360;
- }
- if (degrees < 90) {
- return Orientation.TOP_LEFT; // 0 degrees
- } else if (degrees < 180) {
- return Orientation.RIGHT_TOP; // 90 degrees cw
- } else if (degrees < 270) {
- return Orientation.BOTTOM_LEFT; // 180 degrees
- } else {
- return Orientation.RIGHT_BOTTOM; // 270 degrees cw
- }
- }
-
- /**
- * Returns the rotation degrees corresponding to an ExifTag Orientation
- * value.
- *
- * @param orientation the ExifTag Orientation value.
- */
- public static int getRotationForOrientationValue(short orientation) {
- switch (orientation) {
- case Orientation.TOP_LEFT:
- return 0;
- case Orientation.RIGHT_TOP:
- return 90;
- case Orientation.BOTTOM_LEFT:
- return 180;
- case Orientation.RIGHT_BOTTOM:
- return 270;
- default:
- return 0;
- }
- }
-
- /**
- * Gets the double representation of the GPS latitude or longitude
- * coordinate.
- *
- * @param coordinate an array of 3 Rationals representing the degrees,
- * minutes, and seconds of the GPS location as defined in the
- * exif specification.
- * @param reference a GPS reference reperesented by a String containing "N",
- * "S", "E", or "W".
- * @return the GPS coordinate represented as degrees + minutes/60 +
- * seconds/3600
- */
- public static double convertLatOrLongToDouble(Rational[] coordinate, String reference) {
- try {
- double degrees = coordinate[0].toDouble();
- double minutes = coordinate[1].toDouble();
- double seconds = coordinate[2].toDouble();
- double result = degrees + minutes / 60.0 + seconds / 3600.0;
- if ((reference.equals("S") || reference.equals("W"))) {
- return -result;
- }
- return result;
- } catch (ArrayIndexOutOfBoundsException e) {
- throw new IllegalArgumentException();
- }
- }
-
- /**
- * Gets the GPS latitude and longitude as a pair of doubles from this
- * ExifInterface object's tags, or null if the necessary tags do not exist.
- *
- * @return an array of 2 doubles containing the latitude, and longitude
- * respectively.
- * @see #convertLatOrLongToDouble
- */
- public double[] getLatLongAsDoubles() {
- Rational[] latitude = getTagRationalValues(TAG_GPS_LATITUDE);
- String latitudeRef = getTagStringValue(TAG_GPS_LATITUDE_REF);
- Rational[] longitude = getTagRationalValues(TAG_GPS_LONGITUDE);
- String longitudeRef = getTagStringValue(TAG_GPS_LONGITUDE_REF);
- if (latitude == null || longitude == null || latitudeRef == null || longitudeRef == null
- || latitude.length < 3 || longitude.length < 3) {
- return null;
- }
- double[] latLon = new double[2];
- latLon[0] = convertLatOrLongToDouble(latitude, latitudeRef);
- latLon[1] = convertLatOrLongToDouble(longitude, longitudeRef);
- return latLon;
- }
-
- private static final String GPS_DATE_FORMAT_STR = "yyyy:MM:dd";
- private static final String DATETIME_FORMAT_STR = "yyyy:MM:dd kk:mm:ss";
- private final DateFormat mDateTimeStampFormat = new SimpleDateFormat(DATETIME_FORMAT_STR);
- private final DateFormat mGPSDateStampFormat = new SimpleDateFormat(GPS_DATE_FORMAT_STR);
- private final Calendar mGPSTimeStampCalendar = Calendar
- .getInstance(TimeZone.getTimeZone("UTC"));
-
- /**
- * Creates, formats, and sets the DateTimeStamp tag for one of:
- * {@link #TAG_DATE_TIME}, {@link #TAG_DATE_TIME_DIGITIZED},
- * {@link #TAG_DATE_TIME_ORIGINAL}.
- *
- * @param tagId one of the DateTimeStamp tags.
- * @param timestamp a timestamp to format.
- * @param timezone a TimeZone object.
- * @return true if success, false if the tag could not be set.
- */
- public boolean addDateTimeStampTag(int tagId, long timestamp, TimeZone timezone) {
- if (tagId == TAG_DATE_TIME || tagId == TAG_DATE_TIME_DIGITIZED
- || tagId == TAG_DATE_TIME_ORIGINAL) {
- mDateTimeStampFormat.setTimeZone(timezone);
- ExifTag t = buildTag(tagId, mDateTimeStampFormat.format(timestamp));
- if (t == null) {
- return false;
- }
- setTag(t);
- } else {
- return false;
- }
- return true;
- }
-
- /**
- * Creates and sets all to the GPS tags for a give latitude and longitude.
- *
- * @param latitude a GPS latitude coordinate.
- * @param longitude a GPS longitude coordinate.
- * @return true if success, false if they could not be created or set.
- */
- public boolean addGpsTags(double latitude, double longitude) {
- ExifTag latTag = buildTag(TAG_GPS_LATITUDE, toExifLatLong(latitude));
- ExifTag longTag = buildTag(TAG_GPS_LONGITUDE, toExifLatLong(longitude));
- ExifTag latRefTag = buildTag(TAG_GPS_LATITUDE_REF,
- latitude >= 0 ? ExifInterface.GpsLatitudeRef.NORTH
- : ExifInterface.GpsLatitudeRef.SOUTH);
- ExifTag longRefTag = buildTag(TAG_GPS_LONGITUDE_REF,
- longitude >= 0 ? ExifInterface.GpsLongitudeRef.EAST
- : ExifInterface.GpsLongitudeRef.WEST);
- if (latTag == null || longTag == null || latRefTag == null || longRefTag == null) {
- return false;
- }
- setTag(latTag);
- setTag(longTag);
- setTag(latRefTag);
- setTag(longRefTag);
- return true;
- }
-
- /**
- * Creates and sets the GPS timestamp tag.
- *
- * @param timestamp a GPS timestamp.
- * @return true if success, false if could not be created or set.
- */
- public boolean addGpsDateTimeStampTag(long timestamp) {
- ExifTag t = buildTag(TAG_GPS_DATE_STAMP, mGPSDateStampFormat.format(timestamp));
- if (t == null) {
- return false;
- }
- setTag(t);
- mGPSTimeStampCalendar.setTimeInMillis(timestamp);
- t = buildTag(TAG_GPS_TIME_STAMP, new Rational[] {
- new Rational(mGPSTimeStampCalendar.get(Calendar.HOUR_OF_DAY), 1),
- new Rational(mGPSTimeStampCalendar.get(Calendar.MINUTE), 1),
- new Rational(mGPSTimeStampCalendar.get(Calendar.SECOND), 1)
- });
- if (t == null) {
- return false;
- }
- setTag(t);
- return true;
- }
-
- private static Rational[] toExifLatLong(double value) {
- // convert to the format dd/1 mm/1 ssss/100
- value = Math.abs(value);
- int degrees = (int) value;
- value = (value - degrees) * 60;
- int minutes = (int) value;
- value = (value - minutes) * 6000;
- int seconds = (int) value;
- return new Rational[] {
- new Rational(degrees, 1), new Rational(minutes, 1), new Rational(seconds, 100)
- };
- }
-
- private void doExifStreamIO(InputStream is, OutputStream os) throws IOException {
- byte[] buf = new byte[1024];
- int ret = is.read(buf, 0, 1024);
- while (ret != -1) {
- os.write(buf, 0, ret);
- ret = is.read(buf, 0, 1024);
- }
- }
-
- protected static void closeSilently(Closeable c) {
- if (c != null) {
- try {
- c.close();
- } catch (Throwable e) {
- // ignored
- }
- }
- }
-
- private SparseIntArray mTagInfo = null;
-
- protected SparseIntArray getTagInfo() {
- if (mTagInfo == null) {
- mTagInfo = new SparseIntArray();
- initTagInfo();
- }
- return mTagInfo;
- }
-
- private void initTagInfo() {
- /**
- * We put tag information in a 4-bytes integer. The first byte a bitmask
- * representing the allowed IFDs of the tag, the second byte is the data
- * type, and the last two byte are a short value indicating the default
- * component count of this tag.
- */
- // IFD0 tags
- int[] ifdAllowedIfds = {
- IfdId.TYPE_IFD_0, IfdId.TYPE_IFD_1
- };
- int ifdFlags = getFlagsFromAllowedIfds(ifdAllowedIfds) << 24;
- mTagInfo.put(ExifInterface.TAG_MAKE,
- ifdFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
- mTagInfo.put(ExifInterface.TAG_IMAGE_WIDTH,
- ifdFlags | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_IMAGE_LENGTH,
- ifdFlags | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_BITS_PER_SAMPLE,
- ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 3);
- mTagInfo.put(ExifInterface.TAG_COMPRESSION,
- ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_PHOTOMETRIC_INTERPRETATION,
- ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_ORIENTATION, ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16
- | 1);
- mTagInfo.put(ExifInterface.TAG_SAMPLES_PER_PIXEL,
- ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_PLANAR_CONFIGURATION,
- ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_Y_CB_CR_SUB_SAMPLING,
- ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 2);
- mTagInfo.put(ExifInterface.TAG_Y_CB_CR_POSITIONING,
- ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_X_RESOLUTION,
- ifdFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_Y_RESOLUTION,
- ifdFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_RESOLUTION_UNIT,
- ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_STRIP_OFFSETS,
- ifdFlags | ExifTag.TYPE_UNSIGNED_LONG << 16 | ExifTag.SIZE_UNDEFINED);
- mTagInfo.put(ExifInterface.TAG_ROWS_PER_STRIP,
- ifdFlags | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_STRIP_BYTE_COUNTS,
- ifdFlags | ExifTag.TYPE_UNSIGNED_LONG << 16 | ExifTag.SIZE_UNDEFINED);
- mTagInfo.put(ExifInterface.TAG_TRANSFER_FUNCTION,
- ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 3 * 256);
- mTagInfo.put(ExifInterface.TAG_WHITE_POINT,
- ifdFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 2);
- mTagInfo.put(ExifInterface.TAG_PRIMARY_CHROMATICITIES,
- ifdFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 6);
- mTagInfo.put(ExifInterface.TAG_Y_CB_CR_COEFFICIENTS,
- ifdFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 3);
- mTagInfo.put(ExifInterface.TAG_REFERENCE_BLACK_WHITE,
- ifdFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 6);
- mTagInfo.put(ExifInterface.TAG_DATE_TIME,
- ifdFlags | ExifTag.TYPE_ASCII << 16 | 20);
- mTagInfo.put(ExifInterface.TAG_IMAGE_DESCRIPTION,
- ifdFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
- mTagInfo.put(ExifInterface.TAG_MAKE,
- ifdFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
- mTagInfo.put(ExifInterface.TAG_MODEL,
- ifdFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
- mTagInfo.put(ExifInterface.TAG_SOFTWARE,
- ifdFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
- mTagInfo.put(ExifInterface.TAG_ARTIST,
- ifdFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
- mTagInfo.put(ExifInterface.TAG_COPYRIGHT,
- ifdFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
- mTagInfo.put(ExifInterface.TAG_EXIF_IFD,
- ifdFlags | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_GPS_IFD,
- ifdFlags | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
- // IFD1 tags
- int[] ifd1AllowedIfds = {
- IfdId.TYPE_IFD_1
- };
- int ifdFlags1 = getFlagsFromAllowedIfds(ifd1AllowedIfds) << 24;
- mTagInfo.put(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT,
- ifdFlags1 | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH,
- ifdFlags1 | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
- // Exif tags
- int[] exifAllowedIfds = {
- IfdId.TYPE_IFD_EXIF
- };
- int exifFlags = getFlagsFromAllowedIfds(exifAllowedIfds) << 24;
- mTagInfo.put(ExifInterface.TAG_EXIF_VERSION,
- exifFlags | ExifTag.TYPE_UNDEFINED << 16 | 4);
- mTagInfo.put(ExifInterface.TAG_FLASHPIX_VERSION,
- exifFlags | ExifTag.TYPE_UNDEFINED << 16 | 4);
- mTagInfo.put(ExifInterface.TAG_COLOR_SPACE,
- exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_COMPONENTS_CONFIGURATION,
- exifFlags | ExifTag.TYPE_UNDEFINED << 16 | 4);
- mTagInfo.put(ExifInterface.TAG_COMPRESSED_BITS_PER_PIXEL,
- exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_PIXEL_X_DIMENSION,
- exifFlags | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_PIXEL_Y_DIMENSION,
- exifFlags | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_MAKER_NOTE,
- exifFlags | ExifTag.TYPE_UNDEFINED << 16 | ExifTag.SIZE_UNDEFINED);
- mTagInfo.put(ExifInterface.TAG_USER_COMMENT,
- exifFlags | ExifTag.TYPE_UNDEFINED << 16 | ExifTag.SIZE_UNDEFINED);
- mTagInfo.put(ExifInterface.TAG_RELATED_SOUND_FILE,
- exifFlags | ExifTag.TYPE_ASCII << 16 | 13);
- mTagInfo.put(ExifInterface.TAG_DATE_TIME_ORIGINAL,
- exifFlags | ExifTag.TYPE_ASCII << 16 | 20);
- mTagInfo.put(ExifInterface.TAG_DATE_TIME_DIGITIZED,
- exifFlags | ExifTag.TYPE_ASCII << 16 | 20);
- mTagInfo.put(ExifInterface.TAG_SUB_SEC_TIME,
- exifFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
- mTagInfo.put(ExifInterface.TAG_SUB_SEC_TIME_ORIGINAL,
- exifFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
- mTagInfo.put(ExifInterface.TAG_SUB_SEC_TIME_DIGITIZED,
- exifFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
- mTagInfo.put(ExifInterface.TAG_IMAGE_UNIQUE_ID,
- exifFlags | ExifTag.TYPE_ASCII << 16 | 33);
- mTagInfo.put(ExifInterface.TAG_EXPOSURE_TIME,
- exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_F_NUMBER,
- exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_EXPOSURE_PROGRAM,
- exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_SPECTRAL_SENSITIVITY,
- exifFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
- mTagInfo.put(ExifInterface.TAG_ISO_SPEED_RATINGS,
- exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | ExifTag.SIZE_UNDEFINED);
- mTagInfo.put(ExifInterface.TAG_OECF,
- exifFlags | ExifTag.TYPE_UNDEFINED << 16 | ExifTag.SIZE_UNDEFINED);
- mTagInfo.put(ExifInterface.TAG_SHUTTER_SPEED_VALUE,
- exifFlags | ExifTag.TYPE_RATIONAL << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_APERTURE_VALUE,
- exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_BRIGHTNESS_VALUE,
- exifFlags | ExifTag.TYPE_RATIONAL << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_EXPOSURE_BIAS_VALUE,
- exifFlags | ExifTag.TYPE_RATIONAL << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_MAX_APERTURE_VALUE,
- exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_SUBJECT_DISTANCE,
- exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_METERING_MODE,
- exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_LIGHT_SOURCE,
- exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_FLASH,
- exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_FOCAL_LENGTH,
- exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_SUBJECT_AREA,
- exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | ExifTag.SIZE_UNDEFINED);
- mTagInfo.put(ExifInterface.TAG_FLASH_ENERGY,
- exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_SPATIAL_FREQUENCY_RESPONSE,
- exifFlags | ExifTag.TYPE_UNDEFINED << 16 | ExifTag.SIZE_UNDEFINED);
- mTagInfo.put(ExifInterface.TAG_FOCAL_PLANE_X_RESOLUTION,
- exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_FOCAL_PLANE_Y_RESOLUTION,
- exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_FOCAL_PLANE_RESOLUTION_UNIT,
- exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_SUBJECT_LOCATION,
- exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 2);
- mTagInfo.put(ExifInterface.TAG_EXPOSURE_INDEX,
- exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_SENSING_METHOD,
- exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_FILE_SOURCE,
- exifFlags | ExifTag.TYPE_UNDEFINED << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_SCENE_TYPE,
- exifFlags | ExifTag.TYPE_UNDEFINED << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_CFA_PATTERN,
- exifFlags | ExifTag.TYPE_UNDEFINED << 16 | ExifTag.SIZE_UNDEFINED);
- mTagInfo.put(ExifInterface.TAG_CUSTOM_RENDERED,
- exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_EXPOSURE_MODE,
- exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_WHITE_BALANCE,
- exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_DIGITAL_ZOOM_RATIO,
- exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_FOCAL_LENGTH_IN_35_MM_FILE,
- exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_SCENE_CAPTURE_TYPE,
- exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_GAIN_CONTROL,
- exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_CONTRAST,
- exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_SATURATION,
- exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_SHARPNESS,
- exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_DEVICE_SETTING_DESCRIPTION,
- exifFlags | ExifTag.TYPE_UNDEFINED << 16 | ExifTag.SIZE_UNDEFINED);
- mTagInfo.put(ExifInterface.TAG_SUBJECT_DISTANCE_RANGE,
- exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_INTEROPERABILITY_IFD, exifFlags
- | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
- // GPS tag
- int[] gpsAllowedIfds = {
- IfdId.TYPE_IFD_GPS
- };
- int gpsFlags = getFlagsFromAllowedIfds(gpsAllowedIfds) << 24;
- mTagInfo.put(ExifInterface.TAG_GPS_VERSION_ID,
- gpsFlags | ExifTag.TYPE_UNSIGNED_BYTE << 16 | 4);
- mTagInfo.put(ExifInterface.TAG_GPS_LATITUDE_REF,
- gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
- mTagInfo.put(ExifInterface.TAG_GPS_LONGITUDE_REF,
- gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
- mTagInfo.put(ExifInterface.TAG_GPS_LATITUDE,
- gpsFlags | ExifTag.TYPE_RATIONAL << 16 | 3);
- mTagInfo.put(ExifInterface.TAG_GPS_LONGITUDE,
- gpsFlags | ExifTag.TYPE_RATIONAL << 16 | 3);
- mTagInfo.put(ExifInterface.TAG_GPS_ALTITUDE_REF,
- gpsFlags | ExifTag.TYPE_UNSIGNED_BYTE << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_GPS_ALTITUDE,
- gpsFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_GPS_TIME_STAMP,
- gpsFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 3);
- mTagInfo.put(ExifInterface.TAG_GPS_SATTELLITES,
- gpsFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
- mTagInfo.put(ExifInterface.TAG_GPS_STATUS,
- gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
- mTagInfo.put(ExifInterface.TAG_GPS_MEASURE_MODE,
- gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
- mTagInfo.put(ExifInterface.TAG_GPS_DOP,
- gpsFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_GPS_SPEED_REF,
- gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
- mTagInfo.put(ExifInterface.TAG_GPS_SPEED,
- gpsFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_GPS_TRACK_REF,
- gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
- mTagInfo.put(ExifInterface.TAG_GPS_TRACK,
- gpsFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_GPS_IMG_DIRECTION_REF,
- gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
- mTagInfo.put(ExifInterface.TAG_GPS_IMG_DIRECTION,
- gpsFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_GPS_MAP_DATUM,
- gpsFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
- mTagInfo.put(ExifInterface.TAG_GPS_DEST_LATITUDE_REF,
- gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
- mTagInfo.put(ExifInterface.TAG_GPS_DEST_LATITUDE,
- gpsFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_GPS_DEST_BEARING_REF,
- gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
- mTagInfo.put(ExifInterface.TAG_GPS_DEST_BEARING,
- gpsFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_GPS_DEST_DISTANCE_REF,
- gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
- mTagInfo.put(ExifInterface.TAG_GPS_DEST_DISTANCE,
- gpsFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
- mTagInfo.put(ExifInterface.TAG_GPS_PROCESSING_METHOD,
- gpsFlags | ExifTag.TYPE_UNDEFINED << 16 | ExifTag.SIZE_UNDEFINED);
- mTagInfo.put(ExifInterface.TAG_GPS_AREA_INFORMATION,
- gpsFlags | ExifTag.TYPE_UNDEFINED << 16 | ExifTag.SIZE_UNDEFINED);
- mTagInfo.put(ExifInterface.TAG_GPS_DATE_STAMP,
- gpsFlags | ExifTag.TYPE_ASCII << 16 | 11);
- mTagInfo.put(ExifInterface.TAG_GPS_DIFFERENTIAL,
- gpsFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 11);
- // Interoperability tag
- int[] interopAllowedIfds = {
- IfdId.TYPE_IFD_INTEROPERABILITY
- };
- int interopFlags = getFlagsFromAllowedIfds(interopAllowedIfds) << 24;
- mTagInfo.put(TAG_INTEROPERABILITY_INDEX, interopFlags | ExifTag.TYPE_ASCII << 16
- | ExifTag.SIZE_UNDEFINED);
- }
-
- protected static int getAllowedIfdFlagsFromInfo(int info) {
- return info >>> 24;
- }
-
- protected static int[] getAllowedIfdsFromInfo(int info) {
- int ifdFlags = getAllowedIfdFlagsFromInfo(info);
- int[] ifds = IfdData.getIfds();
- ArrayList<Integer> l = new ArrayList<Integer>();
- for (int i = 0; i < IfdId.TYPE_IFD_COUNT; i++) {
- int flag = (ifdFlags >> i) & 1;
- if (flag == 1) {
- l.add(ifds[i]);
- }
- }
- if (l.size() <= 0) {
- return null;
- }
- int[] ret = new int[l.size()];
- int j = 0;
- for (int i : l) {
- ret[j++] = i;
- }
- return ret;
- }
-
- protected static boolean isIfdAllowed(int info, int ifd) {
- int[] ifds = IfdData.getIfds();
- int ifdFlags = getAllowedIfdFlagsFromInfo(info);
- for (int i = 0; i < ifds.length; i++) {
- if (ifd == ifds[i] && ((ifdFlags >> i) & 1) == 1) {
- return true;
- }
- }
- return false;
- }
-
- protected static int getFlagsFromAllowedIfds(int[] allowedIfds) {
- if (allowedIfds == null || allowedIfds.length == 0) {
- return 0;
- }
- int flags = 0;
- int[] ifds = IfdData.getIfds();
- for (int i = 0; i < IfdId.TYPE_IFD_COUNT; i++) {
- for (int j : allowedIfds) {
- if (ifds[i] == j) {
- flags |= 1 << i;
- break;
- }
- }
- }
- return flags;
- }
-
- protected static short getTypeFromInfo(int info) {
- return (short) ((info >> 16) & 0x0ff);
- }
-
- protected static int getComponentCountFromInfo(int info) {
- return info & 0x0ffff;
- }
-
-}
diff --git a/WallpaperPicker/src/com/android/gallery3d/exif/ExifInvalidFormatException.java b/WallpaperPicker/src/com/android/gallery3d/exif/ExifInvalidFormatException.java
deleted file mode 100644
index bf923ec26..000000000
--- a/WallpaperPicker/src/com/android/gallery3d/exif/ExifInvalidFormatException.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2012 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.exif;
-
-public class ExifInvalidFormatException extends Exception {
- public ExifInvalidFormatException(String meg) {
- super(meg);
- }
-} \ No newline at end of file
diff --git a/WallpaperPicker/src/com/android/gallery3d/exif/ExifModifier.java b/WallpaperPicker/src/com/android/gallery3d/exif/ExifModifier.java
deleted file mode 100644
index 0531cbad9..000000000
--- a/WallpaperPicker/src/com/android/gallery3d/exif/ExifModifier.java
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * Copyright (C) 2012 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.exif;
-
-import android.util.Log;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.util.ArrayList;
-import java.util.List;
-
-class ExifModifier {
- public static final String TAG = "ExifModifier";
- public static final boolean DEBUG = false;
- private final ByteBuffer mByteBuffer;
- private final ExifData mTagToModified;
- private final List<TagOffset> mTagOffsets = new ArrayList<TagOffset>();
- private final ExifInterface mInterface;
- private int mOffsetBase;
-
- private static class TagOffset {
- final int mOffset;
- final ExifTag mTag;
-
- TagOffset(ExifTag tag, int offset) {
- mTag = tag;
- mOffset = offset;
- }
- }
-
- protected ExifModifier(ByteBuffer byteBuffer, ExifInterface iRef) throws IOException,
- ExifInvalidFormatException {
- mByteBuffer = byteBuffer;
- mOffsetBase = byteBuffer.position();
- mInterface = iRef;
- InputStream is = null;
- try {
- is = new ByteBufferInputStream(byteBuffer);
- // Do not require any IFD;
- ExifParser parser = ExifParser.parse(is, mInterface);
- mTagToModified = new ExifData(parser.getByteOrder());
- mOffsetBase += parser.getTiffStartPosition();
- mByteBuffer.position(0);
- } finally {
- ExifInterface.closeSilently(is);
- }
- }
-
- protected ByteOrder getByteOrder() {
- return mTagToModified.getByteOrder();
- }
-
- protected boolean commit() throws IOException, ExifInvalidFormatException {
- InputStream is = null;
- try {
- is = new ByteBufferInputStream(mByteBuffer);
- int flag = 0;
- IfdData[] ifdDatas = new IfdData[] {
- mTagToModified.getIfdData(IfdId.TYPE_IFD_0),
- mTagToModified.getIfdData(IfdId.TYPE_IFD_1),
- mTagToModified.getIfdData(IfdId.TYPE_IFD_EXIF),
- mTagToModified.getIfdData(IfdId.TYPE_IFD_INTEROPERABILITY),
- mTagToModified.getIfdData(IfdId.TYPE_IFD_GPS)
- };
-
- if (ifdDatas[IfdId.TYPE_IFD_0] != null) {
- flag |= ExifParser.OPTION_IFD_0;
- }
- if (ifdDatas[IfdId.TYPE_IFD_1] != null) {
- flag |= ExifParser.OPTION_IFD_1;
- }
- if (ifdDatas[IfdId.TYPE_IFD_EXIF] != null) {
- flag |= ExifParser.OPTION_IFD_EXIF;
- }
- if (ifdDatas[IfdId.TYPE_IFD_GPS] != null) {
- flag |= ExifParser.OPTION_IFD_GPS;
- }
- if (ifdDatas[IfdId.TYPE_IFD_INTEROPERABILITY] != null) {
- flag |= ExifParser.OPTION_IFD_INTEROPERABILITY;
- }
-
- ExifParser parser = ExifParser.parse(is, flag, mInterface);
- int event = parser.next();
- IfdData currIfd = null;
- while (event != ExifParser.EVENT_END) {
- switch (event) {
- case ExifParser.EVENT_START_OF_IFD:
- currIfd = ifdDatas[parser.getCurrentIfd()];
- if (currIfd == null) {
- parser.skipRemainingTagsInCurrentIfd();
- }
- break;
- case ExifParser.EVENT_NEW_TAG:
- ExifTag oldTag = parser.getTag();
- ExifTag newTag = currIfd.getTag(oldTag.getTagId());
- if (newTag != null) {
- if (newTag.getComponentCount() != oldTag.getComponentCount()
- || newTag.getDataType() != oldTag.getDataType()) {
- return false;
- } else {
- mTagOffsets.add(new TagOffset(newTag, oldTag.getOffset()));
- currIfd.removeTag(oldTag.getTagId());
- if (currIfd.getTagCount() == 0) {
- parser.skipRemainingTagsInCurrentIfd();
- }
- }
- }
- break;
- }
- event = parser.next();
- }
- for (IfdData ifd : ifdDatas) {
- if (ifd != null && ifd.getTagCount() > 0) {
- return false;
- }
- }
- modify();
- } finally {
- ExifInterface.closeSilently(is);
- }
- return true;
- }
-
- private void modify() {
- mByteBuffer.order(getByteOrder());
- for (TagOffset tagOffset : mTagOffsets) {
- writeTagValue(tagOffset.mTag, tagOffset.mOffset);
- }
- }
-
- private void writeTagValue(ExifTag tag, int offset) {
- if (DEBUG) {
- Log.v(TAG, "modifying tag to: \n" + tag.toString());
- Log.v(TAG, "at offset: " + offset);
- }
- mByteBuffer.position(offset + mOffsetBase);
- switch (tag.getDataType()) {
- case ExifTag.TYPE_ASCII:
- byte buf[] = tag.getStringByte();
- if (buf.length == tag.getComponentCount()) {
- buf[buf.length - 1] = 0;
- mByteBuffer.put(buf);
- } else {
- mByteBuffer.put(buf);
- mByteBuffer.put((byte) 0);
- }
- break;
- case ExifTag.TYPE_LONG:
- case ExifTag.TYPE_UNSIGNED_LONG:
- for (int i = 0, n = tag.getComponentCount(); i < n; i++) {
- mByteBuffer.putInt((int) tag.getValueAt(i));
- }
- break;
- case ExifTag.TYPE_RATIONAL:
- case ExifTag.TYPE_UNSIGNED_RATIONAL:
- for (int i = 0, n = tag.getComponentCount(); i < n; i++) {
- Rational v = tag.getRational(i);
- mByteBuffer.putInt((int) v.getNumerator());
- mByteBuffer.putInt((int) v.getDenominator());
- }
- break;
- case ExifTag.TYPE_UNDEFINED:
- case ExifTag.TYPE_UNSIGNED_BYTE:
- buf = new byte[tag.getComponentCount()];
- tag.getBytes(buf);
- mByteBuffer.put(buf);
- break;
- case ExifTag.TYPE_UNSIGNED_SHORT:
- for (int i = 0, n = tag.getComponentCount(); i < n; i++) {
- mByteBuffer.putShort((short) tag.getValueAt(i));
- }
- break;
- }
- }
-
- public void modifyTag(ExifTag tag) {
- mTagToModified.addTag(tag);
- }
-}
diff --git a/WallpaperPicker/src/com/android/gallery3d/exif/ExifOutputStream.java b/WallpaperPicker/src/com/android/gallery3d/exif/ExifOutputStream.java
deleted file mode 100644
index 7ca05f2e0..000000000
--- a/WallpaperPicker/src/com/android/gallery3d/exif/ExifOutputStream.java
+++ /dev/null
@@ -1,518 +0,0 @@
-/*
- * Copyright (C) 2012 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.exif;
-
-import android.util.Log;
-
-import java.io.BufferedOutputStream;
-import java.io.FilterOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.util.ArrayList;
-
-/**
- * This class provides a way to replace the Exif header of a JPEG image.
- * <p>
- * Below is an example of writing EXIF data into a file
- *
- * <pre>
- * public static void writeExif(byte[] jpeg, ExifData exif, String path) {
- * OutputStream os = null;
- * try {
- * os = new FileOutputStream(path);
- * ExifOutputStream eos = new ExifOutputStream(os);
- * // Set the exif header
- * eos.setExifData(exif);
- * // Write the original jpeg out, the header will be add into the file.
- * eos.write(jpeg);
- * } catch (FileNotFoundException e) {
- * e.printStackTrace();
- * } catch (IOException e) {
- * e.printStackTrace();
- * } finally {
- * if (os != null) {
- * try {
- * os.close();
- * } catch (IOException e) {
- * e.printStackTrace();
- * }
- * }
- * }
- * }
- * </pre>
- */
-class ExifOutputStream extends FilterOutputStream {
- private static final String TAG = "ExifOutputStream";
- private static final boolean DEBUG = false;
- private static final int STREAMBUFFER_SIZE = 0x00010000; // 64Kb
-
- private static final int STATE_SOI = 0;
- private static final int STATE_FRAME_HEADER = 1;
- private static final int STATE_JPEG_DATA = 2;
-
- private static final int EXIF_HEADER = 0x45786966;
- private static final short TIFF_HEADER = 0x002A;
- private static final short TIFF_BIG_ENDIAN = 0x4d4d;
- private static final short TIFF_LITTLE_ENDIAN = 0x4949;
- private static final short TAG_SIZE = 12;
- private static final short TIFF_HEADER_SIZE = 8;
- private static final int MAX_EXIF_SIZE = 65535;
-
- private ExifData mExifData;
- private int mState = STATE_SOI;
- private int mByteToSkip;
- private int mByteToCopy;
- private byte[] mSingleByteArray = new byte[1];
- private ByteBuffer mBuffer = ByteBuffer.allocate(4);
- private final ExifInterface mInterface;
-
- protected ExifOutputStream(OutputStream ou, ExifInterface iRef) {
- super(new BufferedOutputStream(ou, STREAMBUFFER_SIZE));
- mInterface = iRef;
- }
-
- /**
- * Sets the ExifData to be written into the JPEG file. Should be called
- * before writing image data.
- */
- protected void setExifData(ExifData exifData) {
- mExifData = exifData;
- }
-
- /**
- * Gets the Exif header to be written into the JPEF file.
- */
- protected ExifData getExifData() {
- return mExifData;
- }
-
- private int requestByteToBuffer(int requestByteCount, byte[] buffer
- , int offset, int length) {
- int byteNeeded = requestByteCount - mBuffer.position();
- int byteToRead = length > byteNeeded ? byteNeeded : length;
- mBuffer.put(buffer, offset, byteToRead);
- return byteToRead;
- }
-
- /**
- * Writes the image out. The input data should be a valid JPEG format. After
- * writing, it's Exif header will be replaced by the given header.
- */
- @Override
- public void write(byte[] buffer, int offset, int length) throws IOException {
- while ((mByteToSkip > 0 || mByteToCopy > 0 || mState != STATE_JPEG_DATA)
- && length > 0) {
- if (mByteToSkip > 0) {
- int byteToProcess = length > mByteToSkip ? mByteToSkip : length;
- length -= byteToProcess;
- mByteToSkip -= byteToProcess;
- offset += byteToProcess;
- }
- if (mByteToCopy > 0) {
- int byteToProcess = length > mByteToCopy ? mByteToCopy : length;
- out.write(buffer, offset, byteToProcess);
- length -= byteToProcess;
- mByteToCopy -= byteToProcess;
- offset += byteToProcess;
- }
- if (length == 0) {
- return;
- }
- switch (mState) {
- case STATE_SOI:
- int byteRead = requestByteToBuffer(2, buffer, offset, length);
- offset += byteRead;
- length -= byteRead;
- if (mBuffer.position() < 2) {
- return;
- }
- mBuffer.rewind();
- if (mBuffer.getShort() != JpegHeader.SOI) {
- throw new IOException("Not a valid jpeg image, cannot write exif");
- }
- out.write(mBuffer.array(), 0, 2);
- mState = STATE_FRAME_HEADER;
- mBuffer.rewind();
- writeExifData();
- break;
- case STATE_FRAME_HEADER:
- // We ignore the APP1 segment and copy all other segments
- // until SOF tag.
- byteRead = requestByteToBuffer(4, buffer, offset, length);
- offset += byteRead;
- length -= byteRead;
- // Check if this image data doesn't contain SOF.
- if (mBuffer.position() == 2) {
- short tag = mBuffer.getShort();
- if (tag == JpegHeader.EOI) {
- out.write(mBuffer.array(), 0, 2);
- mBuffer.rewind();
- }
- }
- if (mBuffer.position() < 4) {
- return;
- }
- mBuffer.rewind();
- short marker = mBuffer.getShort();
- if (marker == JpegHeader.APP1) {
- mByteToSkip = (mBuffer.getShort() & 0x0000ffff) - 2;
- mState = STATE_JPEG_DATA;
- } else if (!JpegHeader.isSofMarker(marker)) {
- out.write(mBuffer.array(), 0, 4);
- mByteToCopy = (mBuffer.getShort() & 0x0000ffff) - 2;
- } else {
- out.write(mBuffer.array(), 0, 4);
- mState = STATE_JPEG_DATA;
- }
- mBuffer.rewind();
- }
- }
- if (length > 0) {
- out.write(buffer, offset, length);
- }
- }
-
- /**
- * Writes the one bytes out. The input data should be a valid JPEG format.
- * After writing, it's Exif header will be replaced by the given header.
- */
- @Override
- public void write(int oneByte) throws IOException {
- mSingleByteArray[0] = (byte) (0xff & oneByte);
- write(mSingleByteArray);
- }
-
- /**
- * Equivalent to calling write(buffer, 0, buffer.length).
- */
- @Override
- public void write(byte[] buffer) throws IOException {
- write(buffer, 0, buffer.length);
- }
-
- private void writeExifData() throws IOException {
- if (mExifData == null) {
- return;
- }
- if (DEBUG) {
- Log.v(TAG, "Writing exif data...");
- }
- ArrayList<ExifTag> nullTags = stripNullValueTags(mExifData);
- createRequiredIfdAndTag();
- int exifSize = calculateAllOffset();
- if (exifSize + 8 > MAX_EXIF_SIZE) {
- throw new IOException("Exif header is too large (>64Kb)");
- }
- OrderedDataOutputStream dataOutputStream = new OrderedDataOutputStream(out);
- dataOutputStream.setByteOrder(ByteOrder.BIG_ENDIAN);
- dataOutputStream.writeShort(JpegHeader.APP1);
- dataOutputStream.writeShort((short) (exifSize + 8));
- dataOutputStream.writeInt(EXIF_HEADER);
- dataOutputStream.writeShort((short) 0x0000);
- if (mExifData.getByteOrder() == ByteOrder.BIG_ENDIAN) {
- dataOutputStream.writeShort(TIFF_BIG_ENDIAN);
- } else {
- dataOutputStream.writeShort(TIFF_LITTLE_ENDIAN);
- }
- dataOutputStream.setByteOrder(mExifData.getByteOrder());
- dataOutputStream.writeShort(TIFF_HEADER);
- dataOutputStream.writeInt(8);
- writeAllTags(dataOutputStream);
- writeThumbnail(dataOutputStream);
- for (ExifTag t : nullTags) {
- mExifData.addTag(t);
- }
- }
-
- private ArrayList<ExifTag> stripNullValueTags(ExifData data) {
- ArrayList<ExifTag> nullTags = new ArrayList<ExifTag>();
- for(ExifTag t : data.getAllTags()) {
- if (t.getValue() == null && !ExifInterface.isOffsetTag(t.getTagId())) {
- data.removeTag(t.getTagId(), t.getIfd());
- nullTags.add(t);
- }
- }
- return nullTags;
- }
-
- private void writeThumbnail(OrderedDataOutputStream dataOutputStream) throws IOException {
- if (mExifData.hasCompressedThumbnail()) {
- dataOutputStream.write(mExifData.getCompressedThumbnail());
- } else if (mExifData.hasUncompressedStrip()) {
- for (int i = 0; i < mExifData.getStripCount(); i++) {
- dataOutputStream.write(mExifData.getStrip(i));
- }
- }
- }
-
- private void writeAllTags(OrderedDataOutputStream dataOutputStream) throws IOException {
- writeIfd(mExifData.getIfdData(IfdId.TYPE_IFD_0), dataOutputStream);
- writeIfd(mExifData.getIfdData(IfdId.TYPE_IFD_EXIF), dataOutputStream);
- IfdData interoperabilityIfd = mExifData.getIfdData(IfdId.TYPE_IFD_INTEROPERABILITY);
- if (interoperabilityIfd != null) {
- writeIfd(interoperabilityIfd, dataOutputStream);
- }
- IfdData gpsIfd = mExifData.getIfdData(IfdId.TYPE_IFD_GPS);
- if (gpsIfd != null) {
- writeIfd(gpsIfd, dataOutputStream);
- }
- IfdData ifd1 = mExifData.getIfdData(IfdId.TYPE_IFD_1);
- if (ifd1 != null) {
- writeIfd(mExifData.getIfdData(IfdId.TYPE_IFD_1), dataOutputStream);
- }
- }
-
- private void writeIfd(IfdData ifd, OrderedDataOutputStream dataOutputStream)
- throws IOException {
- ExifTag[] tags = ifd.getAllTags();
- dataOutputStream.writeShort((short) tags.length);
- for (ExifTag tag : tags) {
- dataOutputStream.writeShort(tag.getTagId());
- dataOutputStream.writeShort(tag.getDataType());
- dataOutputStream.writeInt(tag.getComponentCount());
- if (DEBUG) {
- Log.v(TAG, "\n" + tag.toString());
- }
- if (tag.getDataSize() > 4) {
- dataOutputStream.writeInt(tag.getOffset());
- } else {
- ExifOutputStream.writeTagValue(tag, dataOutputStream);
- for (int i = 0, n = 4 - tag.getDataSize(); i < n; i++) {
- dataOutputStream.write(0);
- }
- }
- }
- dataOutputStream.writeInt(ifd.getOffsetToNextIfd());
- for (ExifTag tag : tags) {
- if (tag.getDataSize() > 4) {
- ExifOutputStream.writeTagValue(tag, dataOutputStream);
- }
- }
- }
-
- private int calculateOffsetOfIfd(IfdData ifd, int offset) {
- offset += 2 + ifd.getTagCount() * TAG_SIZE + 4;
- ExifTag[] tags = ifd.getAllTags();
- for (ExifTag tag : tags) {
- if (tag.getDataSize() > 4) {
- tag.setOffset(offset);
- offset += tag.getDataSize();
- }
- }
- return offset;
- }
-
- private void createRequiredIfdAndTag() throws IOException {
- // IFD0 is required for all file
- IfdData ifd0 = mExifData.getIfdData(IfdId.TYPE_IFD_0);
- if (ifd0 == null) {
- ifd0 = new IfdData(IfdId.TYPE_IFD_0);
- mExifData.addIfdData(ifd0);
- }
- ExifTag exifOffsetTag = mInterface.buildUninitializedTag(ExifInterface.TAG_EXIF_IFD);
- if (exifOffsetTag == null) {
- throw new IOException("No definition for crucial exif tag: "
- + ExifInterface.TAG_EXIF_IFD);
- }
- ifd0.setTag(exifOffsetTag);
-
- // Exif IFD is required for all files.
- IfdData exifIfd = mExifData.getIfdData(IfdId.TYPE_IFD_EXIF);
- if (exifIfd == null) {
- exifIfd = new IfdData(IfdId.TYPE_IFD_EXIF);
- mExifData.addIfdData(exifIfd);
- }
-
- // GPS IFD
- IfdData gpsIfd = mExifData.getIfdData(IfdId.TYPE_IFD_GPS);
- if (gpsIfd != null) {
- ExifTag gpsOffsetTag = mInterface.buildUninitializedTag(ExifInterface.TAG_GPS_IFD);
- if (gpsOffsetTag == null) {
- throw new IOException("No definition for crucial exif tag: "
- + ExifInterface.TAG_GPS_IFD);
- }
- ifd0.setTag(gpsOffsetTag);
- }
-
- // Interoperability IFD
- IfdData interIfd = mExifData.getIfdData(IfdId.TYPE_IFD_INTEROPERABILITY);
- if (interIfd != null) {
- ExifTag interOffsetTag = mInterface
- .buildUninitializedTag(ExifInterface.TAG_INTEROPERABILITY_IFD);
- if (interOffsetTag == null) {
- throw new IOException("No definition for crucial exif tag: "
- + ExifInterface.TAG_INTEROPERABILITY_IFD);
- }
- exifIfd.setTag(interOffsetTag);
- }
-
- IfdData ifd1 = mExifData.getIfdData(IfdId.TYPE_IFD_1);
-
- // thumbnail
- if (mExifData.hasCompressedThumbnail()) {
-
- if (ifd1 == null) {
- ifd1 = new IfdData(IfdId.TYPE_IFD_1);
- mExifData.addIfdData(ifd1);
- }
-
- ExifTag offsetTag = mInterface
- .buildUninitializedTag(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT);
- if (offsetTag == null) {
- throw new IOException("No definition for crucial exif tag: "
- + ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT);
- }
-
- ifd1.setTag(offsetTag);
- ExifTag lengthTag = mInterface
- .buildUninitializedTag(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
- if (lengthTag == null) {
- throw new IOException("No definition for crucial exif tag: "
- + ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
- }
-
- lengthTag.setValue(mExifData.getCompressedThumbnail().length);
- ifd1.setTag(lengthTag);
-
- // Get rid of tags for uncompressed if they exist.
- ifd1.removeTag(ExifInterface.getTrueTagKey(ExifInterface.TAG_STRIP_OFFSETS));
- ifd1.removeTag(ExifInterface.getTrueTagKey(ExifInterface.TAG_STRIP_BYTE_COUNTS));
- } else if (mExifData.hasUncompressedStrip()) {
- if (ifd1 == null) {
- ifd1 = new IfdData(IfdId.TYPE_IFD_1);
- mExifData.addIfdData(ifd1);
- }
- int stripCount = mExifData.getStripCount();
- ExifTag offsetTag = mInterface.buildUninitializedTag(ExifInterface.TAG_STRIP_OFFSETS);
- if (offsetTag == null) {
- throw new IOException("No definition for crucial exif tag: "
- + ExifInterface.TAG_STRIP_OFFSETS);
- }
- ExifTag lengthTag = mInterface
- .buildUninitializedTag(ExifInterface.TAG_STRIP_BYTE_COUNTS);
- if (lengthTag == null) {
- throw new IOException("No definition for crucial exif tag: "
- + ExifInterface.TAG_STRIP_BYTE_COUNTS);
- }
- long[] lengths = new long[stripCount];
- for (int i = 0; i < mExifData.getStripCount(); i++) {
- lengths[i] = mExifData.getStrip(i).length;
- }
- lengthTag.setValue(lengths);
- ifd1.setTag(offsetTag);
- ifd1.setTag(lengthTag);
- // Get rid of tags for compressed if they exist.
- ifd1.removeTag(ExifInterface.getTrueTagKey(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT));
- ifd1.removeTag(ExifInterface
- .getTrueTagKey(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH));
- } else if (ifd1 != null) {
- // Get rid of offset and length tags if there is no thumbnail.
- ifd1.removeTag(ExifInterface.getTrueTagKey(ExifInterface.TAG_STRIP_OFFSETS));
- ifd1.removeTag(ExifInterface.getTrueTagKey(ExifInterface.TAG_STRIP_BYTE_COUNTS));
- ifd1.removeTag(ExifInterface.getTrueTagKey(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT));
- ifd1.removeTag(ExifInterface
- .getTrueTagKey(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH));
- }
- }
-
- private int calculateAllOffset() {
- int offset = TIFF_HEADER_SIZE;
- IfdData ifd0 = mExifData.getIfdData(IfdId.TYPE_IFD_0);
- offset = calculateOffsetOfIfd(ifd0, offset);
- ifd0.getTag(ExifInterface.getTrueTagKey(ExifInterface.TAG_EXIF_IFD)).setValue(offset);
-
- IfdData exifIfd = mExifData.getIfdData(IfdId.TYPE_IFD_EXIF);
- offset = calculateOffsetOfIfd(exifIfd, offset);
-
- IfdData interIfd = mExifData.getIfdData(IfdId.TYPE_IFD_INTEROPERABILITY);
- if (interIfd != null) {
- exifIfd.getTag(ExifInterface.getTrueTagKey(ExifInterface.TAG_INTEROPERABILITY_IFD))
- .setValue(offset);
- offset = calculateOffsetOfIfd(interIfd, offset);
- }
-
- IfdData gpsIfd = mExifData.getIfdData(IfdId.TYPE_IFD_GPS);
- if (gpsIfd != null) {
- ifd0.getTag(ExifInterface.getTrueTagKey(ExifInterface.TAG_GPS_IFD)).setValue(offset);
- offset = calculateOffsetOfIfd(gpsIfd, offset);
- }
-
- IfdData ifd1 = mExifData.getIfdData(IfdId.TYPE_IFD_1);
- if (ifd1 != null) {
- ifd0.setOffsetToNextIfd(offset);
- offset = calculateOffsetOfIfd(ifd1, offset);
- }
-
- // thumbnail
- if (mExifData.hasCompressedThumbnail()) {
- ifd1.getTag(ExifInterface.getTrueTagKey(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT))
- .setValue(offset);
- offset += mExifData.getCompressedThumbnail().length;
- } else if (mExifData.hasUncompressedStrip()) {
- int stripCount = mExifData.getStripCount();
- long[] offsets = new long[stripCount];
- for (int i = 0; i < mExifData.getStripCount(); i++) {
- offsets[i] = offset;
- offset += mExifData.getStrip(i).length;
- }
- ifd1.getTag(ExifInterface.getTrueTagKey(ExifInterface.TAG_STRIP_OFFSETS)).setValue(
- offsets);
- }
- return offset;
- }
-
- static void writeTagValue(ExifTag tag, OrderedDataOutputStream dataOutputStream)
- throws IOException {
- switch (tag.getDataType()) {
- case ExifTag.TYPE_ASCII:
- byte buf[] = tag.getStringByte();
- if (buf.length == tag.getComponentCount()) {
- buf[buf.length - 1] = 0;
- dataOutputStream.write(buf);
- } else {
- dataOutputStream.write(buf);
- dataOutputStream.write(0);
- }
- break;
- case ExifTag.TYPE_LONG:
- case ExifTag.TYPE_UNSIGNED_LONG:
- for (int i = 0, n = tag.getComponentCount(); i < n; i++) {
- dataOutputStream.writeInt((int) tag.getValueAt(i));
- }
- break;
- case ExifTag.TYPE_RATIONAL:
- case ExifTag.TYPE_UNSIGNED_RATIONAL:
- for (int i = 0, n = tag.getComponentCount(); i < n; i++) {
- dataOutputStream.writeRational(tag.getRational(i));
- }
- break;
- case ExifTag.TYPE_UNDEFINED:
- case ExifTag.TYPE_UNSIGNED_BYTE:
- buf = new byte[tag.getComponentCount()];
- tag.getBytes(buf);
- dataOutputStream.write(buf);
- break;
- case ExifTag.TYPE_UNSIGNED_SHORT:
- for (int i = 0, n = tag.getComponentCount(); i < n; i++) {
- dataOutputStream.writeShort((short) tag.getValueAt(i));
- }
- break;
- }
- }
-}
diff --git a/WallpaperPicker/src/com/android/gallery3d/exif/ExifParser.java b/WallpaperPicker/src/com/android/gallery3d/exif/ExifParser.java
deleted file mode 100644
index 5467d423d..000000000
--- a/WallpaperPicker/src/com/android/gallery3d/exif/ExifParser.java
+++ /dev/null
@@ -1,916 +0,0 @@
-/*
- * Copyright (C) 2012 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.exif;
-
-import android.util.Log;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.ByteOrder;
-import java.nio.charset.Charset;
-import java.util.Map.Entry;
-import java.util.TreeMap;
-
-/**
- * This class provides a low-level EXIF parsing API. Given a JPEG format
- * InputStream, the caller can request which IFD's to read via
- * {@link #parse(InputStream, int)} with given options.
- * <p>
- * Below is an example of getting EXIF data from IFD 0 and EXIF IFD using the
- * parser.
- *
- * <pre>
- * void parse() {
- * ExifParser parser = ExifParser.parse(mImageInputStream,
- * ExifParser.OPTION_IFD_0 | ExifParser.OPTIONS_IFD_EXIF);
- * int event = parser.next();
- * while (event != ExifParser.EVENT_END) {
- * switch (event) {
- * case ExifParser.EVENT_START_OF_IFD:
- * break;
- * case ExifParser.EVENT_NEW_TAG:
- * ExifTag tag = parser.getTag();
- * if (!tag.hasValue()) {
- * parser.registerForTagValue(tag);
- * } else {
- * processTag(tag);
- * }
- * break;
- * case ExifParser.EVENT_VALUE_OF_REGISTERED_TAG:
- * tag = parser.getTag();
- * if (tag.getDataType() != ExifTag.TYPE_UNDEFINED) {
- * processTag(tag);
- * }
- * break;
- * }
- * event = parser.next();
- * }
- * }
- *
- * void processTag(ExifTag tag) {
- * // process the tag as you like.
- * }
- * </pre>
- */
-class ExifParser {
- private static final boolean LOGV = false;
- private static final String TAG = "ExifParser";
- /**
- * When the parser reaches a new IFD area. Call {@link #getCurrentIfd()} to
- * know which IFD we are in.
- */
- public static final int EVENT_START_OF_IFD = 0;
- /**
- * When the parser reaches a new tag. Call {@link #getTag()}to get the
- * corresponding tag.
- */
- public static final int EVENT_NEW_TAG = 1;
- /**
- * When the parser reaches the value area of tag that is registered by
- * {@link #registerForTagValue(ExifTag)} previously. Call {@link #getTag()}
- * to get the corresponding tag.
- */
- public static final int EVENT_VALUE_OF_REGISTERED_TAG = 2;
-
- /**
- * When the parser reaches the compressed image area.
- */
- public static final int EVENT_COMPRESSED_IMAGE = 3;
- /**
- * When the parser reaches the uncompressed image strip. Call
- * {@link #getStripIndex()} to get the index of the strip.
- *
- * @see #getStripIndex()
- * @see #getStripCount()
- */
- public static final int EVENT_UNCOMPRESSED_STRIP = 4;
- /**
- * When there is nothing more to parse.
- */
- public static final int EVENT_END = 5;
-
- /**
- * Option bit to request to parse IFD0.
- */
- public static final int OPTION_IFD_0 = 1 << 0;
- /**
- * Option bit to request to parse IFD1.
- */
- public static final int OPTION_IFD_1 = 1 << 1;
- /**
- * Option bit to request to parse Exif-IFD.
- */
- public static final int OPTION_IFD_EXIF = 1 << 2;
- /**
- * Option bit to request to parse GPS-IFD.
- */
- public static final int OPTION_IFD_GPS = 1 << 3;
- /**
- * Option bit to request to parse Interoperability-IFD.
- */
- public static final int OPTION_IFD_INTEROPERABILITY = 1 << 4;
- /**
- * Option bit to request to parse thumbnail.
- */
- public static final int OPTION_THUMBNAIL = 1 << 5;
-
- protected static final int EXIF_HEADER = 0x45786966; // EXIF header "Exif"
- protected static final short EXIF_HEADER_TAIL = (short) 0x0000; // EXIF header in APP1
-
- // TIFF header
- protected static final short LITTLE_ENDIAN_TAG = (short) 0x4949; // "II"
- protected static final short BIG_ENDIAN_TAG = (short) 0x4d4d; // "MM"
- protected static final short TIFF_HEADER_TAIL = 0x002A;
-
- protected static final int TAG_SIZE = 12;
- protected static final int OFFSET_SIZE = 2;
-
- private static final Charset US_ASCII = Charset.forName("US-ASCII");
-
- protected static final int DEFAULT_IFD0_OFFSET = 8;
-
- private final CountedDataInputStream mTiffStream;
- private final int mOptions;
- private int mIfdStartOffset = 0;
- private int mNumOfTagInIfd = 0;
- private int mIfdType;
- private ExifTag mTag;
- private ImageEvent mImageEvent;
- private int mStripCount;
- private ExifTag mStripSizeTag;
- private ExifTag mJpegSizeTag;
- private boolean mNeedToParseOffsetsInCurrentIfd;
- private boolean mContainExifData = false;
- private int mApp1End;
- private int mOffsetToApp1EndFromSOF = 0;
- private byte[] mDataAboveIfd0;
- private int mIfd0Position;
- private int mTiffStartPosition;
- private final ExifInterface mInterface;
-
- private static final short TAG_EXIF_IFD = ExifInterface
- .getTrueTagKey(ExifInterface.TAG_EXIF_IFD);
- private static final short TAG_GPS_IFD = ExifInterface.getTrueTagKey(ExifInterface.TAG_GPS_IFD);
- private static final short TAG_INTEROPERABILITY_IFD = ExifInterface
- .getTrueTagKey(ExifInterface.TAG_INTEROPERABILITY_IFD);
- private static final short TAG_JPEG_INTERCHANGE_FORMAT = ExifInterface
- .getTrueTagKey(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT);
- private static final short TAG_JPEG_INTERCHANGE_FORMAT_LENGTH = ExifInterface
- .getTrueTagKey(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
- private static final short TAG_STRIP_OFFSETS = ExifInterface
- .getTrueTagKey(ExifInterface.TAG_STRIP_OFFSETS);
- private static final short TAG_STRIP_BYTE_COUNTS = ExifInterface
- .getTrueTagKey(ExifInterface.TAG_STRIP_BYTE_COUNTS);
-
- private final TreeMap<Integer, Object> mCorrespondingEvent = new TreeMap<Integer, Object>();
-
- private boolean isIfdRequested(int ifdType) {
- switch (ifdType) {
- case IfdId.TYPE_IFD_0:
- return (mOptions & OPTION_IFD_0) != 0;
- case IfdId.TYPE_IFD_1:
- return (mOptions & OPTION_IFD_1) != 0;
- case IfdId.TYPE_IFD_EXIF:
- return (mOptions & OPTION_IFD_EXIF) != 0;
- case IfdId.TYPE_IFD_GPS:
- return (mOptions & OPTION_IFD_GPS) != 0;
- case IfdId.TYPE_IFD_INTEROPERABILITY:
- return (mOptions & OPTION_IFD_INTEROPERABILITY) != 0;
- }
- return false;
- }
-
- private boolean isThumbnailRequested() {
- return (mOptions & OPTION_THUMBNAIL) != 0;
- }
-
- private ExifParser(InputStream inputStream, int options, ExifInterface iRef)
- throws IOException, ExifInvalidFormatException {
- if (inputStream == null) {
- throw new IOException("Null argument inputStream to ExifParser");
- }
- if (LOGV) {
- Log.v(TAG, "Reading exif...");
- }
- mInterface = iRef;
- mContainExifData = seekTiffData(inputStream);
- mTiffStream = new CountedDataInputStream(inputStream);
- mOptions = options;
- if (!mContainExifData) {
- return;
- }
-
- parseTiffHeader();
- long offset = mTiffStream.readUnsignedInt();
- if (offset > Integer.MAX_VALUE) {
- throw new ExifInvalidFormatException("Invalid offset " + offset);
- }
- mIfd0Position = (int) offset;
- mIfdType = IfdId.TYPE_IFD_0;
- if (isIfdRequested(IfdId.TYPE_IFD_0) || needToParseOffsetsInCurrentIfd()) {
- registerIfd(IfdId.TYPE_IFD_0, offset);
- if (offset != DEFAULT_IFD0_OFFSET) {
- mDataAboveIfd0 = new byte[(int) offset - DEFAULT_IFD0_OFFSET];
- read(mDataAboveIfd0);
- }
- }
- }
-
- /**
- * Parses the the given InputStream with the given options
- *
- * @exception IOException
- * @exception ExifInvalidFormatException
- */
- protected static ExifParser parse(InputStream inputStream, int options, ExifInterface iRef)
- throws IOException, ExifInvalidFormatException {
- return new ExifParser(inputStream, options, iRef);
- }
-
- /**
- * Parses the the given InputStream with default options; that is, every IFD
- * and thumbnaill will be parsed.
- *
- * @exception IOException
- * @exception ExifInvalidFormatException
- * @see #parse(InputStream, int)
- */
- protected static ExifParser parse(InputStream inputStream, ExifInterface iRef)
- throws IOException, ExifInvalidFormatException {
- return new ExifParser(inputStream, OPTION_IFD_0 | OPTION_IFD_1
- | OPTION_IFD_EXIF | OPTION_IFD_GPS | OPTION_IFD_INTEROPERABILITY
- | OPTION_THUMBNAIL, iRef);
- }
-
- /**
- * Moves the parser forward and returns the next parsing event
- *
- * @exception IOException
- * @exception ExifInvalidFormatException
- * @see #EVENT_START_OF_IFD
- * @see #EVENT_NEW_TAG
- * @see #EVENT_VALUE_OF_REGISTERED_TAG
- * @see #EVENT_COMPRESSED_IMAGE
- * @see #EVENT_UNCOMPRESSED_STRIP
- * @see #EVENT_END
- */
- protected int next() throws IOException, ExifInvalidFormatException {
- if (!mContainExifData) {
- return EVENT_END;
- }
- int offset = mTiffStream.getReadByteCount();
- int endOfTags = mIfdStartOffset + OFFSET_SIZE + TAG_SIZE * mNumOfTagInIfd;
- if (offset < endOfTags) {
- mTag = readTag();
- if (mTag == null) {
- return next();
- }
- if (mNeedToParseOffsetsInCurrentIfd) {
- checkOffsetOrImageTag(mTag);
- }
- return EVENT_NEW_TAG;
- } else if (offset == endOfTags) {
- // There is a link to ifd1 at the end of ifd0
- if (mIfdType == IfdId.TYPE_IFD_0) {
- long ifdOffset = readUnsignedLong();
- if (isIfdRequested(IfdId.TYPE_IFD_1) || isThumbnailRequested()) {
- if (ifdOffset != 0) {
- registerIfd(IfdId.TYPE_IFD_1, ifdOffset);
- }
- }
- } else {
- int offsetSize = 4;
- // Some camera models use invalid length of the offset
- if (mCorrespondingEvent.size() > 0) {
- offsetSize = mCorrespondingEvent.firstEntry().getKey() -
- mTiffStream.getReadByteCount();
- }
- if (offsetSize < 4) {
- Log.w(TAG, "Invalid size of link to next IFD: " + offsetSize);
- } else {
- long ifdOffset = readUnsignedLong();
- if (ifdOffset != 0) {
- Log.w(TAG, "Invalid link to next IFD: " + ifdOffset);
- }
- }
- }
- }
- while (mCorrespondingEvent.size() != 0) {
- Entry<Integer, Object> entry = mCorrespondingEvent.pollFirstEntry();
- Object event = entry.getValue();
- try {
- skipTo(entry.getKey());
- } catch (IOException e) {
- Log.w(TAG, "Failed to skip to data at: " + entry.getKey() +
- " for " + event.getClass().getName() + ", the file may be broken.");
- continue;
- }
- if (event instanceof IfdEvent) {
- mIfdType = ((IfdEvent) event).ifd;
- mNumOfTagInIfd = mTiffStream.readUnsignedShort();
- mIfdStartOffset = entry.getKey();
-
- if (mNumOfTagInIfd * TAG_SIZE + mIfdStartOffset + OFFSET_SIZE > mApp1End) {
- Log.w(TAG, "Invalid size of IFD " + mIfdType);
- return EVENT_END;
- }
-
- mNeedToParseOffsetsInCurrentIfd = needToParseOffsetsInCurrentIfd();
- if (((IfdEvent) event).isRequested) {
- return EVENT_START_OF_IFD;
- } else {
- skipRemainingTagsInCurrentIfd();
- }
- } else if (event instanceof ImageEvent) {
- mImageEvent = (ImageEvent) event;
- return mImageEvent.type;
- } else {
- ExifTagEvent tagEvent = (ExifTagEvent) event;
- mTag = tagEvent.tag;
- if (mTag.getDataType() != ExifTag.TYPE_UNDEFINED) {
- readFullTagValue(mTag);
- checkOffsetOrImageTag(mTag);
- }
- if (tagEvent.isRequested) {
- return EVENT_VALUE_OF_REGISTERED_TAG;
- }
- }
- }
- return EVENT_END;
- }
-
- /**
- * Skips the tags area of current IFD, if the parser is not in the tag area,
- * nothing will happen.
- *
- * @throws IOException
- * @throws ExifInvalidFormatException
- */
- protected void skipRemainingTagsInCurrentIfd() throws IOException, ExifInvalidFormatException {
- int endOfTags = mIfdStartOffset + OFFSET_SIZE + TAG_SIZE * mNumOfTagInIfd;
- int offset = mTiffStream.getReadByteCount();
- if (offset > endOfTags) {
- return;
- }
- if (mNeedToParseOffsetsInCurrentIfd) {
- while (offset < endOfTags) {
- mTag = readTag();
- offset += TAG_SIZE;
- if (mTag == null) {
- continue;
- }
- checkOffsetOrImageTag(mTag);
- }
- } else {
- skipTo(endOfTags);
- }
- long ifdOffset = readUnsignedLong();
- // For ifd0, there is a link to ifd1 in the end of all tags
- if (mIfdType == IfdId.TYPE_IFD_0
- && (isIfdRequested(IfdId.TYPE_IFD_1) || isThumbnailRequested())) {
- if (ifdOffset > 0) {
- registerIfd(IfdId.TYPE_IFD_1, ifdOffset);
- }
- }
- }
-
- private boolean needToParseOffsetsInCurrentIfd() {
- switch (mIfdType) {
- case IfdId.TYPE_IFD_0:
- return isIfdRequested(IfdId.TYPE_IFD_EXIF) || isIfdRequested(IfdId.TYPE_IFD_GPS)
- || isIfdRequested(IfdId.TYPE_IFD_INTEROPERABILITY)
- || isIfdRequested(IfdId.TYPE_IFD_1);
- case IfdId.TYPE_IFD_1:
- return isThumbnailRequested();
- case IfdId.TYPE_IFD_EXIF:
- // The offset to interoperability IFD is located in Exif IFD
- return isIfdRequested(IfdId.TYPE_IFD_INTEROPERABILITY);
- default:
- return false;
- }
- }
-
- /**
- * If {@link #next()} return {@link #EVENT_NEW_TAG} or
- * {@link #EVENT_VALUE_OF_REGISTERED_TAG}, call this function to get the
- * corresponding tag.
- * <p>
- * For {@link #EVENT_NEW_TAG}, the tag may not contain the value if the size
- * of the value is greater than 4 bytes. One should call
- * {@link ExifTag#hasValue()} to check if the tag contains value. If there
- * is no value,call {@link #registerForTagValue(ExifTag)} to have the parser
- * emit {@link #EVENT_VALUE_OF_REGISTERED_TAG} when it reaches the area
- * pointed by the offset.
- * <p>
- * When {@link #EVENT_VALUE_OF_REGISTERED_TAG} is emitted, the value of the
- * tag will have already been read except for tags of undefined type. For
- * tags of undefined type, call one of the read methods to get the value.
- *
- * @see #registerForTagValue(ExifTag)
- * @see #read(byte[])
- * @see #read(byte[], int, int)
- * @see #readLong()
- * @see #readRational()
- * @see #readString(int)
- * @see #readString(int, Charset)
- */
- protected ExifTag getTag() {
- return mTag;
- }
-
- /**
- * Gets number of tags in the current IFD area.
- */
- protected int getTagCountInCurrentIfd() {
- return mNumOfTagInIfd;
- }
-
- /**
- * Gets the ID of current IFD.
- *
- * @see IfdId#TYPE_IFD_0
- * @see IfdId#TYPE_IFD_1
- * @see IfdId#TYPE_IFD_GPS
- * @see IfdId#TYPE_IFD_INTEROPERABILITY
- * @see IfdId#TYPE_IFD_EXIF
- */
- protected int getCurrentIfd() {
- return mIfdType;
- }
-
- /**
- * When receiving {@link #EVENT_UNCOMPRESSED_STRIP}, call this function to
- * get the index of this strip.
- *
- * @see #getStripCount()
- */
- protected int getStripIndex() {
- return mImageEvent.stripIndex;
- }
-
- /**
- * When receiving {@link #EVENT_UNCOMPRESSED_STRIP}, call this function to
- * get the number of strip data.
- *
- * @see #getStripIndex()
- */
- protected int getStripCount() {
- return mStripCount;
- }
-
- /**
- * When receiving {@link #EVENT_UNCOMPRESSED_STRIP}, call this function to
- * get the strip size.
- */
- protected int getStripSize() {
- if (mStripSizeTag == null)
- return 0;
- return (int) mStripSizeTag.getValueAt(0);
- }
-
- /**
- * When receiving {@link #EVENT_COMPRESSED_IMAGE}, call this function to get
- * the image data size.
- */
- protected int getCompressedImageSize() {
- if (mJpegSizeTag == null) {
- return 0;
- }
- return (int) mJpegSizeTag.getValueAt(0);
- }
-
- private void skipTo(int offset) throws IOException {
- mTiffStream.skipTo(offset);
- while (!mCorrespondingEvent.isEmpty() && mCorrespondingEvent.firstKey() < offset) {
- mCorrespondingEvent.pollFirstEntry();
- }
- }
-
- /**
- * When getting {@link #EVENT_NEW_TAG} in the tag area of IFD, the tag may
- * not contain the value if the size of the value is greater than 4 bytes.
- * When the value is not available here, call this method so that the parser
- * will emit {@link #EVENT_VALUE_OF_REGISTERED_TAG} when it reaches the area
- * where the value is located.
- *
- * @see #EVENT_VALUE_OF_REGISTERED_TAG
- */
- protected void registerForTagValue(ExifTag tag) {
- if (tag.getOffset() >= mTiffStream.getReadByteCount()) {
- mCorrespondingEvent.put(tag.getOffset(), new ExifTagEvent(tag, true));
- }
- }
-
- private void registerIfd(int ifdType, long offset) {
- // Cast unsigned int to int since the offset is always smaller
- // than the size of APP1 (65536)
- mCorrespondingEvent.put((int) offset, new IfdEvent(ifdType, isIfdRequested(ifdType)));
- }
-
- private void registerCompressedImage(long offset) {
- mCorrespondingEvent.put((int) offset, new ImageEvent(EVENT_COMPRESSED_IMAGE));
- }
-
- private void registerUncompressedStrip(int stripIndex, long offset) {
- mCorrespondingEvent.put((int) offset, new ImageEvent(EVENT_UNCOMPRESSED_STRIP
- , stripIndex));
- }
-
- private ExifTag readTag() throws IOException, ExifInvalidFormatException {
- short tagId = mTiffStream.readShort();
- short dataFormat = mTiffStream.readShort();
- long numOfComp = mTiffStream.readUnsignedInt();
- if (numOfComp > Integer.MAX_VALUE) {
- throw new ExifInvalidFormatException(
- "Number of component is larger then Integer.MAX_VALUE");
- }
- // Some invalid image file contains invalid data type. Ignore those tags
- if (!ExifTag.isValidType(dataFormat)) {
- Log.w(TAG, String.format("Tag %04x: Invalid data type %d", tagId, dataFormat));
- mTiffStream.skip(4);
- return null;
- }
- // TODO: handle numOfComp overflow
- ExifTag tag = new ExifTag(tagId, dataFormat, (int) numOfComp, mIfdType,
- ((int) numOfComp) != ExifTag.SIZE_UNDEFINED);
- int dataSize = tag.getDataSize();
- if (dataSize > 4) {
- long offset = mTiffStream.readUnsignedInt();
- if (offset > Integer.MAX_VALUE) {
- throw new ExifInvalidFormatException(
- "offset is larger then Integer.MAX_VALUE");
- }
- // Some invalid images put some undefined data before IFD0.
- // Read the data here.
- if ((offset < mIfd0Position) && (dataFormat == ExifTag.TYPE_UNDEFINED)) {
- byte[] buf = new byte[(int) numOfComp];
- System.arraycopy(mDataAboveIfd0, (int) offset - DEFAULT_IFD0_OFFSET,
- buf, 0, (int) numOfComp);
- tag.setValue(buf);
- } else {
- tag.setOffset((int) offset);
- }
- } else {
- boolean defCount = tag.hasDefinedCount();
- // Set defined count to 0 so we can add \0 to non-terminated strings
- tag.setHasDefinedCount(false);
- // Read value
- readFullTagValue(tag);
- tag.setHasDefinedCount(defCount);
- mTiffStream.skip(4 - dataSize);
- // Set the offset to the position of value.
- tag.setOffset(mTiffStream.getReadByteCount() - 4);
- }
- return tag;
- }
-
- /**
- * Check the tag, if the tag is one of the offset tag that points to the IFD
- * or image the caller is interested in, register the IFD or image.
- */
- private void checkOffsetOrImageTag(ExifTag tag) {
- // Some invalid formattd image contains tag with 0 size.
- if (tag.getComponentCount() == 0) {
- return;
- }
- short tid = tag.getTagId();
- int ifd = tag.getIfd();
- if (tid == TAG_EXIF_IFD && checkAllowed(ifd, ExifInterface.TAG_EXIF_IFD)) {
- if (isIfdRequested(IfdId.TYPE_IFD_EXIF)
- || isIfdRequested(IfdId.TYPE_IFD_INTEROPERABILITY)) {
- registerIfd(IfdId.TYPE_IFD_EXIF, tag.getValueAt(0));
- }
- } else if (tid == TAG_GPS_IFD && checkAllowed(ifd, ExifInterface.TAG_GPS_IFD)) {
- if (isIfdRequested(IfdId.TYPE_IFD_GPS)) {
- registerIfd(IfdId.TYPE_IFD_GPS, tag.getValueAt(0));
- }
- } else if (tid == TAG_INTEROPERABILITY_IFD
- && checkAllowed(ifd, ExifInterface.TAG_INTEROPERABILITY_IFD)) {
- if (isIfdRequested(IfdId.TYPE_IFD_INTEROPERABILITY)) {
- registerIfd(IfdId.TYPE_IFD_INTEROPERABILITY, tag.getValueAt(0));
- }
- } else if (tid == TAG_JPEG_INTERCHANGE_FORMAT
- && checkAllowed(ifd, ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT)) {
- if (isThumbnailRequested()) {
- registerCompressedImage(tag.getValueAt(0));
- }
- } else if (tid == TAG_JPEG_INTERCHANGE_FORMAT_LENGTH
- && checkAllowed(ifd, ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH)) {
- if (isThumbnailRequested()) {
- mJpegSizeTag = tag;
- }
- } else if (tid == TAG_STRIP_OFFSETS && checkAllowed(ifd, ExifInterface.TAG_STRIP_OFFSETS)) {
- if (isThumbnailRequested()) {
- if (tag.hasValue()) {
- for (int i = 0; i < tag.getComponentCount(); i++) {
- if (tag.getDataType() == ExifTag.TYPE_UNSIGNED_SHORT) {
- registerUncompressedStrip(i, tag.getValueAt(i));
- } else {
- registerUncompressedStrip(i, tag.getValueAt(i));
- }
- }
- } else {
- mCorrespondingEvent.put(tag.getOffset(), new ExifTagEvent(tag, false));
- }
- }
- } else if (tid == TAG_STRIP_BYTE_COUNTS
- && checkAllowed(ifd, ExifInterface.TAG_STRIP_BYTE_COUNTS)
- &&isThumbnailRequested() && tag.hasValue()) {
- mStripSizeTag = tag;
- }
- }
-
- private boolean checkAllowed(int ifd, int tagId) {
- int info = mInterface.getTagInfo().get(tagId);
- if (info == ExifInterface.DEFINITION_NULL) {
- return false;
- }
- return ExifInterface.isIfdAllowed(info, ifd);
- }
-
- protected void readFullTagValue(ExifTag tag) throws IOException {
- // Some invalid images contains tags with wrong size, check it here
- short type = tag.getDataType();
- if (type == ExifTag.TYPE_ASCII || type == ExifTag.TYPE_UNDEFINED ||
- type == ExifTag.TYPE_UNSIGNED_BYTE) {
- int size = tag.getComponentCount();
- if (mCorrespondingEvent.size() > 0) {
- if (mCorrespondingEvent.firstEntry().getKey() < mTiffStream.getReadByteCount()
- + size) {
- Object event = mCorrespondingEvent.firstEntry().getValue();
- if (event instanceof ImageEvent) {
- // Tag value overlaps thumbnail, ignore thumbnail.
- Log.w(TAG, "Thumbnail overlaps value for tag: \n" + tag.toString());
- Entry<Integer, Object> entry = mCorrespondingEvent.pollFirstEntry();
- Log.w(TAG, "Invalid thumbnail offset: " + entry.getKey());
- } else {
- // Tag value overlaps another tag, shorten count
- if (event instanceof IfdEvent) {
- Log.w(TAG, "Ifd " + ((IfdEvent) event).ifd
- + " overlaps value for tag: \n" + tag.toString());
- } else if (event instanceof ExifTagEvent) {
- Log.w(TAG, "Tag value for tag: \n"
- + ((ExifTagEvent) event).tag.toString()
- + " overlaps value for tag: \n" + tag.toString());
- }
- size = mCorrespondingEvent.firstEntry().getKey()
- - mTiffStream.getReadByteCount();
- Log.w(TAG, "Invalid size of tag: \n" + tag.toString()
- + " setting count to: " + size);
- tag.forceSetComponentCount(size);
- }
- }
- }
- }
- switch (tag.getDataType()) {
- case ExifTag.TYPE_UNSIGNED_BYTE:
- case ExifTag.TYPE_UNDEFINED: {
- byte buf[] = new byte[tag.getComponentCount()];
- read(buf);
- tag.setValue(buf);
- }
- break;
- case ExifTag.TYPE_ASCII:
- tag.setValue(readString(tag.getComponentCount()));
- break;
- case ExifTag.TYPE_UNSIGNED_LONG: {
- long value[] = new long[tag.getComponentCount()];
- for (int i = 0, n = value.length; i < n; i++) {
- value[i] = readUnsignedLong();
- }
- tag.setValue(value);
- }
- break;
- case ExifTag.TYPE_UNSIGNED_RATIONAL: {
- Rational value[] = new Rational[tag.getComponentCount()];
- for (int i = 0, n = value.length; i < n; i++) {
- value[i] = readUnsignedRational();
- }
- tag.setValue(value);
- }
- break;
- case ExifTag.TYPE_UNSIGNED_SHORT: {
- int value[] = new int[tag.getComponentCount()];
- for (int i = 0, n = value.length; i < n; i++) {
- value[i] = readUnsignedShort();
- }
- tag.setValue(value);
- }
- break;
- case ExifTag.TYPE_LONG: {
- int value[] = new int[tag.getComponentCount()];
- for (int i = 0, n = value.length; i < n; i++) {
- value[i] = readLong();
- }
- tag.setValue(value);
- }
- break;
- case ExifTag.TYPE_RATIONAL: {
- Rational value[] = new Rational[tag.getComponentCount()];
- for (int i = 0, n = value.length; i < n; i++) {
- value[i] = readRational();
- }
- tag.setValue(value);
- }
- break;
- }
- if (LOGV) {
- Log.v(TAG, "\n" + tag.toString());
- }
- }
-
- private void parseTiffHeader() throws IOException,
- ExifInvalidFormatException {
- short byteOrder = mTiffStream.readShort();
- if (LITTLE_ENDIAN_TAG == byteOrder) {
- mTiffStream.setByteOrder(ByteOrder.LITTLE_ENDIAN);
- } else if (BIG_ENDIAN_TAG == byteOrder) {
- mTiffStream.setByteOrder(ByteOrder.BIG_ENDIAN);
- } else {
- throw new ExifInvalidFormatException("Invalid TIFF header");
- }
-
- if (mTiffStream.readShort() != TIFF_HEADER_TAIL) {
- throw new ExifInvalidFormatException("Invalid TIFF header");
- }
- }
-
- private boolean seekTiffData(InputStream inputStream) throws IOException,
- ExifInvalidFormatException {
- CountedDataInputStream dataStream = new CountedDataInputStream(inputStream);
- if (dataStream.readShort() != JpegHeader.SOI) {
- throw new ExifInvalidFormatException("Invalid JPEG format");
- }
-
- short marker = dataStream.readShort();
- while (marker != JpegHeader.EOI
- && !JpegHeader.isSofMarker(marker)) {
- int length = dataStream.readUnsignedShort();
- // Some invalid formatted image contains multiple APP1,
- // try to find the one with Exif data.
- if (marker == JpegHeader.APP1) {
- int header = 0;
- short headerTail = 0;
- if (length >= 8) {
- header = dataStream.readInt();
- headerTail = dataStream.readShort();
- length -= 6;
- if (header == EXIF_HEADER && headerTail == EXIF_HEADER_TAIL) {
- mTiffStartPosition = dataStream.getReadByteCount();
- mApp1End = length;
- mOffsetToApp1EndFromSOF = mTiffStartPosition + mApp1End;
- return true;
- }
- }
- }
- if (length < 2 || (length - 2) != dataStream.skip(length - 2)) {
- Log.w(TAG, "Invalid JPEG format.");
- return false;
- }
- marker = dataStream.readShort();
- }
- return false;
- }
-
- protected int getOffsetToExifEndFromSOF() {
- return mOffsetToApp1EndFromSOF;
- }
-
- protected int getTiffStartPosition() {
- return mTiffStartPosition;
- }
-
- /**
- * Reads bytes from the InputStream.
- */
- protected int read(byte[] buffer, int offset, int length) throws IOException {
- return mTiffStream.read(buffer, offset, length);
- }
-
- /**
- * Equivalent to read(buffer, 0, buffer.length).
- */
- protected int read(byte[] buffer) throws IOException {
- return mTiffStream.read(buffer);
- }
-
- /**
- * Reads a String from the InputStream with US-ASCII charset. The parser
- * will read n bytes and convert it to ascii string. This is used for
- * reading values of type {@link ExifTag#TYPE_ASCII}.
- */
- protected String readString(int n) throws IOException {
- return readString(n, US_ASCII);
- }
-
- /**
- * Reads a String from the InputStream with the given charset. The parser
- * will read n bytes and convert it to string. This is used for reading
- * values of type {@link ExifTag#TYPE_ASCII}.
- */
- protected String readString(int n, Charset charset) throws IOException {
- if (n > 0) {
- return mTiffStream.readString(n, charset);
- } else {
- return "";
- }
- }
-
- /**
- * Reads value of type {@link ExifTag#TYPE_UNSIGNED_SHORT} from the
- * InputStream.
- */
- protected int readUnsignedShort() throws IOException {
- return mTiffStream.readShort() & 0xffff;
- }
-
- /**
- * Reads value of type {@link ExifTag#TYPE_UNSIGNED_LONG} from the
- * InputStream.
- */
- protected long readUnsignedLong() throws IOException {
- return readLong() & 0xffffffffL;
- }
-
- /**
- * Reads value of type {@link ExifTag#TYPE_UNSIGNED_RATIONAL} from the
- * InputStream.
- */
- protected Rational readUnsignedRational() throws IOException {
- long nomi = readUnsignedLong();
- long denomi = readUnsignedLong();
- return new Rational(nomi, denomi);
- }
-
- /**
- * Reads value of type {@link ExifTag#TYPE_LONG} from the InputStream.
- */
- protected int readLong() throws IOException {
- return mTiffStream.readInt();
- }
-
- /**
- * Reads value of type {@link ExifTag#TYPE_RATIONAL} from the InputStream.
- */
- protected Rational readRational() throws IOException {
- int nomi = readLong();
- int denomi = readLong();
- return new Rational(nomi, denomi);
- }
-
- private static class ImageEvent {
- int stripIndex;
- int type;
-
- ImageEvent(int type) {
- this.stripIndex = 0;
- this.type = type;
- }
-
- ImageEvent(int type, int stripIndex) {
- this.type = type;
- this.stripIndex = stripIndex;
- }
- }
-
- private static class IfdEvent {
- int ifd;
- boolean isRequested;
-
- IfdEvent(int ifd, boolean isInterestedIfd) {
- this.ifd = ifd;
- this.isRequested = isInterestedIfd;
- }
- }
-
- private static class ExifTagEvent {
- ExifTag tag;
- boolean isRequested;
-
- ExifTagEvent(ExifTag tag, boolean isRequireByUser) {
- this.tag = tag;
- this.isRequested = isRequireByUser;
- }
- }
-
- /**
- * Gets the byte order of the current InputStream.
- */
- protected ByteOrder getByteOrder() {
- return mTiffStream.getByteOrder();
- }
-}
diff --git a/WallpaperPicker/src/com/android/gallery3d/exif/ExifReader.java b/WallpaperPicker/src/com/android/gallery3d/exif/ExifReader.java
deleted file mode 100644
index 68e972fb7..000000000
--- a/WallpaperPicker/src/com/android/gallery3d/exif/ExifReader.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2012 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.exif;
-
-import android.util.Log;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * This class reads the EXIF header of a JPEG file and stores it in
- * {@link ExifData}.
- */
-class ExifReader {
- private static final String TAG = "ExifReader";
-
- private final ExifInterface mInterface;
-
- ExifReader(ExifInterface iRef) {
- mInterface = iRef;
- }
-
- /**
- * Parses the inputStream and and returns the EXIF data in an
- * {@link ExifData}.
- *
- * @throws ExifInvalidFormatException
- * @throws IOException
- */
- protected ExifData read(InputStream inputStream) throws ExifInvalidFormatException,
- IOException {
- ExifParser parser = ExifParser.parse(inputStream, mInterface);
- ExifData exifData = new ExifData(parser.getByteOrder());
- ExifTag tag = null;
-
- int event = parser.next();
- while (event != ExifParser.EVENT_END) {
- switch (event) {
- case ExifParser.EVENT_START_OF_IFD:
- exifData.addIfdData(new IfdData(parser.getCurrentIfd()));
- break;
- case ExifParser.EVENT_NEW_TAG:
- tag = parser.getTag();
- if (!tag.hasValue()) {
- parser.registerForTagValue(tag);
- } else {
- exifData.getIfdData(tag.getIfd()).setTag(tag);
- }
- break;
- case ExifParser.EVENT_VALUE_OF_REGISTERED_TAG:
- tag = parser.getTag();
- if (tag.getDataType() == ExifTag.TYPE_UNDEFINED) {
- parser.readFullTagValue(tag);
- }
- exifData.getIfdData(tag.getIfd()).setTag(tag);
- break;
- case ExifParser.EVENT_COMPRESSED_IMAGE:
- byte buf[] = new byte[parser.getCompressedImageSize()];
- if (buf.length == parser.read(buf)) {
- exifData.setCompressedThumbnail(buf);
- } else {
- Log.w(TAG, "Failed to read the compressed thumbnail");
- }
- break;
- case ExifParser.EVENT_UNCOMPRESSED_STRIP:
- buf = new byte[parser.getStripSize()];
- if (buf.length == parser.read(buf)) {
- exifData.setStripBytes(parser.getStripIndex(), buf);
- } else {
- Log.w(TAG, "Failed to read the strip bytes");
- }
- break;
- }
- event = parser.next();
- }
- return exifData;
- }
-}
diff --git a/WallpaperPicker/src/com/android/gallery3d/exif/ExifTag.java b/WallpaperPicker/src/com/android/gallery3d/exif/ExifTag.java
deleted file mode 100644
index b8b387201..000000000
--- a/WallpaperPicker/src/com/android/gallery3d/exif/ExifTag.java
+++ /dev/null
@@ -1,1008 +0,0 @@
-/*
- * Copyright (C) 2012 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.exif;
-
-import java.nio.charset.Charset;
-import java.text.SimpleDateFormat;
-import java.util.Arrays;
-import java.util.Date;
-
-/**
- * This class stores information of an EXIF tag. For more information about
- * defined EXIF tags, please read the Jeita EXIF 2.2 standard. Tags should be
- * instantiated using {@link ExifInterface#buildTag}.
- *
- * @see ExifInterface
- */
-public class ExifTag {
- /**
- * The BYTE type in the EXIF standard. An 8-bit unsigned integer.
- */
- public static final short TYPE_UNSIGNED_BYTE = 1;
- /**
- * The ASCII type in the EXIF standard. An 8-bit byte containing one 7-bit
- * ASCII code. The final byte is terminated with NULL.
- */
- public static final short TYPE_ASCII = 2;
- /**
- * The SHORT type in the EXIF standard. A 16-bit (2-byte) unsigned integer
- */
- public static final short TYPE_UNSIGNED_SHORT = 3;
- /**
- * The LONG type in the EXIF standard. A 32-bit (4-byte) unsigned integer
- */
- public static final short TYPE_UNSIGNED_LONG = 4;
- /**
- * The RATIONAL type of EXIF standard. It consists of two LONGs. The first
- * one is the numerator and the second one expresses the denominator.
- */
- public static final short TYPE_UNSIGNED_RATIONAL = 5;
- /**
- * The UNDEFINED type in the EXIF standard. An 8-bit byte that can take any
- * value depending on the field definition.
- */
- public static final short TYPE_UNDEFINED = 7;
- /**
- * The SLONG type in the EXIF standard. A 32-bit (4-byte) signed integer
- * (2's complement notation).
- */
- public static final short TYPE_LONG = 9;
- /**
- * The SRATIONAL type of EXIF standard. It consists of two SLONGs. The first
- * one is the numerator and the second one is the denominator.
- */
- public static final short TYPE_RATIONAL = 10;
-
- private static Charset US_ASCII = Charset.forName("US-ASCII");
- private static final int TYPE_TO_SIZE_MAP[] = new int[11];
- private static final int UNSIGNED_SHORT_MAX = 65535;
- private static final long UNSIGNED_LONG_MAX = 4294967295L;
- private static final long LONG_MAX = Integer.MAX_VALUE;
- private static final long LONG_MIN = Integer.MIN_VALUE;
-
- static {
- TYPE_TO_SIZE_MAP[TYPE_UNSIGNED_BYTE] = 1;
- TYPE_TO_SIZE_MAP[TYPE_ASCII] = 1;
- TYPE_TO_SIZE_MAP[TYPE_UNSIGNED_SHORT] = 2;
- TYPE_TO_SIZE_MAP[TYPE_UNSIGNED_LONG] = 4;
- TYPE_TO_SIZE_MAP[TYPE_UNSIGNED_RATIONAL] = 8;
- TYPE_TO_SIZE_MAP[TYPE_UNDEFINED] = 1;
- TYPE_TO_SIZE_MAP[TYPE_LONG] = 4;
- TYPE_TO_SIZE_MAP[TYPE_RATIONAL] = 8;
- }
-
- static final int SIZE_UNDEFINED = 0;
-
- // Exif TagId
- private final short mTagId;
- // Exif Tag Type
- private final short mDataType;
- // If tag has defined count
- private boolean mHasDefinedDefaultComponentCount;
- // Actual data count in tag (should be number of elements in value array)
- private int mComponentCountActual;
- // The ifd that this tag should be put in
- private int mIfd;
- // The value (array of elements of type Tag Type)
- private Object mValue;
- // Value offset in exif header.
- private int mOffset;
-
- private static final SimpleDateFormat TIME_FORMAT = new SimpleDateFormat("yyyy:MM:dd kk:mm:ss");
-
- /**
- * Returns true if the given IFD is a valid IFD.
- */
- public static boolean isValidIfd(int ifdId) {
- return ifdId == IfdId.TYPE_IFD_0 || ifdId == IfdId.TYPE_IFD_1
- || ifdId == IfdId.TYPE_IFD_EXIF || ifdId == IfdId.TYPE_IFD_INTEROPERABILITY
- || ifdId == IfdId.TYPE_IFD_GPS;
- }
-
- /**
- * Returns true if a given type is a valid tag type.
- */
- public static boolean isValidType(short type) {
- return type == TYPE_UNSIGNED_BYTE || type == TYPE_ASCII ||
- type == TYPE_UNSIGNED_SHORT || type == TYPE_UNSIGNED_LONG ||
- type == TYPE_UNSIGNED_RATIONAL || type == TYPE_UNDEFINED ||
- type == TYPE_LONG || type == TYPE_RATIONAL;
- }
-
- // Use builtTag in ExifInterface instead of constructor.
- ExifTag(short tagId, short type, int componentCount, int ifd,
- boolean hasDefinedComponentCount) {
- mTagId = tagId;
- mDataType = type;
- mComponentCountActual = componentCount;
- mHasDefinedDefaultComponentCount = hasDefinedComponentCount;
- mIfd = ifd;
- mValue = null;
- }
-
- /**
- * Gets the element size of the given data type in bytes.
- *
- * @see #TYPE_ASCII
- * @see #TYPE_LONG
- * @see #TYPE_RATIONAL
- * @see #TYPE_UNDEFINED
- * @see #TYPE_UNSIGNED_BYTE
- * @see #TYPE_UNSIGNED_LONG
- * @see #TYPE_UNSIGNED_RATIONAL
- * @see #TYPE_UNSIGNED_SHORT
- */
- public static int getElementSize(short type) {
- return TYPE_TO_SIZE_MAP[type];
- }
-
- /**
- * Returns the ID of the IFD this tag belongs to.
- *
- * @see IfdId#TYPE_IFD_0
- * @see IfdId#TYPE_IFD_1
- * @see IfdId#TYPE_IFD_EXIF
- * @see IfdId#TYPE_IFD_GPS
- * @see IfdId#TYPE_IFD_INTEROPERABILITY
- */
- public int getIfd() {
- return mIfd;
- }
-
- protected void setIfd(int ifdId) {
- mIfd = ifdId;
- }
-
- /**
- * Gets the TID of this tag.
- */
- public short getTagId() {
- return mTagId;
- }
-
- /**
- * Gets the data type of this tag
- *
- * @see #TYPE_ASCII
- * @see #TYPE_LONG
- * @see #TYPE_RATIONAL
- * @see #TYPE_UNDEFINED
- * @see #TYPE_UNSIGNED_BYTE
- * @see #TYPE_UNSIGNED_LONG
- * @see #TYPE_UNSIGNED_RATIONAL
- * @see #TYPE_UNSIGNED_SHORT
- */
- public short getDataType() {
- return mDataType;
- }
-
- /**
- * Gets the total data size in bytes of the value of this tag.
- */
- public int getDataSize() {
- return getComponentCount() * getElementSize(getDataType());
- }
-
- /**
- * Gets the component count of this tag.
- */
-
- // TODO: fix integer overflows with this
- public int getComponentCount() {
- return mComponentCountActual;
- }
-
- /**
- * Sets the component count of this tag. Call this function before
- * setValue() if the length of value does not match the component count.
- */
- protected void forceSetComponentCount(int count) {
- mComponentCountActual = count;
- }
-
- /**
- * Returns true if this ExifTag contains value; otherwise, this tag will
- * contain an offset value that is determined when the tag is written.
- */
- public boolean hasValue() {
- return mValue != null;
- }
-
- /**
- * Sets integer values into this tag. This method should be used for tags of
- * type {@link #TYPE_UNSIGNED_SHORT}. This method will fail if:
- * <ul>
- * <li>The component type of this tag is not {@link #TYPE_UNSIGNED_SHORT},
- * {@link #TYPE_UNSIGNED_LONG}, or {@link #TYPE_LONG}.</li>
- * <li>The value overflows.</li>
- * <li>The value.length does NOT match the component count in the definition
- * for this tag.</li>
- * </ul>
- */
- public boolean setValue(int[] value) {
- if (checkBadComponentCount(value.length)) {
- return false;
- }
- if (mDataType != TYPE_UNSIGNED_SHORT && mDataType != TYPE_LONG &&
- mDataType != TYPE_UNSIGNED_LONG) {
- return false;
- }
- if (mDataType == TYPE_UNSIGNED_SHORT && checkOverflowForUnsignedShort(value)) {
- return false;
- } else if (mDataType == TYPE_UNSIGNED_LONG && checkOverflowForUnsignedLong(value)) {
- return false;
- }
-
- long[] data = new long[value.length];
- for (int i = 0; i < value.length; i++) {
- data[i] = value[i];
- }
- mValue = data;
- mComponentCountActual = value.length;
- return true;
- }
-
- /**
- * Sets integer value into this tag. This method should be used for tags of
- * type {@link #TYPE_UNSIGNED_SHORT}, or {@link #TYPE_LONG}. This method
- * will fail if:
- * <ul>
- * <li>The component type of this tag is not {@link #TYPE_UNSIGNED_SHORT},
- * {@link #TYPE_UNSIGNED_LONG}, or {@link #TYPE_LONG}.</li>
- * <li>The value overflows.</li>
- * <li>The component count in the definition of this tag is not 1.</li>
- * </ul>
- */
- public boolean setValue(int value) {
- return setValue(new int[] {
- value
- });
- }
-
- /**
- * Sets long values into this tag. This method should be used for tags of
- * type {@link #TYPE_UNSIGNED_LONG}. This method will fail if:
- * <ul>
- * <li>The component type of this tag is not {@link #TYPE_UNSIGNED_LONG}.</li>
- * <li>The value overflows.</li>
- * <li>The value.length does NOT match the component count in the definition
- * for this tag.</li>
- * </ul>
- */
- public boolean setValue(long[] value) {
- if (checkBadComponentCount(value.length) || mDataType != TYPE_UNSIGNED_LONG) {
- return false;
- }
- if (checkOverflowForUnsignedLong(value)) {
- return false;
- }
- mValue = value;
- mComponentCountActual = value.length;
- return true;
- }
-
- /**
- * Sets long values into this tag. This method should be used for tags of
- * type {@link #TYPE_UNSIGNED_LONG}. This method will fail if:
- * <ul>
- * <li>The component type of this tag is not {@link #TYPE_UNSIGNED_LONG}.</li>
- * <li>The value overflows.</li>
- * <li>The component count in the definition for this tag is not 1.</li>
- * </ul>
- */
- public boolean setValue(long value) {
- return setValue(new long[] {
- value
- });
- }
-
- /**
- * Sets a string value into this tag. This method should be used for tags of
- * type {@link #TYPE_ASCII}. The string is converted to an ASCII string.
- * Characters that cannot be converted are replaced with '?'. The length of
- * the string must be equal to either (component count -1) or (component
- * count). The final byte will be set to the string null terminator '\0',
- * overwriting the last character in the string if the value.length is equal
- * to the component count. This method will fail if:
- * <ul>
- * <li>The data type is not {@link #TYPE_ASCII} or {@link #TYPE_UNDEFINED}.</li>
- * <li>The length of the string is not equal to (component count -1) or
- * (component count) in the definition for this tag.</li>
- * </ul>
- */
- public boolean setValue(String value) {
- if (mDataType != TYPE_ASCII && mDataType != TYPE_UNDEFINED) {
- return false;
- }
-
- byte[] buf = value.getBytes(US_ASCII);
- byte[] finalBuf = buf;
- if (buf.length > 0) {
- finalBuf = (buf[buf.length - 1] == 0 || mDataType == TYPE_UNDEFINED) ? buf : Arrays
- .copyOf(buf, buf.length + 1);
- } else if (mDataType == TYPE_ASCII && mComponentCountActual == 1) {
- finalBuf = new byte[] { 0 };
- }
- int count = finalBuf.length;
- if (checkBadComponentCount(count)) {
- return false;
- }
- mComponentCountActual = count;
- mValue = finalBuf;
- return true;
- }
-
- /**
- * Sets Rational values into this tag. This method should be used for tags
- * of type {@link #TYPE_UNSIGNED_RATIONAL}, or {@link #TYPE_RATIONAL}. This
- * method will fail if:
- * <ul>
- * <li>The component type of this tag is not {@link #TYPE_UNSIGNED_RATIONAL}
- * or {@link #TYPE_RATIONAL}.</li>
- * <li>The value overflows.</li>
- * <li>The value.length does NOT match the component count in the definition
- * for this tag.</li>
- * </ul>
- *
- * @see Rational
- */
- public boolean setValue(Rational[] value) {
- if (checkBadComponentCount(value.length)) {
- return false;
- }
- if (mDataType != TYPE_UNSIGNED_RATIONAL && mDataType != TYPE_RATIONAL) {
- return false;
- }
- if (mDataType == TYPE_UNSIGNED_RATIONAL && checkOverflowForUnsignedRational(value)) {
- return false;
- } else if (mDataType == TYPE_RATIONAL && checkOverflowForRational(value)) {
- return false;
- }
-
- mValue = value;
- mComponentCountActual = value.length;
- return true;
- }
-
- /**
- * Sets a Rational value into this tag. This method should be used for tags
- * of type {@link #TYPE_UNSIGNED_RATIONAL}, or {@link #TYPE_RATIONAL}. This
- * method will fail if:
- * <ul>
- * <li>The component type of this tag is not {@link #TYPE_UNSIGNED_RATIONAL}
- * or {@link #TYPE_RATIONAL}.</li>
- * <li>The value overflows.</li>
- * <li>The component count in the definition for this tag is not 1.</li>
- * </ul>
- *
- * @see Rational
- */
- public boolean setValue(Rational value) {
- return setValue(new Rational[] {
- value
- });
- }
-
- /**
- * Sets byte values into this tag. This method should be used for tags of
- * type {@link #TYPE_UNSIGNED_BYTE} or {@link #TYPE_UNDEFINED}. This method
- * will fail if:
- * <ul>
- * <li>The component type of this tag is not {@link #TYPE_UNSIGNED_BYTE} or
- * {@link #TYPE_UNDEFINED} .</li>
- * <li>The length does NOT match the component count in the definition for
- * this tag.</li>
- * </ul>
- */
- public boolean setValue(byte[] value, int offset, int length) {
- if (checkBadComponentCount(length)) {
- return false;
- }
- if (mDataType != TYPE_UNSIGNED_BYTE && mDataType != TYPE_UNDEFINED) {
- return false;
- }
- mValue = new byte[length];
- System.arraycopy(value, offset, mValue, 0, length);
- mComponentCountActual = length;
- return true;
- }
-
- /**
- * Equivalent to setValue(value, 0, value.length).
- */
- public boolean setValue(byte[] value) {
- return setValue(value, 0, value.length);
- }
-
- /**
- * Sets byte value into this tag. This method should be used for tags of
- * type {@link #TYPE_UNSIGNED_BYTE} or {@link #TYPE_UNDEFINED}. This method
- * will fail if:
- * <ul>
- * <li>The component type of this tag is not {@link #TYPE_UNSIGNED_BYTE} or
- * {@link #TYPE_UNDEFINED} .</li>
- * <li>The component count in the definition for this tag is not 1.</li>
- * </ul>
- */
- public boolean setValue(byte value) {
- return setValue(new byte[] {
- value
- });
- }
-
- /**
- * Sets the value for this tag using an appropriate setValue method for the
- * given object. This method will fail if:
- * <ul>
- * <li>The corresponding setValue method for the class of the object passed
- * in would fail.</li>
- * <li>There is no obvious way to cast the object passed in into an EXIF tag
- * type.</li>
- * </ul>
- */
- public boolean setValue(Object obj) {
- if (obj == null) {
- return false;
- } else if (obj instanceof Short) {
- return setValue(((Short) obj).shortValue() & 0x0ffff);
- } else if (obj instanceof String) {
- return setValue((String) obj);
- } else if (obj instanceof int[]) {
- return setValue((int[]) obj);
- } else if (obj instanceof long[]) {
- return setValue((long[]) obj);
- } else if (obj instanceof Rational) {
- return setValue((Rational) obj);
- } else if (obj instanceof Rational[]) {
- return setValue((Rational[]) obj);
- } else if (obj instanceof byte[]) {
- return setValue((byte[]) obj);
- } else if (obj instanceof Integer) {
- return setValue(((Integer) obj).intValue());
- } else if (obj instanceof Long) {
- return setValue(((Long) obj).longValue());
- } else if (obj instanceof Byte) {
- return setValue(((Byte) obj).byteValue());
- } else if (obj instanceof Short[]) {
- // Nulls in this array are treated as zeroes.
- Short[] arr = (Short[]) obj;
- int[] fin = new int[arr.length];
- for (int i = 0; i < arr.length; i++) {
- fin[i] = (arr[i] == null) ? 0 : arr[i].shortValue() & 0x0ffff;
- }
- return setValue(fin);
- } else if (obj instanceof Integer[]) {
- // Nulls in this array are treated as zeroes.
- Integer[] arr = (Integer[]) obj;
- int[] fin = new int[arr.length];
- for (int i = 0; i < arr.length; i++) {
- fin[i] = (arr[i] == null) ? 0 : arr[i].intValue();
- }
- return setValue(fin);
- } else if (obj instanceof Long[]) {
- // Nulls in this array are treated as zeroes.
- Long[] arr = (Long[]) obj;
- long[] fin = new long[arr.length];
- for (int i = 0; i < arr.length; i++) {
- fin[i] = (arr[i] == null) ? 0 : arr[i].longValue();
- }
- return setValue(fin);
- } else if (obj instanceof Byte[]) {
- // Nulls in this array are treated as zeroes.
- Byte[] arr = (Byte[]) obj;
- byte[] fin = new byte[arr.length];
- for (int i = 0; i < arr.length; i++) {
- fin[i] = (arr[i] == null) ? 0 : arr[i].byteValue();
- }
- return setValue(fin);
- } else {
- return false;
- }
- }
-
- /**
- * Sets a timestamp to this tag. The method converts the timestamp with the
- * format of "yyyy:MM:dd kk:mm:ss" and calls {@link #setValue(String)}. This
- * method will fail if the data type is not {@link #TYPE_ASCII} or the
- * component count of this tag is not 20 or undefined.
- *
- * @param time the number of milliseconds since Jan. 1, 1970 GMT
- * @return true on success
- */
- public boolean setTimeValue(long time) {
- // synchronized on TIME_FORMAT as SimpleDateFormat is not thread safe
- synchronized (TIME_FORMAT) {
- return setValue(TIME_FORMAT.format(new Date(time)));
- }
- }
-
- /**
- * Gets the value as a String. This method should be used for tags of type
- * {@link #TYPE_ASCII}.
- *
- * @return the value as a String, or null if the tag's value does not exist
- * or cannot be converted to a String.
- */
- public String getValueAsString() {
- if (mValue == null) {
- return null;
- } else if (mValue instanceof String) {
- return (String) mValue;
- } else if (mValue instanceof byte[]) {
- return new String((byte[]) mValue, US_ASCII);
- }
- return null;
- }
-
- /**
- * Gets the value as a String. This method should be used for tags of type
- * {@link #TYPE_ASCII}.
- *
- * @param defaultValue the String to return if the tag's value does not
- * exist or cannot be converted to a String.
- * @return the tag's value as a String, or the defaultValue.
- */
- public String getValueAsString(String defaultValue) {
- String s = getValueAsString();
- if (s == null) {
- return defaultValue;
- }
- return s;
- }
-
- /**
- * Gets the value as a byte array. This method should be used for tags of
- * type {@link #TYPE_UNDEFINED} or {@link #TYPE_UNSIGNED_BYTE}.
- *
- * @return the value as a byte array, or null if the tag's value does not
- * exist or cannot be converted to a byte array.
- */
- public byte[] getValueAsBytes() {
- if (mValue instanceof byte[]) {
- return (byte[]) mValue;
- }
- return null;
- }
-
- /**
- * Gets the value as a byte. If there are more than 1 bytes in this value,
- * gets the first byte. This method should be used for tags of type
- * {@link #TYPE_UNDEFINED} or {@link #TYPE_UNSIGNED_BYTE}.
- *
- * @param defaultValue the byte to return if tag's value does not exist or
- * cannot be converted to a byte.
- * @return the tag's value as a byte, or the defaultValue.
- */
- public byte getValueAsByte(byte defaultValue) {
- byte[] b = getValueAsBytes();
- if (b == null || b.length < 1) {
- return defaultValue;
- }
- return b[0];
- }
-
- /**
- * Gets the value as an array of Rationals. This method should be used for
- * tags of type {@link #TYPE_RATIONAL} or {@link #TYPE_UNSIGNED_RATIONAL}.
- *
- * @return the value as as an array of Rationals, or null if the tag's value
- * does not exist or cannot be converted to an array of Rationals.
- */
- public Rational[] getValueAsRationals() {
- if (mValue instanceof Rational[]) {
- return (Rational[]) mValue;
- }
- return null;
- }
-
- /**
- * Gets the value as a Rational. If there are more than 1 Rationals in this
- * value, gets the first one. This method should be used for tags of type
- * {@link #TYPE_RATIONAL} or {@link #TYPE_UNSIGNED_RATIONAL}.
- *
- * @param defaultValue the Rational to return if tag's value does not exist
- * or cannot be converted to a Rational.
- * @return the tag's value as a Rational, or the defaultValue.
- */
- public Rational getValueAsRational(Rational defaultValue) {
- Rational[] r = getValueAsRationals();
- if (r == null || r.length < 1) {
- return defaultValue;
- }
- return r[0];
- }
-
- /**
- * Gets the value as a Rational. If there are more than 1 Rationals in this
- * value, gets the first one. This method should be used for tags of type
- * {@link #TYPE_RATIONAL} or {@link #TYPE_UNSIGNED_RATIONAL}.
- *
- * @param defaultValue the numerator of the Rational to return if tag's
- * value does not exist or cannot be converted to a Rational (the
- * denominator will be 1).
- * @return the tag's value as a Rational, or the defaultValue.
- */
- public Rational getValueAsRational(long defaultValue) {
- Rational defaultVal = new Rational(defaultValue, 1);
- return getValueAsRational(defaultVal);
- }
-
- /**
- * Gets the value as an array of ints. This method should be used for tags
- * of type {@link #TYPE_UNSIGNED_SHORT}, {@link #TYPE_UNSIGNED_LONG}.
- *
- * @return the value as as an array of ints, or null if the tag's value does
- * not exist or cannot be converted to an array of ints.
- */
- public int[] getValueAsInts() {
- if (mValue == null) {
- return null;
- } else if (mValue instanceof long[]) {
- long[] val = (long[]) mValue;
- int[] arr = new int[val.length];
- for (int i = 0; i < val.length; i++) {
- arr[i] = (int) val[i]; // Truncates
- }
- return arr;
- }
- return null;
- }
-
- /**
- * Gets the value as an int. If there are more than 1 ints in this value,
- * gets the first one. This method should be used for tags of type
- * {@link #TYPE_UNSIGNED_SHORT}, {@link #TYPE_UNSIGNED_LONG}.
- *
- * @param defaultValue the int to return if tag's value does not exist or
- * cannot be converted to an int.
- * @return the tag's value as a int, or the defaultValue.
- */
- public int getValueAsInt(int defaultValue) {
- int[] i = getValueAsInts();
- if (i == null || i.length < 1) {
- return defaultValue;
- }
- return i[0];
- }
-
- /**
- * Gets the value as an array of longs. This method should be used for tags
- * of type {@link #TYPE_UNSIGNED_LONG}.
- *
- * @return the value as as an array of longs, or null if the tag's value
- * does not exist or cannot be converted to an array of longs.
- */
- public long[] getValueAsLongs() {
- if (mValue instanceof long[]) {
- return (long[]) mValue;
- }
- return null;
- }
-
- /**
- * Gets the value or null if none exists. If there are more than 1 longs in
- * this value, gets the first one. This method should be used for tags of
- * type {@link #TYPE_UNSIGNED_LONG}.
- *
- * @param defaultValue the long to return if tag's value does not exist or
- * cannot be converted to a long.
- * @return the tag's value as a long, or the defaultValue.
- */
- public long getValueAsLong(long defaultValue) {
- long[] l = getValueAsLongs();
- if (l == null || l.length < 1) {
- return defaultValue;
- }
- return l[0];
- }
-
- /**
- * Gets the tag's value or null if none exists.
- */
- public Object getValue() {
- return mValue;
- }
-
- /**
- * Gets a long representation of the value.
- *
- * @param defaultValue value to return if there is no value or value is a
- * rational with a denominator of 0.
- * @return the tag's value as a long, or defaultValue if no representation
- * exists.
- */
- public long forceGetValueAsLong(long defaultValue) {
- long[] l = getValueAsLongs();
- if (l != null && l.length >= 1) {
- return l[0];
- }
- byte[] b = getValueAsBytes();
- if (b != null && b.length >= 1) {
- return b[0];
- }
- Rational[] r = getValueAsRationals();
- if (r != null && r.length >= 1 && r[0].getDenominator() != 0) {
- return (long) r[0].toDouble();
- }
- return defaultValue;
- }
-
- /**
- * Gets a string representation of the value.
- */
- public String forceGetValueAsString() {
- if (mValue == null) {
- return "";
- } else if (mValue instanceof byte[]) {
- if (mDataType == TYPE_ASCII) {
- return new String((byte[]) mValue, US_ASCII);
- } else {
- return Arrays.toString((byte[]) mValue);
- }
- } else if (mValue instanceof long[]) {
- if (((long[]) mValue).length == 1) {
- return String.valueOf(((long[]) mValue)[0]);
- } else {
- return Arrays.toString((long[]) mValue);
- }
- } else if (mValue instanceof Object[]) {
- if (((Object[]) mValue).length == 1) {
- Object val = ((Object[]) mValue)[0];
- if (val == null) {
- return "";
- } else {
- return val.toString();
- }
- } else {
- return Arrays.toString((Object[]) mValue);
- }
- } else {
- return mValue.toString();
- }
- }
-
- /**
- * Gets the value for type {@link #TYPE_ASCII}, {@link #TYPE_LONG},
- * {@link #TYPE_UNDEFINED}, {@link #TYPE_UNSIGNED_BYTE},
- * {@link #TYPE_UNSIGNED_LONG}, or {@link #TYPE_UNSIGNED_SHORT}. For
- * {@link #TYPE_RATIONAL} or {@link #TYPE_UNSIGNED_RATIONAL}, call
- * {@link #getRational(int)} instead.
- *
- * @exception IllegalArgumentException if the data type is
- * {@link #TYPE_RATIONAL} or {@link #TYPE_UNSIGNED_RATIONAL}.
- */
- protected long getValueAt(int index) {
- if (mValue instanceof long[]) {
- return ((long[]) mValue)[index];
- } else if (mValue instanceof byte[]) {
- return ((byte[]) mValue)[index];
- }
- throw new IllegalArgumentException("Cannot get integer value from "
- + convertTypeToString(mDataType));
- }
-
- /**
- * Gets the {@link #TYPE_ASCII} data.
- *
- * @exception IllegalArgumentException If the type is NOT
- * {@link #TYPE_ASCII}.
- */
- protected String getString() {
- if (mDataType != TYPE_ASCII) {
- throw new IllegalArgumentException("Cannot get ASCII value from "
- + convertTypeToString(mDataType));
- }
- return new String((byte[]) mValue, US_ASCII);
- }
-
- /*
- * Get the converted ascii byte. Used by ExifOutputStream.
- */
- protected byte[] getStringByte() {
- return (byte[]) mValue;
- }
-
- /**
- * Gets the {@link #TYPE_RATIONAL} or {@link #TYPE_UNSIGNED_RATIONAL} data.
- *
- * @exception IllegalArgumentException If the type is NOT
- * {@link #TYPE_RATIONAL} or {@link #TYPE_UNSIGNED_RATIONAL}.
- */
- protected Rational getRational(int index) {
- if ((mDataType != TYPE_RATIONAL) && (mDataType != TYPE_UNSIGNED_RATIONAL)) {
- throw new IllegalArgumentException("Cannot get RATIONAL value from "
- + convertTypeToString(mDataType));
- }
- return ((Rational[]) mValue)[index];
- }
-
- /**
- * Equivalent to getBytes(buffer, 0, buffer.length).
- */
- protected void getBytes(byte[] buf) {
- getBytes(buf, 0, buf.length);
- }
-
- /**
- * Gets the {@link #TYPE_UNDEFINED} or {@link #TYPE_UNSIGNED_BYTE} data.
- *
- * @param buf the byte array in which to store the bytes read.
- * @param offset the initial position in buffer to store the bytes.
- * @param length the maximum number of bytes to store in buffer. If length >
- * component count, only the valid bytes will be stored.
- * @exception IllegalArgumentException If the type is NOT
- * {@link #TYPE_UNDEFINED} or {@link #TYPE_UNSIGNED_BYTE}.
- */
- protected void getBytes(byte[] buf, int offset, int length) {
- if ((mDataType != TYPE_UNDEFINED) && (mDataType != TYPE_UNSIGNED_BYTE)) {
- throw new IllegalArgumentException("Cannot get BYTE value from "
- + convertTypeToString(mDataType));
- }
- System.arraycopy(mValue, 0, buf, offset,
- (length > mComponentCountActual) ? mComponentCountActual : length);
- }
-
- /**
- * Gets the offset of this tag. This is only valid if this data size > 4 and
- * contains an offset to the location of the actual value.
- */
- protected int getOffset() {
- return mOffset;
- }
-
- /**
- * Sets the offset of this tag.
- */
- protected void setOffset(int offset) {
- mOffset = offset;
- }
-
- protected void setHasDefinedCount(boolean d) {
- mHasDefinedDefaultComponentCount = d;
- }
-
- protected boolean hasDefinedCount() {
- return mHasDefinedDefaultComponentCount;
- }
-
- private boolean checkBadComponentCount(int count) {
- if (mHasDefinedDefaultComponentCount && (mComponentCountActual != count)) {
- return true;
- }
- return false;
- }
-
- private static String convertTypeToString(short type) {
- switch (type) {
- case TYPE_UNSIGNED_BYTE:
- return "UNSIGNED_BYTE";
- case TYPE_ASCII:
- return "ASCII";
- case TYPE_UNSIGNED_SHORT:
- return "UNSIGNED_SHORT";
- case TYPE_UNSIGNED_LONG:
- return "UNSIGNED_LONG";
- case TYPE_UNSIGNED_RATIONAL:
- return "UNSIGNED_RATIONAL";
- case TYPE_UNDEFINED:
- return "UNDEFINED";
- case TYPE_LONG:
- return "LONG";
- case TYPE_RATIONAL:
- return "RATIONAL";
- default:
- return "";
- }
- }
-
- private boolean checkOverflowForUnsignedShort(int[] value) {
- for (int v : value) {
- if (v > UNSIGNED_SHORT_MAX || v < 0) {
- return true;
- }
- }
- return false;
- }
-
- private boolean checkOverflowForUnsignedLong(long[] value) {
- for (long v : value) {
- if (v < 0 || v > UNSIGNED_LONG_MAX) {
- return true;
- }
- }
- return false;
- }
-
- private boolean checkOverflowForUnsignedLong(int[] value) {
- for (int v : value) {
- if (v < 0) {
- return true;
- }
- }
- return false;
- }
-
- private boolean checkOverflowForUnsignedRational(Rational[] value) {
- for (Rational v : value) {
- if (v.getNumerator() < 0 || v.getDenominator() < 0
- || v.getNumerator() > UNSIGNED_LONG_MAX
- || v.getDenominator() > UNSIGNED_LONG_MAX) {
- return true;
- }
- }
- return false;
- }
-
- private boolean checkOverflowForRational(Rational[] value) {
- for (Rational v : value) {
- if (v.getNumerator() < LONG_MIN || v.getDenominator() < LONG_MIN
- || v.getNumerator() > LONG_MAX
- || v.getDenominator() > LONG_MAX) {
- return true;
- }
- }
- return false;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (obj == null) {
- return false;
- }
- if (obj instanceof ExifTag) {
- ExifTag tag = (ExifTag) obj;
- if (tag.mTagId != this.mTagId
- || tag.mComponentCountActual != this.mComponentCountActual
- || tag.mDataType != this.mDataType) {
- return false;
- }
- if (mValue != null) {
- if (tag.mValue == null) {
- return false;
- } else if (mValue instanceof long[]) {
- if (!(tag.mValue instanceof long[])) {
- return false;
- }
- return Arrays.equals((long[]) mValue, (long[]) tag.mValue);
- } else if (mValue instanceof Rational[]) {
- if (!(tag.mValue instanceof Rational[])) {
- return false;
- }
- return Arrays.equals((Rational[]) mValue, (Rational[]) tag.mValue);
- } else if (mValue instanceof byte[]) {
- if (!(tag.mValue instanceof byte[])) {
- return false;
- }
- return Arrays.equals((byte[]) mValue, (byte[]) tag.mValue);
- } else {
- return mValue.equals(tag.mValue);
- }
- } else {
- return tag.mValue == null;
- }
- }
- return false;
- }
-
- @Override
- public String toString() {
- return String.format("tag id: %04X\n", mTagId) + "ifd id: " + mIfd + "\ntype: "
- + convertTypeToString(mDataType) + "\ncount: " + mComponentCountActual
- + "\noffset: " + mOffset + "\nvalue: " + forceGetValueAsString() + "\n";
- }
-
-}
diff --git a/WallpaperPicker/src/com/android/gallery3d/exif/IfdData.java b/WallpaperPicker/src/com/android/gallery3d/exif/IfdData.java
deleted file mode 100644
index 093944aec..000000000
--- a/WallpaperPicker/src/com/android/gallery3d/exif/IfdData.java
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (C) 2012 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.exif;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * This class stores all the tags in an IFD.
- *
- * @see ExifData
- * @see ExifTag
- */
-class IfdData {
-
- private final int mIfdId;
- private final Map<Short, ExifTag> mExifTags = new HashMap<Short, ExifTag>();
- private int mOffsetToNextIfd = 0;
- private static final int[] sIfds = {
- IfdId.TYPE_IFD_0, IfdId.TYPE_IFD_1, IfdId.TYPE_IFD_EXIF,
- IfdId.TYPE_IFD_INTEROPERABILITY, IfdId.TYPE_IFD_GPS
- };
- /**
- * Creates an IfdData with given IFD ID.
- *
- * @see IfdId#TYPE_IFD_0
- * @see IfdId#TYPE_IFD_1
- * @see IfdId#TYPE_IFD_EXIF
- * @see IfdId#TYPE_IFD_GPS
- * @see IfdId#TYPE_IFD_INTEROPERABILITY
- */
- IfdData(int ifdId) {
- mIfdId = ifdId;
- }
-
- static protected int[] getIfds() {
- return sIfds;
- }
-
- /**
- * Get a array the contains all {@link ExifTag} in this IFD.
- */
- protected ExifTag[] getAllTags() {
- return mExifTags.values().toArray(new ExifTag[mExifTags.size()]);
- }
-
- /**
- * Gets the ID of this IFD.
- *
- * @see IfdId#TYPE_IFD_0
- * @see IfdId#TYPE_IFD_1
- * @see IfdId#TYPE_IFD_EXIF
- * @see IfdId#TYPE_IFD_GPS
- * @see IfdId#TYPE_IFD_INTEROPERABILITY
- */
- protected int getId() {
- return mIfdId;
- }
-
- /**
- * Gets the {@link ExifTag} with given tag id. Return null if there is no
- * such tag.
- */
- protected ExifTag getTag(short tagId) {
- return mExifTags.get(tagId);
- }
-
- /**
- * Adds or replaces a {@link ExifTag}.
- */
- protected ExifTag setTag(ExifTag tag) {
- tag.setIfd(mIfdId);
- return mExifTags.put(tag.getTagId(), tag);
- }
-
- protected boolean checkCollision(short tagId) {
- return mExifTags.get(tagId) != null;
- }
-
- /**
- * Removes the tag of the given ID
- */
- protected void removeTag(short tagId) {
- mExifTags.remove(tagId);
- }
-
- /**
- * Gets the tags count in the IFD.
- */
- protected int getTagCount() {
- return mExifTags.size();
- }
-
- /**
- * Sets the offset of next IFD.
- */
- protected void setOffsetToNextIfd(int offset) {
- mOffsetToNextIfd = offset;
- }
-
- /**
- * Gets the offset of next IFD.
- */
- protected int getOffsetToNextIfd() {
- return mOffsetToNextIfd;
- }
-
- /**
- * Returns true if all tags in this two IFDs are equal. Note that tags of
- * IFDs offset or thumbnail offset will be ignored.
- */
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null) {
- return false;
- }
- if (obj instanceof IfdData) {
- IfdData data = (IfdData) obj;
- if (data.getId() == mIfdId && data.getTagCount() == getTagCount()) {
- ExifTag[] tags = data.getAllTags();
- for (ExifTag tag : tags) {
- if (ExifInterface.isOffsetTag(tag.getTagId())) {
- continue;
- }
- ExifTag tag2 = mExifTags.get(tag.getTagId());
- if (!tag.equals(tag2)) {
- return false;
- }
- }
- return true;
- }
- }
- return false;
- }
-}
diff --git a/WallpaperPicker/src/com/android/gallery3d/exif/IfdId.java b/WallpaperPicker/src/com/android/gallery3d/exif/IfdId.java
deleted file mode 100644
index 7842edbd4..000000000
--- a/WallpaperPicker/src/com/android/gallery3d/exif/IfdId.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2012 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.exif;
-
-/**
- * The constants of the IFD ID defined in EXIF spec.
- */
-public interface IfdId {
- public static final int TYPE_IFD_0 = 0;
- public static final int TYPE_IFD_1 = 1;
- public static final int TYPE_IFD_EXIF = 2;
- public static final int TYPE_IFD_INTEROPERABILITY = 3;
- public static final int TYPE_IFD_GPS = 4;
- /* This is used in ExifData to allocate enough IfdData */
- static final int TYPE_IFD_COUNT = 5;
-
-}
diff --git a/WallpaperPicker/src/com/android/gallery3d/exif/JpegHeader.java b/WallpaperPicker/src/com/android/gallery3d/exif/JpegHeader.java
deleted file mode 100644
index e3e787eff..000000000
--- a/WallpaperPicker/src/com/android/gallery3d/exif/JpegHeader.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2012 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.exif;
-
-class JpegHeader {
- public static final short SOI = (short) 0xFFD8;
- public static final short APP1 = (short) 0xFFE1;
- public static final short APP0 = (short) 0xFFE0;
- public static final short EOI = (short) 0xFFD9;
-
- /**
- * SOF (start of frame). All value between SOF0 and SOF15 is SOF marker except for DHT, JPG,
- * and DAC marker.
- */
- public static final short SOF0 = (short) 0xFFC0;
- public static final short SOF15 = (short) 0xFFCF;
- public static final short DHT = (short) 0xFFC4;
- public static final short JPG = (short) 0xFFC8;
- public static final short DAC = (short) 0xFFCC;
-
- public static final boolean isSofMarker(short marker) {
- return marker >= SOF0 && marker <= SOF15 && marker != DHT && marker != JPG
- && marker != DAC;
- }
-}
diff --git a/WallpaperPicker/src/com/android/gallery3d/exif/OrderedDataOutputStream.java b/WallpaperPicker/src/com/android/gallery3d/exif/OrderedDataOutputStream.java
deleted file mode 100644
index 428e6b9fc..000000000
--- a/WallpaperPicker/src/com/android/gallery3d/exif/OrderedDataOutputStream.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2012 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.exif;
-
-import java.io.FilterOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-
-class OrderedDataOutputStream extends FilterOutputStream {
- private final ByteBuffer mByteBuffer = ByteBuffer.allocate(4);
-
- public OrderedDataOutputStream(OutputStream out) {
- super(out);
- }
-
- public OrderedDataOutputStream setByteOrder(ByteOrder order) {
- mByteBuffer.order(order);
- return this;
- }
-
- public OrderedDataOutputStream writeShort(short value) throws IOException {
- mByteBuffer.rewind();
- mByteBuffer.putShort(value);
- out.write(mByteBuffer.array(), 0, 2);
- return this;
- }
-
- public OrderedDataOutputStream writeInt(int value) throws IOException {
- mByteBuffer.rewind();
- mByteBuffer.putInt(value);
- out.write(mByteBuffer.array());
- return this;
- }
-
- public OrderedDataOutputStream writeRational(Rational rational) throws IOException {
- writeInt((int) rational.getNumerator());
- writeInt((int) rational.getDenominator());
- return this;
- }
-}
diff --git a/WallpaperPicker/src/com/android/gallery3d/exif/Rational.java b/WallpaperPicker/src/com/android/gallery3d/exif/Rational.java
deleted file mode 100644
index 591d63faf..000000000
--- a/WallpaperPicker/src/com/android/gallery3d/exif/Rational.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2012 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.exif;
-
-/**
- * The rational data type of EXIF tag. Contains a pair of longs representing the
- * numerator and denominator of a Rational number.
- */
-public class Rational {
-
- private final long mNumerator;
- private final long mDenominator;
-
- /**
- * Create a Rational with a given numerator and denominator.
- *
- * @param nominator
- * @param denominator
- */
- public Rational(long nominator, long denominator) {
- mNumerator = nominator;
- mDenominator = denominator;
- }
-
- /**
- * Create a copy of a Rational.
- */
- public Rational(Rational r) {
- mNumerator = r.mNumerator;
- mDenominator = r.mDenominator;
- }
-
- /**
- * Gets the numerator of the rational.
- */
- public long getNumerator() {
- return mNumerator;
- }
-
- /**
- * Gets the denominator of the rational
- */
- public long getDenominator() {
- return mDenominator;
- }
-
- /**
- * Gets the rational value as type double. Will cause a divide-by-zero error
- * if the denominator is 0.
- */
- public double toDouble() {
- return mNumerator / (double) mDenominator;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (obj == null) {
- return false;
- }
- if (this == obj) {
- return true;
- }
- if (obj instanceof Rational) {
- Rational data = (Rational) obj;
- return mNumerator == data.mNumerator && mDenominator == data.mDenominator;
- }
- return false;
- }
-
- @Override
- public String toString() {
- return mNumerator + "/" + mDenominator;
- }
-}
diff --git a/WallpaperPicker/src/com/android/gallery3d/glrenderer/BasicTexture.java b/WallpaperPicker/src/com/android/gallery3d/glrenderer/BasicTexture.java
index 0f3efb727..7270e88c0 100644
--- a/WallpaperPicker/src/com/android/gallery3d/glrenderer/BasicTexture.java
+++ b/WallpaperPicker/src/com/android/gallery3d/glrenderer/BasicTexture.java
@@ -46,8 +46,6 @@ public abstract class BasicTexture implements Texture {
protected int mTextureWidth;
protected int mTextureHeight;
- private boolean mHasBorder;
-
protected GLCanvas mCanvasRef = null;
private static WeakHashMap<BasicTexture, Object> sAllTextures
= new WeakHashMap<BasicTexture, Object>();
@@ -85,10 +83,6 @@ public abstract class BasicTexture implements Texture {
}
}
- public boolean isFlippedVertically() {
- return false;
- }
-
public int getId() {
return mId;
}
@@ -113,25 +107,6 @@ public abstract class BasicTexture implements Texture {
return mTextureHeight;
}
- // Returns true if the texture has one pixel transparent border around the
- // actual content. This is used to avoid jigged edges.
- //
- // The jigged edges appear because we use GL_CLAMP_TO_EDGE for texture wrap
- // mode (GL_CLAMP is not available in OpenGL ES), so a pixel partially
- // covered by the texture will use the color of the edge texel. If we add
- // the transparent border, the color of the edge texel will be mixed with
- // appropriate amount of transparent.
- //
- // Currently our background is black, so we can draw the thumbnails without
- // enabling blending.
- public boolean hasBorder() {
- return mHasBorder;
- }
-
- protected void setBorder(boolean hasBorder) {
- mHasBorder = hasBorder;
- }
-
@Override
public void draw(GLCanvas canvas, int x, int y) {
canvas.drawTexture(this, x, y, getWidth(), getHeight());
@@ -146,9 +121,6 @@ public abstract class BasicTexture implements Texture {
// It should make sure the data is uploaded to GL memory.
abstract protected boolean onBind(GLCanvas canvas);
- // Returns the GL texture target for this texture (e.g. GL_TEXTURE_2D).
- abstract protected int getTarget();
-
public boolean isLoaded() {
return mState == STATE_LOADED;
}
@@ -185,13 +157,6 @@ public abstract class BasicTexture implements Texture {
sInFinalizer.set(null);
}
- // This is for deciding if we can call Bitmap's recycle().
- // We cannot call Bitmap's recycle() in finalizer because at that point
- // the finalizer of Bitmap may already be called so recycle() will crash.
- public static boolean inFinalizer() {
- return sInFinalizer.get() != null;
- }
-
public static void yieldAllTextures() {
synchronized (sAllTextures) {
for (BasicTexture t : sAllTextures.keySet()) {
diff --git a/WallpaperPicker/src/com/android/gallery3d/glrenderer/BitmapTexture.java b/WallpaperPicker/src/com/android/gallery3d/glrenderer/BitmapTexture.java
index f8b01cb42..bb69b6858 100644
--- a/WallpaperPicker/src/com/android/gallery3d/glrenderer/BitmapTexture.java
+++ b/WallpaperPicker/src/com/android/gallery3d/glrenderer/BitmapTexture.java
@@ -29,11 +29,7 @@ public class BitmapTexture extends UploadedTexture {
protected Bitmap mContentBitmap;
public BitmapTexture(Bitmap bitmap) {
- this(bitmap, false);
- }
-
- public BitmapTexture(Bitmap bitmap, boolean hasBorder) {
- super(hasBorder);
+ super();
Utils.assertTrue(bitmap != null && !bitmap.isRecycled());
mContentBitmap = bitmap;
}
diff --git a/WallpaperPicker/src/com/android/gallery3d/glrenderer/GLCanvas.java b/WallpaperPicker/src/com/android/gallery3d/glrenderer/GLCanvas.java
index 5b0747704..2bda8d21a 100644
--- a/WallpaperPicker/src/com/android/gallery3d/glrenderer/GLCanvas.java
+++ b/WallpaperPicker/src/com/android/gallery3d/glrenderer/GLCanvas.java
@@ -17,7 +17,6 @@
package com.android.gallery3d.glrenderer;
import android.graphics.Bitmap;
-import android.graphics.Rect;
import android.graphics.RectF;
//
@@ -40,36 +39,14 @@ public interface GLCanvas {
// Clear the drawing buffers. This should only be used by GLRoot.
public abstract void clearBuffer();
- public abstract void clearBuffer(float[] argb);
-
- // Sets and gets the current alpha, alpha must be in [0, 1].
- public abstract void setAlpha(float alpha);
-
- public abstract float getAlpha();
-
- // (current alpha) = (current alpha) * alpha
- public abstract void multiplyAlpha(float alpha);
-
- // Change the current transform matrix.
- public abstract void translate(float x, float y, float z);
-
public abstract void translate(float x, float y);
- public abstract void scale(float sx, float sy, float sz);
-
public abstract void rotate(float angle, float x, float y, float z);
- public abstract void multiplyMatrix(float[] mMatrix, int offset);
-
- // Pushes the configuration state (matrix, and alpha) onto
- // a private stack.
- public abstract void save();
-
// Same as save(), but only save those specified in saveFlags.
public abstract void save(int saveFlags);
public static final int SAVE_FLAG_ALL = 0xFFFFFFFF;
- public static final int SAVE_FLAG_ALPHA = 0x01;
public static final int SAVE_FLAG_MATRIX = 0x02;
// Pops from the top of the stack as current configuration state (matrix,
@@ -78,64 +55,22 @@ public interface GLCanvas {
// last save call.
public abstract void restore();
- // Draws a line using the specified paint from (x1, y1) to (x2, y2).
- // (Both end points are included).
- public abstract void drawLine(float x1, float y1, float x2, float y2, GLPaint paint);
-
- // Draws a rectangle using the specified paint from (x1, y1) to (x2, y2).
- // (Both end points are included).
- public abstract void drawRect(float x1, float y1, float x2, float y2, GLPaint paint);
-
- // Fills the specified rectangle with the specified color.
- public abstract void fillRect(float x, float y, float width, float height, int color);
-
// Draws a texture to the specified rectangle.
- public abstract void drawTexture(
- BasicTexture texture, int x, int y, int width, int height);
-
- public abstract void drawMesh(BasicTexture tex, int x, int y, int xyBuffer,
- int uvBuffer, int indexBuffer, int indexCount);
+ public abstract void drawTexture(BasicTexture texture, int x, int y, int width, int height);
// Draws the source rectangle part of the texture to the target rectangle.
public abstract void drawTexture(BasicTexture texture, RectF source, RectF target);
- // Draw a texture with a specified texture transform.
- public abstract void drawTexture(BasicTexture texture, float[] mTextureTransform,
- int x, int y, int w, int h);
-
- // Draw two textures to the specified rectangle. The actual texture used is
- // from * (1 - ratio) + to * ratio
- // The two textures must have the same size.
- public abstract void drawMixed(BasicTexture from, int toColor,
- float ratio, int x, int y, int w, int h);
-
- // Draw a region of a texture and a specified color to the specified
- // rectangle. The actual color used is from * (1 - ratio) + to * ratio.
- // The region of the texture is defined by parameter "src". The target
- // rectangle is specified by parameter "target".
- public abstract void drawMixed(BasicTexture from, int toColor,
- float ratio, RectF src, RectF target);
-
// Unloads the specified texture from the canvas. The resource allocated
// to draw the texture will be released. The specified texture will return
// to the unloaded state. This function should be called only from
// BasicTexture or its descendant
public abstract boolean unloadTexture(BasicTexture texture);
- // Delete the specified buffer object, similar to unloadTexture.
- public abstract void deleteBuffer(int bufferId);
-
// Delete the textures and buffers in GL side. This function should only be
// called in the GL thread.
public abstract void deleteRecycledResources();
- // Dump statistics information and clear the counters. For debug only.
- public abstract void dumpStatisticsAndClear();
-
- public abstract void beginRenderTarget(RawTexture texture);
-
- public abstract void endRenderTarget();
-
/**
* Sets texture parameters to use GL_CLAMP_TO_EDGE for both
* GL_TEXTURE_WRAP_S and GL_TEXTURE_WRAP_T. Sets texture parameters to be
@@ -185,31 +120,4 @@ public interface GLCanvas {
* @return The buffer ID that was generated.
*/
public abstract int uploadBuffer(java.nio.FloatBuffer buffer);
-
- /**
- * Generates buffers and uploads the element array buffer data.
- *
- * @param buffer The buffer to upload
- * @return The buffer ID that was generated.
- */
- public abstract int uploadBuffer(java.nio.ByteBuffer buffer);
-
- /**
- * After LightCycle makes GL calls, this method is called to restore the GL
- * configuration to the one expected by GLCanvas.
- */
- public abstract void recoverFromLightCycle();
-
- /**
- * Gets the bounds given by x, y, width, and height as well as the internal
- * matrix state. There is no special handling for non-90-degree rotations.
- * It only considers the lower-left and upper-right corners as the bounds.
- *
- * @param bounds The output bounds to write to.
- * @param x The left side of the input rectangle.
- * @param y The bottom of the input rectangle.
- * @param width The width of the input rectangle.
- * @param height The height of the input rectangle.
- */
- public abstract void getBounds(Rect bounds, int x, int y, int width, int height);
}
diff --git a/WallpaperPicker/src/com/android/gallery3d/glrenderer/GLES20Canvas.java b/WallpaperPicker/src/com/android/gallery3d/glrenderer/GLES20Canvas.java
index 933260b48..0da3bae96 100644
--- a/WallpaperPicker/src/com/android/gallery3d/glrenderer/GLES20Canvas.java
+++ b/WallpaperPicker/src/com/android/gallery3d/glrenderer/GLES20Canvas.java
@@ -16,7 +16,6 @@
package com.android.gallery3d.glrenderer;
import android.graphics.Bitmap;
-import android.graphics.Rect;
import android.graphics.RectF;
import android.opengl.GLES20;
import android.opengl.GLUtils;
@@ -27,24 +26,22 @@ import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
-import java.util.ArrayList;
import java.util.Arrays;
+import javax.microedition.khronos.opengles.GL11;
+
public class GLES20Canvas implements GLCanvas {
// ************** Constants **********************
private static final String TAG = GLES20Canvas.class.getSimpleName();
private static final int FLOAT_SIZE = Float.SIZE / Byte.SIZE;
- private static final float OPAQUE_ALPHA = 0.95f;
private static final int COORDS_PER_VERTEX = 2;
private static final int VERTEX_STRIDE = COORDS_PER_VERTEX * FLOAT_SIZE;
private static final int COUNT_FILL_VERTEX = 4;
- private static final int COUNT_LINE_VERTEX = 2;
- private static final int COUNT_RECT_VERTEX = 4;
private static final int OFFSET_FILL_RECT = 0;
- private static final int OFFSET_DRAW_LINE = OFFSET_FILL_RECT + COUNT_FILL_VERTEX;
- private static final int OFFSET_DRAW_RECT = OFFSET_DRAW_LINE + COUNT_LINE_VERTEX;
+
+ private static final int GL_TARGET = GL11.GL_TEXTURE_2D;
private static final float[] BOX_COORDINATES = {
0, 0, // Fill rectangle
@@ -59,33 +56,11 @@ public class GLES20Canvas implements GLCanvas {
1, 0,
};
- private static final float[] BOUNDS_COORDINATES = {
- 0, 0, 0, 1,
- 1, 1, 0, 1,
- };
-
private static final String POSITION_ATTRIBUTE = "aPosition";
- private static final String COLOR_UNIFORM = "uColor";
private static final String MATRIX_UNIFORM = "uMatrix";
private static final String TEXTURE_MATRIX_UNIFORM = "uTextureMatrix";
private static final String TEXTURE_SAMPLER_UNIFORM = "uTextureSampler";
private static final String ALPHA_UNIFORM = "uAlpha";
- private static final String TEXTURE_COORD_ATTRIBUTE = "aTextureCoordinate";
-
- private static final String DRAW_VERTEX_SHADER = ""
- + "uniform mat4 " + MATRIX_UNIFORM + ";\n"
- + "attribute vec2 " + POSITION_ATTRIBUTE + ";\n"
- + "void main() {\n"
- + " vec4 pos = vec4(" + POSITION_ATTRIBUTE + ", 0.0, 1.0);\n"
- + " gl_Position = " + MATRIX_UNIFORM + " * pos;\n"
- + "}\n";
-
- private static final String DRAW_FRAGMENT_SHADER = ""
- + "precision mediump float;\n"
- + "uniform vec4 " + COLOR_UNIFORM + ";\n"
- + "void main() {\n"
- + " gl_FragColor = " + COLOR_UNIFORM + ";\n"
- + "}\n";
private static final String TEXTURE_VERTEX_SHADER = ""
+ "uniform mat4 " + MATRIX_UNIFORM + ";\n"
@@ -98,17 +73,6 @@ public class GLES20Canvas implements GLCanvas {
+ " vTextureCoord = (" + TEXTURE_MATRIX_UNIFORM + " * pos).xy;\n"
+ "}\n";
- private static final String MESH_VERTEX_SHADER = ""
- + "uniform mat4 " + MATRIX_UNIFORM + ";\n"
- + "attribute vec2 " + POSITION_ATTRIBUTE + ";\n"
- + "attribute vec2 " + TEXTURE_COORD_ATTRIBUTE + ";\n"
- + "varying vec2 vTextureCoord;\n"
- + "void main() {\n"
- + " vec4 pos = vec4(" + POSITION_ATTRIBUTE + ", 0.0, 1.0);\n"
- + " gl_Position = " + MATRIX_UNIFORM + " * pos;\n"
- + " vTextureCoord = " + TEXTURE_COORD_ATTRIBUTE + ";\n"
- + "}\n";
-
private static final String TEXTURE_FRAGMENT_SHADER = ""
+ "precision mediump float;\n"
+ "varying vec2 vTextureCoord;\n"
@@ -119,26 +83,13 @@ public class GLES20Canvas implements GLCanvas {
+ " gl_FragColor *= " + ALPHA_UNIFORM + ";\n"
+ "}\n";
- private static final String OES_TEXTURE_FRAGMENT_SHADER = ""
- + "#extension GL_OES_EGL_image_external : require\n"
- + "precision mediump float;\n"
- + "varying vec2 vTextureCoord;\n"
- + "uniform float " + ALPHA_UNIFORM + ";\n"
- + "uniform samplerExternalOES " + TEXTURE_SAMPLER_UNIFORM + ";\n"
- + "void main() {\n"
- + " gl_FragColor = texture2D(" + TEXTURE_SAMPLER_UNIFORM + ", vTextureCoord);\n"
- + " gl_FragColor *= " + ALPHA_UNIFORM + ";\n"
- + "}\n";
-
private static final int INITIAL_RESTORE_STATE_SIZE = 8;
private static final int MATRIX_SIZE = 16;
// Keep track of restore state
private float[] mMatrices = new float[INITIAL_RESTORE_STATE_SIZE * MATRIX_SIZE];
- private float[] mAlphas = new float[INITIAL_RESTORE_STATE_SIZE];
private IntArray mSaveFlags = new IntArray();
- private int mCurrentAlphaIndex = 0;
private int mCurrentMatrixIndex = 0;
// Viewport size
@@ -148,15 +99,8 @@ public class GLES20Canvas implements GLCanvas {
// Projection matrix
private float[] mProjectionMatrix = new float[MATRIX_SIZE];
- // Screen size for when we aren't bound to a texture
- private int mScreenWidth;
- private int mScreenHeight;
-
// GL programs
- private int mDrawProgram;
private int mTextureProgram;
- private int mOesTextureProgram;
- private int mMeshProgram;
// GL buffer containing BOX_COORDINATES
private int mBoxCoordinates;
@@ -165,17 +109,11 @@ public class GLES20Canvas implements GLCanvas {
private static final int INDEX_POSITION = 0;
private static final int INDEX_MATRIX = 1;
- // Handle indices -- draw
- private static final int INDEX_COLOR = 2;
-
// Handle indices -- texture
private static final int INDEX_TEXTURE_MATRIX = 2;
private static final int INDEX_TEXTURE_SAMPLER = 3;
private static final int INDEX_ALPHA = 4;
- // Handle indices -- mesh
- private static final int INDEX_TEXTURE_COORD = 2;
-
private abstract static class ShaderParameter {
public int handle;
protected final String mName;
@@ -211,52 +149,18 @@ public class GLES20Canvas implements GLCanvas {
}
}
- ShaderParameter[] mDrawParameters = {
- new AttributeShaderParameter(POSITION_ATTRIBUTE), // INDEX_POSITION
- new UniformShaderParameter(MATRIX_UNIFORM), // INDEX_MATRIX
- new UniformShaderParameter(COLOR_UNIFORM), // INDEX_COLOR
- };
- ShaderParameter[] mTextureParameters = {
+ private ShaderParameter[] mTextureParameters = {
new AttributeShaderParameter(POSITION_ATTRIBUTE), // INDEX_POSITION
new UniformShaderParameter(MATRIX_UNIFORM), // INDEX_MATRIX
new UniformShaderParameter(TEXTURE_MATRIX_UNIFORM), // INDEX_TEXTURE_MATRIX
new UniformShaderParameter(TEXTURE_SAMPLER_UNIFORM), // INDEX_TEXTURE_SAMPLER
new UniformShaderParameter(ALPHA_UNIFORM), // INDEX_ALPHA
};
- ShaderParameter[] mOesTextureParameters = {
- new AttributeShaderParameter(POSITION_ATTRIBUTE), // INDEX_POSITION
- new UniformShaderParameter(MATRIX_UNIFORM), // INDEX_MATRIX
- new UniformShaderParameter(TEXTURE_MATRIX_UNIFORM), // INDEX_TEXTURE_MATRIX
- new UniformShaderParameter(TEXTURE_SAMPLER_UNIFORM), // INDEX_TEXTURE_SAMPLER
- new UniformShaderParameter(ALPHA_UNIFORM), // INDEX_ALPHA
- };
- ShaderParameter[] mMeshParameters = {
- new AttributeShaderParameter(POSITION_ATTRIBUTE), // INDEX_POSITION
- new UniformShaderParameter(MATRIX_UNIFORM), // INDEX_MATRIX
- new AttributeShaderParameter(TEXTURE_COORD_ATTRIBUTE), // INDEX_TEXTURE_COORD
- new UniformShaderParameter(TEXTURE_SAMPLER_UNIFORM), // INDEX_TEXTURE_SAMPLER
- new UniformShaderParameter(ALPHA_UNIFORM), // INDEX_ALPHA
- };
private final IntArray mUnboundTextures = new IntArray();
- private final IntArray mDeleteBuffers = new IntArray();
-
- // Keep track of statistics for debugging
- private int mCountDrawMesh = 0;
- private int mCountTextureRect = 0;
- private int mCountFillRect = 0;
- private int mCountDrawLine = 0;
-
- // Buffer for framebuffer IDs -- we keep track so we can switch the attached
- // texture.
- private int[] mFrameBuffer = new int[1];
-
- // Bound textures.
- private ArrayList<RawTexture> mTargetTextures = new ArrayList<RawTexture>();
// Temporary variables used within calculations
private final float[] mTempMatrix = new float[32];
- private final float[] mTempColor = new float[4];
private final RectF mTempSourceRect = new RectF();
private final RectF mTempTargetRect = new RectF();
private final float[] mTempTextureMatrix = new float[MATRIX_SIZE];
@@ -267,26 +171,15 @@ public class GLES20Canvas implements GLCanvas {
public GLES20Canvas() {
Matrix.setIdentityM(mTempTextureMatrix, 0);
Matrix.setIdentityM(mMatrices, mCurrentMatrixIndex);
- mAlphas[mCurrentAlphaIndex] = 1f;
- mTargetTextures.add(null);
FloatBuffer boxBuffer = createBuffer(BOX_COORDINATES);
mBoxCoordinates = uploadBuffer(boxBuffer);
- int drawVertexShader = loadShader(GLES20.GL_VERTEX_SHADER, DRAW_VERTEX_SHADER);
int textureVertexShader = loadShader(GLES20.GL_VERTEX_SHADER, TEXTURE_VERTEX_SHADER);
- int meshVertexShader = loadShader(GLES20.GL_VERTEX_SHADER, MESH_VERTEX_SHADER);
- int drawFragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, DRAW_FRAGMENT_SHADER);
int textureFragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, TEXTURE_FRAGMENT_SHADER);
- int oesTextureFragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER,
- OES_TEXTURE_FRAGMENT_SHADER);
- mDrawProgram = assembleProgram(drawVertexShader, drawFragmentShader, mDrawParameters);
mTextureProgram = assembleProgram(textureVertexShader, textureFragmentShader,
mTextureParameters);
- mOesTextureProgram = assembleProgram(textureVertexShader, oesTextureFragmentShader,
- mOesTextureParameters);
- mMeshProgram = assembleProgram(meshVertexShader, textureFragmentShader, mMeshParameters);
GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA);
checkError();
}
@@ -348,12 +241,8 @@ public class GLES20Canvas implements GLCanvas {
checkError();
Matrix.setIdentityM(mMatrices, mCurrentMatrixIndex);
Matrix.orthoM(mProjectionMatrix, 0, 0, width, 0, height, -1, 1);
- if (getTargetTexture() == null) {
- mScreenWidth = width;
- mScreenHeight = height;
- Matrix.translateM(mMatrices, mCurrentMatrixIndex, 0, height, 0);
- Matrix.scaleM(mMatrices, mCurrentMatrixIndex, 1, -1, 1);
- }
+ Matrix.translateM(mMatrices, mCurrentMatrixIndex, 0, height, 0);
+ Matrix.scaleM(mMatrices, mCurrentMatrixIndex, 1, -1, 1);
}
@Override
@@ -364,34 +253,6 @@ public class GLES20Canvas implements GLCanvas {
checkError();
}
- @Override
- public void clearBuffer(float[] argb) {
- GLES20.glClearColor(argb[1], argb[2], argb[3], argb[0]);
- checkError();
- GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
- checkError();
- }
-
- @Override
- public float getAlpha() {
- return mAlphas[mCurrentAlphaIndex];
- }
-
- @Override
- public void setAlpha(float alpha) {
- mAlphas[mCurrentAlphaIndex] = alpha;
- }
-
- @Override
- public void multiplyAlpha(float alpha) {
- setAlpha(getAlpha() * alpha);
- }
-
- @Override
- public void translate(float x, float y, float z) {
- Matrix.translateM(mMatrices, mCurrentMatrixIndex, x, y, z);
- }
-
// This is a faster version of translate(x, y, z) because
// (1) we knows z = 0, (2) we inline the Matrix.translateM call,
// (3) we unroll the loop
@@ -406,11 +267,6 @@ public class GLES20Canvas implements GLCanvas {
}
@Override
- public void scale(float sx, float sy, float sz) {
- Matrix.scaleM(mMatrices, mCurrentMatrixIndex, sx, sy, sz);
- }
-
- @Override
public void rotate(float angle, float x, float y, float z) {
if (angle == 0f) {
return;
@@ -424,30 +280,7 @@ public class GLES20Canvas implements GLCanvas {
}
@Override
- public void multiplyMatrix(float[] matrix, int offset) {
- float[] temp = mTempMatrix;
- float[] currentMatrix = mMatrices;
- int index = mCurrentMatrixIndex;
- Matrix.multiplyMM(temp, 0, currentMatrix, index, matrix, offset);
- System.arraycopy(temp, 0, currentMatrix, index, 16);
- }
-
- @Override
- public void save() {
- save(SAVE_FLAG_ALL);
- }
-
- @Override
public void save(int saveFlags) {
- boolean saveAlpha = (saveFlags & SAVE_FLAG_ALPHA) == SAVE_FLAG_ALPHA;
- if (saveAlpha) {
- float currentAlpha = getAlpha();
- mCurrentAlphaIndex++;
- if (mAlphas.length <= mCurrentAlphaIndex) {
- mAlphas = Arrays.copyOf(mAlphas, mAlphas.length * 2);
- }
- mAlphas[mCurrentAlphaIndex] = currentAlpha;
- }
boolean saveMatrix = (saveFlags & SAVE_FLAG_MATRIX) == SAVE_FLAG_MATRIX;
if (saveMatrix) {
int currentIndex = mCurrentMatrixIndex;
@@ -463,82 +296,12 @@ public class GLES20Canvas implements GLCanvas {
@Override
public void restore() {
int restoreFlags = mSaveFlags.removeLast();
- boolean restoreAlpha = (restoreFlags & SAVE_FLAG_ALPHA) == SAVE_FLAG_ALPHA;
- if (restoreAlpha) {
- mCurrentAlphaIndex--;
- }
boolean restoreMatrix = (restoreFlags & SAVE_FLAG_MATRIX) == SAVE_FLAG_MATRIX;
if (restoreMatrix) {
mCurrentMatrixIndex -= MATRIX_SIZE;
}
}
- @Override
- public void drawLine(float x1, float y1, float x2, float y2, GLPaint paint) {
- draw(GLES20.GL_LINE_STRIP, OFFSET_DRAW_LINE, COUNT_LINE_VERTEX, x1, y1, x2 - x1, y2 - y1,
- paint);
- mCountDrawLine++;
- }
-
- @Override
- public void drawRect(float x, float y, float width, float height, GLPaint paint) {
- draw(GLES20.GL_LINE_LOOP, OFFSET_DRAW_RECT, COUNT_RECT_VERTEX, x, y, width, height, paint);
- mCountDrawLine++;
- }
-
- private void draw(int type, int offset, int count, float x, float y, float width, float height,
- GLPaint paint) {
- draw(type, offset, count, x, y, width, height, paint.getColor(), paint.getLineWidth());
- }
-
- private void draw(int type, int offset, int count, float x, float y, float width, float height,
- int color, float lineWidth) {
- prepareDraw(offset, color, lineWidth);
- draw(mDrawParameters, type, count, x, y, width, height);
- }
-
- private void prepareDraw(int offset, int color, float lineWidth) {
- GLES20.glUseProgram(mDrawProgram);
- checkError();
- if (lineWidth > 0) {
- GLES20.glLineWidth(lineWidth);
- checkError();
- }
- float[] colorArray = getColor(color);
- boolean blendingEnabled = (colorArray[3] < 1f);
- enableBlending(blendingEnabled);
- if (blendingEnabled) {
- GLES20.glBlendColor(colorArray[0], colorArray[1], colorArray[2], colorArray[3]);
- checkError();
- }
-
- GLES20.glUniform4fv(mDrawParameters[INDEX_COLOR].handle, 1, colorArray, 0);
- setPosition(mDrawParameters, offset);
- checkError();
- }
-
- private float[] getColor(int color) {
- float alpha = ((color >>> 24) & 0xFF) / 255f * getAlpha();
- float red = ((color >>> 16) & 0xFF) / 255f * alpha;
- float green = ((color >>> 8) & 0xFF) / 255f * alpha;
- float blue = (color & 0xFF) / 255f * alpha;
- mTempColor[0] = red;
- mTempColor[1] = green;
- mTempColor[2] = blue;
- mTempColor[3] = alpha;
- return mTempColor;
- }
-
- private void enableBlending(boolean enableBlending) {
- if (enableBlending) {
- GLES20.glEnable(GLES20.GL_BLEND);
- checkError();
- } else {
- GLES20.glDisable(GLES20.GL_BLEND);
- checkError();
- }
- }
-
private void setPosition(ShaderParameter[] params, int offset) {
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mBoxCoordinates);
checkError();
@@ -570,13 +333,6 @@ public class GLES20Canvas implements GLCanvas {
}
@Override
- public void fillRect(float x, float y, float width, float height, int color) {
- draw(GLES20.GL_TRIANGLE_STRIP, OFFSET_FILL_RECT, COUNT_FILL_VERTEX, x, y, width, height,
- color, 0f);
- mCountFillRect++;
- }
-
- @Override
public void drawTexture(BasicTexture texture, int x, int y, int width, int height) {
if (width <= 0 || height <= 0) {
return;
@@ -588,17 +344,7 @@ public class GLES20Canvas implements GLCanvas {
}
private static void copyTextureCoordinates(BasicTexture texture, RectF outRect) {
- int left = 0;
- int top = 0;
- int right = texture.getWidth();
- int bottom = texture.getHeight();
- if (texture.hasBorder()) {
- left = 1;
- top = 1;
- right -= 1;
- bottom -= 1;
- }
- outRect.set(left, top, right, bottom);
+ outRect.set(0, 0, texture.getWidth(), texture.getHeight());
}
@Override
@@ -613,16 +359,6 @@ public class GLES20Canvas implements GLCanvas {
drawTextureRect(texture, mTempSourceRect, mTempTargetRect);
}
- @Override
- public void drawTexture(BasicTexture texture, float[] textureTransform, int x, int y, int w,
- int h) {
- if (w <= 0 || h <= 0) {
- return;
- }
- mTempTargetRect.set(x, y, x + w, y + h);
- drawTextureRect(texture, textureTransform, mTempTargetRect);
- }
-
private void drawTextureRect(BasicTexture texture, RectF source, RectF target) {
setTextureMatrix(source);
drawTextureRect(texture, mTempTextureMatrix, target);
@@ -667,30 +403,15 @@ public class GLES20Canvas implements GLCanvas {
setPosition(params, OFFSET_FILL_RECT);
GLES20.glUniformMatrix4fv(params[INDEX_TEXTURE_MATRIX].handle, 1, false, textureMatrix, 0);
checkError();
- if (texture.isFlippedVertically()) {
- save(SAVE_FLAG_MATRIX);
- translate(0, target.centerY());
- scale(1, -1, 1);
- translate(0, -target.centerY());
- }
draw(params, GLES20.GL_TRIANGLE_STRIP, COUNT_FILL_VERTEX, target.left, target.top,
target.width(), target.height());
- if (texture.isFlippedVertically()) {
- restore();
- }
- mCountTextureRect++;
}
private ShaderParameter[] prepareTexture(BasicTexture texture) {
ShaderParameter[] params;
int program;
- if (texture.getTarget() == GLES20.GL_TEXTURE_2D) {
- params = mTextureParameters;
- program = mTextureProgram;
- } else {
- params = mOesTextureParameters;
- program = mOesTextureProgram;
- }
+ params = mTextureParameters;
+ program = mTextureProgram;
prepareTexture(texture, program, params);
return params;
}
@@ -699,86 +420,17 @@ public class GLES20Canvas implements GLCanvas {
deleteRecycledResources();
GLES20.glUseProgram(program);
checkError();
- enableBlending(!texture.isOpaque() || getAlpha() < OPAQUE_ALPHA);
+ GLES20.glDisable(GLES20.GL_BLEND);
+ checkError();
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
checkError();
texture.onBind(this);
- GLES20.glBindTexture(texture.getTarget(), texture.getId());
+ GLES20.glBindTexture(GL_TARGET, texture.getId());
checkError();
GLES20.glUniform1i(params[INDEX_TEXTURE_SAMPLER].handle, 0);
checkError();
- GLES20.glUniform1f(params[INDEX_ALPHA].handle, getAlpha());
- checkError();
- }
-
- @Override
- public void drawMesh(BasicTexture texture, int x, int y, int xyBuffer, int uvBuffer,
- int indexBuffer, int indexCount) {
- prepareTexture(texture, mMeshProgram, mMeshParameters);
-
- GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
- checkError();
-
- GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, xyBuffer);
- checkError();
- int positionHandle = mMeshParameters[INDEX_POSITION].handle;
- GLES20.glVertexAttribPointer(positionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false,
- VERTEX_STRIDE, 0);
- checkError();
-
- GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, uvBuffer);
- checkError();
- int texCoordHandle = mMeshParameters[INDEX_TEXTURE_COORD].handle;
- GLES20.glVertexAttribPointer(texCoordHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT,
- false, VERTEX_STRIDE, 0);
- checkError();
- GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
- checkError();
-
- GLES20.glEnableVertexAttribArray(positionHandle);
- checkError();
- GLES20.glEnableVertexAttribArray(texCoordHandle);
- checkError();
-
- setMatrix(mMeshParameters, x, y, 1, 1);
- GLES20.glDrawElements(GLES20.GL_TRIANGLE_STRIP, indexCount, GLES20.GL_UNSIGNED_BYTE, 0);
+ GLES20.glUniform1f(params[INDEX_ALPHA].handle, 1);
checkError();
-
- GLES20.glDisableVertexAttribArray(positionHandle);
- checkError();
- GLES20.glDisableVertexAttribArray(texCoordHandle);
- checkError();
- GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);
- checkError();
- mCountDrawMesh++;
- }
-
- @Override
- public void drawMixed(BasicTexture texture, int toColor, float ratio, int x, int y, int w, int h) {
- copyTextureCoordinates(texture, mTempSourceRect);
- mTempTargetRect.set(x, y, x + w, y + h);
- drawMixed(texture, toColor, ratio, mTempSourceRect, mTempTargetRect);
- }
-
- @Override
- public void drawMixed(BasicTexture texture, int toColor, float ratio, RectF source, RectF target) {
- if (target.width() <= 0 || target.height() <= 0) {
- return;
- }
- save(SAVE_FLAG_ALPHA);
-
- float currentAlpha = getAlpha();
- float cappedRatio = Math.min(1f, Math.max(0f, ratio));
-
- float textureAlpha = (1f - cappedRatio) * currentAlpha;
- setAlpha(textureAlpha);
- drawTexture(texture, source, target);
-
- float colorAlpha = cappedRatio * currentAlpha;
- setAlpha(colorAlpha);
- fillRect(target.left, target.top, target.width(), target.height(), toColor);
-
- restore();
}
@Override
@@ -793,13 +445,6 @@ public class GLES20Canvas implements GLCanvas {
}
@Override
- public void deleteBuffer(int bufferId) {
- synchronized (mUnboundTextures) {
- mDeleteBuffers.add(bufferId);
- }
- }
-
- @Override
public void deleteRecycledResources() {
synchronized (mUnboundTextures) {
IntArray ids = mUnboundTextures;
@@ -807,134 +452,41 @@ public class GLES20Canvas implements GLCanvas {
mGLId.glDeleteTextures(null, ids.size(), ids.getInternalArray(), 0);
ids.clear();
}
-
- ids = mDeleteBuffers;
- if (ids.size() > 0) {
- mGLId.glDeleteBuffers(null, ids.size(), ids.getInternalArray(), 0);
- ids.clear();
- }
- }
- }
-
- @Override
- public void dumpStatisticsAndClear() {
- String line = String.format("MESH:%d, TEX_RECT:%d, FILL_RECT:%d, LINE:%d", mCountDrawMesh,
- mCountTextureRect, mCountFillRect, mCountDrawLine);
- mCountDrawMesh = 0;
- mCountTextureRect = 0;
- mCountFillRect = 0;
- mCountDrawLine = 0;
- Log.d(TAG, line);
- }
-
- @Override
- public void endRenderTarget() {
- RawTexture oldTexture = mTargetTextures.remove(mTargetTextures.size() - 1);
- RawTexture texture = getTargetTexture();
- setRenderTarget(oldTexture, texture);
- restore(); // restore matrix and alpha
- }
-
- @Override
- public void beginRenderTarget(RawTexture texture) {
- save(); // save matrix and alpha and blending
- RawTexture oldTexture = getTargetTexture();
- mTargetTextures.add(texture);
- setRenderTarget(oldTexture, texture);
- }
-
- private RawTexture getTargetTexture() {
- return mTargetTextures.get(mTargetTextures.size() - 1);
- }
-
- private void setRenderTarget(BasicTexture oldTexture, RawTexture texture) {
- if (oldTexture == null && texture != null) {
- GLES20.glGenFramebuffers(1, mFrameBuffer, 0);
- checkError();
- GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, mFrameBuffer[0]);
- checkError();
- } else if (oldTexture != null && texture == null) {
- GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
- checkError();
- GLES20.glDeleteFramebuffers(1, mFrameBuffer, 0);
- checkError();
- }
-
- if (texture == null) {
- setSize(mScreenWidth, mScreenHeight);
- } else {
- setSize(texture.getWidth(), texture.getHeight());
-
- if (!texture.isLoaded()) {
- texture.prepare(this);
- }
-
- GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0,
- texture.getTarget(), texture.getId(), 0);
- checkError();
-
- checkFramebufferStatus();
- }
- }
-
- private static void checkFramebufferStatus() {
- int status = GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER);
- if (status != GLES20.GL_FRAMEBUFFER_COMPLETE) {
- String msg = "";
- switch (status) {
- case GLES20.GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
- msg = "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT";
- break;
- case GLES20.GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
- msg = "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS";
- break;
- case GLES20.GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
- msg = "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";
- break;
- case GLES20.GL_FRAMEBUFFER_UNSUPPORTED:
- msg = "GL_FRAMEBUFFER_UNSUPPORTED";
- break;
- }
- throw new RuntimeException(msg + ":" + Integer.toHexString(status));
}
}
@Override
public void setTextureParameters(BasicTexture texture) {
- int target = texture.getTarget();
- GLES20.glBindTexture(target, texture.getId());
+ GLES20.glBindTexture(GL_TARGET, texture.getId());
checkError();
- GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
- GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
- GLES20.glTexParameterf(target, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
- GLES20.glTexParameterf(target, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
+ GLES20.glTexParameteri(GL_TARGET, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
+ GLES20.glTexParameteri(GL_TARGET, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
+ GLES20.glTexParameterf(GL_TARGET, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
+ GLES20.glTexParameterf(GL_TARGET, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
}
@Override
public void initializeTextureSize(BasicTexture texture, int format, int type) {
- int target = texture.getTarget();
- GLES20.glBindTexture(target, texture.getId());
+ GLES20.glBindTexture(GL_TARGET, texture.getId());
checkError();
int width = texture.getTextureWidth();
int height = texture.getTextureHeight();
- GLES20.glTexImage2D(target, 0, format, width, height, 0, format, type, null);
+ GLES20.glTexImage2D(GL_TARGET, 0, format, width, height, 0, format, type, null);
}
@Override
public void initializeTexture(BasicTexture texture, Bitmap bitmap) {
- int target = texture.getTarget();
- GLES20.glBindTexture(target, texture.getId());
+ GLES20.glBindTexture(GL_TARGET, texture.getId());
checkError();
- GLUtils.texImage2D(target, 0, bitmap, 0);
+ GLUtils.texImage2D(GL_TARGET, 0, bitmap, 0);
}
@Override
public void texSubImage2D(BasicTexture texture, int xOffset, int yOffset, Bitmap bitmap,
int format, int type) {
- int target = texture.getTarget();
- GLES20.glBindTexture(target, texture.getId());
+ GLES20.glBindTexture(GL_TARGET, texture.getId());
checkError();
- GLUtils.texSubImage2D(target, 0, xOffset, yOffset, bitmap, format, type);
+ GLUtils.texSubImage2D(GL_TARGET, 0, xOffset, yOffset, bitmap, format, type);
}
@Override
@@ -942,11 +494,6 @@ public class GLES20Canvas implements GLCanvas {
return uploadBuffer(buf, FLOAT_SIZE);
}
- @Override
- public int uploadBuffer(ByteBuffer buf) {
- return uploadBuffer(buf, 1);
- }
-
private int uploadBuffer(Buffer buffer, int elementSize) {
mGLId.glGenBuffers(1, mTempIntArray, 0);
checkError();
@@ -967,40 +514,6 @@ public class GLES20Canvas implements GLCanvas {
}
}
- @SuppressWarnings("unused")
- private static void printMatrix(String message, float[] m, int offset) {
- StringBuilder b = new StringBuilder(message);
- for (int i = 0; i < MATRIX_SIZE; i++) {
- b.append(' ');
- if (i % 4 == 0) {
- b.append('\n');
- }
- b.append(m[offset + i]);
- }
- Log.v(TAG, b.toString());
- }
-
- @Override
- public void recoverFromLightCycle() {
- GLES20.glViewport(0, 0, mWidth, mHeight);
- GLES20.glDisable(GLES20.GL_DEPTH_TEST);
- GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA);
- checkError();
- }
-
- @Override
- public void getBounds(Rect bounds, int x, int y, int width, int height) {
- Matrix.translateM(mTempMatrix, 0, mMatrices, mCurrentMatrixIndex, x, y, 0f);
- Matrix.scaleM(mTempMatrix, 0, width, height, 1f);
- Matrix.multiplyMV(mTempMatrix, MATRIX_SIZE, mTempMatrix, 0, BOUNDS_COORDINATES, 0);
- Matrix.multiplyMV(mTempMatrix, MATRIX_SIZE + 4, mTempMatrix, 0, BOUNDS_COORDINATES, 4);
- bounds.left = Math.round(mTempMatrix[MATRIX_SIZE]);
- bounds.right = Math.round(mTempMatrix[MATRIX_SIZE + 4]);
- bounds.top = Math.round(mTempMatrix[MATRIX_SIZE + 1]);
- bounds.bottom = Math.round(mTempMatrix[MATRIX_SIZE + 5]);
- bounds.sort();
- }
-
@Override
public GLId getGLId() {
return mGLId;
diff --git a/WallpaperPicker/src/com/android/gallery3d/glrenderer/GLPaint.java b/WallpaperPicker/src/com/android/gallery3d/glrenderer/GLPaint.java
deleted file mode 100644
index b26e9ab29..000000000
--- a/WallpaperPicker/src/com/android/gallery3d/glrenderer/GLPaint.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2010 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.glrenderer;
-
-import com.android.gallery3d.common.Utils;
-
-public class GLPaint {
- private float mLineWidth = 1f;
- private int mColor = 0;
-
- public void setColor(int color) {
- mColor = color;
- }
-
- public int getColor() {
- return mColor;
- }
-
- public void setLineWidth(float width) {
- Utils.assertTrue(width >= 0);
- mLineWidth = width;
- }
-
- public float getLineWidth() {
- return mLineWidth;
- }
-}
diff --git a/WallpaperPicker/src/com/android/gallery3d/glrenderer/RawTexture.java b/WallpaperPicker/src/com/android/gallery3d/glrenderer/RawTexture.java
deleted file mode 100644
index 93f0fdff9..000000000
--- a/WallpaperPicker/src/com/android/gallery3d/glrenderer/RawTexture.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2010 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.glrenderer;
-
-import android.util.Log;
-
-import javax.microedition.khronos.opengles.GL11;
-
-public class RawTexture extends BasicTexture {
- private static final String TAG = "RawTexture";
-
- private final boolean mOpaque;
- private boolean mIsFlipped;
-
- public RawTexture(int width, int height, boolean opaque) {
- mOpaque = opaque;
- setSize(width, height);
- }
-
- @Override
- public boolean isOpaque() {
- return mOpaque;
- }
-
- @Override
- public boolean isFlippedVertically() {
- return mIsFlipped;
- }
-
- public void setIsFlippedVertically(boolean isFlipped) {
- mIsFlipped = isFlipped;
- }
-
- protected void prepare(GLCanvas canvas) {
- GLId glId = canvas.getGLId();
- mId = glId.generateTexture();
- canvas.initializeTextureSize(this, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE);
- canvas.setTextureParameters(this);
- mState = STATE_LOADED;
- setAssociatedCanvas(canvas);
- }
-
- @Override
- protected boolean onBind(GLCanvas canvas) {
- if (isLoaded()) return true;
- Log.w(TAG, "lost the content due to context change");
- return false;
- }
-
- @Override
- public void yield() {
- // we cannot free the texture because we have no backup.
- }
-
- @Override
- protected int getTarget() {
- return GL11.GL_TEXTURE_2D;
- }
-}
diff --git a/WallpaperPicker/src/com/android/gallery3d/glrenderer/Texture.java b/WallpaperPicker/src/com/android/gallery3d/glrenderer/Texture.java
index 3dcae4aec..e71a379bc 100644
--- a/WallpaperPicker/src/com/android/gallery3d/glrenderer/Texture.java
+++ b/WallpaperPicker/src/com/android/gallery3d/glrenderer/Texture.java
@@ -24,21 +24,14 @@ package com.android.gallery3d.glrenderer;
// This is the current texture hierarchy:
//
// Texture
-// -- ColorTexture
-// -- FadeInTexture
// -- BasicTexture
// -- UploadedTexture
// -- BitmapTexture
// -- Tile
-// -- ResourceTexture
-// -- NinePatchTexture
-// -- CanvasTexture
-// -- StringTexture
//
public interface Texture {
public int getWidth();
public int getHeight();
public void draw(GLCanvas canvas, int x, int y);
public void draw(GLCanvas canvas, int x, int y, int w, int h);
- public boolean isOpaque();
}
diff --git a/WallpaperPicker/src/com/android/gallery3d/glrenderer/UploadedTexture.java b/WallpaperPicker/src/com/android/gallery3d/glrenderer/UploadedTexture.java
index 8075bf868..607e2a943 100644
--- a/WallpaperPicker/src/com/android/gallery3d/glrenderer/UploadedTexture.java
+++ b/WallpaperPicker/src/com/android/gallery3d/glrenderer/UploadedTexture.java
@@ -19,14 +19,12 @@ package com.android.gallery3d.glrenderer;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.opengl.GLUtils;
+import android.util.Pair;
import com.android.gallery3d.common.Utils;
-import com.android.launcher3.util.Thunk;
import java.util.HashMap;
-import javax.microedition.khronos.opengles.GL11;
-
// UploadedTextures use a Bitmap for the content of the texture.
//
// Subclasses should implement onGetBitmap() to provide the Bitmap and
@@ -45,89 +43,29 @@ public abstract class UploadedTexture extends BasicTexture {
// To prevent keeping allocation the borders, we store those used borders here.
// Since the length will be power of two, it won't use too much memory.
- private static HashMap<BorderKey, Bitmap> sBorderLines =
- new HashMap<BorderKey, Bitmap>();
- private static BorderKey sBorderKey = new BorderKey();
-
- @SuppressWarnings("unused")
- private static final String TAG = "Texture";
- private boolean mContentValid = true;
+ private static HashMap<BorderKey, Bitmap> sBorderLines = new HashMap<BorderKey, Bitmap>();
- // indicate this textures is being uploaded in background
- private boolean mIsUploading = false;
- private boolean mOpaque = true;
- private boolean mThrottled = false;
- private static int sUploadedCount;
- private static final int UPLOAD_LIMIT = 100;
+ private static class BorderKey extends Pair<Config, Integer> {
+ public BorderKey(Config config, boolean vertical, int length) {
+ super(config, vertical ? length : -length);
+ }
+ }
+ private boolean mContentValid = true;
protected Bitmap mBitmap;
- private int mBorder;
protected UploadedTexture() {
- this(false);
- }
-
- protected UploadedTexture(boolean hasBorder) {
super(null, 0, STATE_UNLOADED);
- if (hasBorder) {
- setBorder(true);
- mBorder = 1;
- }
- }
-
- protected void setIsUploading(boolean uploading) {
- mIsUploading = uploading;
}
- public boolean isUploading() {
- return mIsUploading;
- }
-
- @Thunk static class BorderKey implements Cloneable {
- public boolean vertical;
- public Config config;
- public int length;
-
- @Override
- public int hashCode() {
- int x = config.hashCode() ^ length;
- return vertical ? x : -x;
- }
-
- @Override
- public boolean equals(Object object) {
- if (!(object instanceof BorderKey)) return false;
- BorderKey o = (BorderKey) object;
- return vertical == o.vertical
- && config == o.config && length == o.length;
- }
-
- @Override
- public BorderKey clone() {
- try {
- return (BorderKey) super.clone();
- } catch (CloneNotSupportedException e) {
- throw new AssertionError(e);
- }
- }
- }
-
- protected void setThrottled(boolean throttled) {
- mThrottled = throttled;
- }
-
- private static Bitmap getBorderLine(
- boolean vertical, Config config, int length) {
- BorderKey key = sBorderKey;
- key.vertical = vertical;
- key.config = config;
- key.length = length;
+ private static Bitmap getBorderLine(boolean vertical, Config config, int length) {
+ BorderKey key = new BorderKey(config, vertical, length);
Bitmap bitmap = sBorderLines.get(key);
if (bitmap == null) {
bitmap = vertical
? Bitmap.createBitmap(1, length, config)
: Bitmap.createBitmap(length, 1, config);
- sBorderLines.put(key.clone(), bitmap);
+ sBorderLines.put(key, bitmap);
}
return bitmap;
}
@@ -135,8 +73,8 @@ public abstract class UploadedTexture extends BasicTexture {
private Bitmap getBitmap() {
if (mBitmap == null) {
mBitmap = onGetBitmap();
- int w = mBitmap.getWidth() + mBorder * 2;
- int h = mBitmap.getHeight() + mBorder * 2;
+ int w = mBitmap.getWidth();
+ int h = mBitmap.getHeight();
if (mWidth == UNSPECIFIED) {
setSize(w, h);
}
@@ -186,37 +124,23 @@ public abstract class UploadedTexture extends BasicTexture {
*/
public void updateContent(GLCanvas canvas) {
if (!isLoaded()) {
- if (mThrottled && ++sUploadedCount > UPLOAD_LIMIT) {
- return;
- }
uploadToCanvas(canvas);
} else if (!mContentValid) {
Bitmap bitmap = getBitmap();
int format = GLUtils.getInternalFormat(bitmap);
int type = GLUtils.getType(bitmap);
- canvas.texSubImage2D(this, mBorder, mBorder, bitmap, format, type);
+ canvas.texSubImage2D(this, 0, 0, bitmap, format, type);
freeBitmap();
mContentValid = true;
}
}
- public static void resetUploadLimit() {
- sUploadedCount = 0;
- }
-
- public static boolean uploadLimitReached() {
- return sUploadedCount > UPLOAD_LIMIT;
- }
-
private void uploadToCanvas(GLCanvas canvas) {
-
Bitmap bitmap = getBitmap();
if (bitmap != null) {
try {
int bWidth = bitmap.getWidth();
int bHeight = bitmap.getHeight();
- int width = bWidth + mBorder * 2;
- int height = bHeight + mBorder * 2;
int texWidth = getTextureWidth();
int texHeight = getTextureHeight();
@@ -234,28 +158,18 @@ public abstract class UploadedTexture extends BasicTexture {
Config config = bitmap.getConfig();
canvas.initializeTextureSize(this, format, type);
- canvas.texSubImage2D(this, mBorder, mBorder, bitmap, format, type);
-
- if (mBorder > 0) {
- // Left border
- Bitmap line = getBorderLine(true, config, texHeight);
- canvas.texSubImage2D(this, 0, 0, line, format, type);
-
- // Top border
- line = getBorderLine(false, config, texWidth);
- canvas.texSubImage2D(this, 0, 0, line, format, type);
- }
+ canvas.texSubImage2D(this, 0, 0, bitmap, format, type);
// Right border
- if (mBorder + bWidth < texWidth) {
+ if (bWidth < texWidth) {
Bitmap line = getBorderLine(true, config, texHeight);
- canvas.texSubImage2D(this, mBorder + bWidth, 0, line, format, type);
+ canvas.texSubImage2D(this, bWidth, 0, line, format, type);
}
// Bottom border
- if (mBorder + bHeight < texHeight) {
+ if (bHeight < texHeight) {
Bitmap line = getBorderLine(false, config, texWidth);
- canvas.texSubImage2D(this, 0, mBorder + bHeight, line, format, type);
+ canvas.texSubImage2D(this, 0, bHeight, line, format, type);
}
}
} finally {
@@ -278,20 +192,6 @@ public abstract class UploadedTexture extends BasicTexture {
}
@Override
- protected int getTarget() {
- return GL11.GL_TEXTURE_2D;
- }
-
- public void setOpaque(boolean isOpaque) {
- mOpaque = isOpaque;
- }
-
- @Override
- public boolean isOpaque() {
- return mOpaque;
- }
-
- @Override
public void recycle() {
super.recycle();
if (mBitmap != null) freeBitmap();
diff --git a/WallpaperPicker/src/com/android/launcher3/CropView.java b/WallpaperPicker/src/com/android/launcher3/CropView.java
index e98e23e98..4770a7177 100644
--- a/WallpaperPicker/src/com/android/launcher3/CropView.java
+++ b/WallpaperPicker/src/com/android/launcher3/CropView.java
@@ -31,7 +31,7 @@ import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import com.android.photos.views.TiledImageRenderer.TileSource;
import com.android.photos.views.TiledImageView;
-public class CropView extends TiledImageView implements OnScaleGestureListener {
+public class CropView extends TiledImageView implements OnScaleGestureListener {
private ScaleGestureDetector mScaleGestureDetector;
private long mTouchDownTime;
diff --git a/WallpaperPicker/src/com/android/launcher3/LiveWallpaperListAdapter.java b/WallpaperPicker/src/com/android/launcher3/LiveWallpaperListAdapter.java
deleted file mode 100644
index b53fce119..000000000
--- a/WallpaperPicker/src/com/android/launcher3/LiveWallpaperListAdapter.java
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * Copyright (C) 2010 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.launcher3;
-
-import android.app.WallpaperInfo;
-import android.app.WallpaperManager;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.graphics.drawable.Drawable;
-import android.os.AsyncTask;
-import android.service.wallpaper.WallpaperService;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.BaseAdapter;
-import android.widget.ImageView;
-import android.widget.ListAdapter;
-import android.widget.TextView;
-
-import com.android.launcher3.util.Thunk;
-
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.IOException;
-import java.text.Collator;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-
-public class LiveWallpaperListAdapter extends BaseAdapter implements ListAdapter {
- private static final String LOG_TAG = "LiveWallpaperListAdapter";
-
- private final LayoutInflater mInflater;
- private final PackageManager mPackageManager;
-
- @Thunk List<LiveWallpaperTile> mWallpapers;
-
- @SuppressWarnings("unchecked")
- public LiveWallpaperListAdapter(Context context) {
- mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- mPackageManager = context.getPackageManager();
-
- List<ResolveInfo> list = mPackageManager.queryIntentServices(
- new Intent(WallpaperService.SERVICE_INTERFACE),
- PackageManager.GET_META_DATA);
-
- mWallpapers = new ArrayList<LiveWallpaperTile>();
-
- new LiveWallpaperEnumerator(context).execute(list);
- }
-
- public int getCount() {
- if (mWallpapers == null) {
- return 0;
- }
- return mWallpapers.size();
- }
-
- public LiveWallpaperTile getItem(int position) {
- return mWallpapers.get(position);
- }
-
- public long getItemId(int position) {
- return position;
- }
-
- public View getView(int position, View convertView, ViewGroup parent) {
- View view;
-
- if (convertView == null) {
- view = mInflater.inflate(R.layout.wallpaper_picker_live_wallpaper_item, parent, false);
- } else {
- view = convertView;
- }
-
- LiveWallpaperTile wallpaperInfo = mWallpapers.get(position);
- wallpaperInfo.setView(view);
- ImageView image = (ImageView) view.findViewById(R.id.wallpaper_image);
- ImageView icon = (ImageView) view.findViewById(R.id.wallpaper_icon);
- if (wallpaperInfo.mThumbnail != null) {
- image.setImageDrawable(wallpaperInfo.mThumbnail);
- icon.setVisibility(View.GONE);
- } else {
- icon.setImageDrawable(wallpaperInfo.mInfo.loadIcon(mPackageManager));
- icon.setVisibility(View.VISIBLE);
- }
-
- TextView label = (TextView) view.findViewById(R.id.wallpaper_item_label);
- label.setText(wallpaperInfo.mInfo.loadLabel(mPackageManager));
-
- return view;
- }
-
- public static class LiveWallpaperTile extends WallpaperPickerActivity.WallpaperTileInfo {
- @Thunk Drawable mThumbnail;
- @Thunk WallpaperInfo mInfo;
- public LiveWallpaperTile(Drawable thumbnail, WallpaperInfo info, Intent intent) {
- mThumbnail = thumbnail;
- mInfo = info;
- }
- @Override
- public void onClick(WallpaperPickerActivity a) {
- Intent preview = new Intent(WallpaperManager.ACTION_CHANGE_LIVE_WALLPAPER);
- preview.putExtra(WallpaperManager.EXTRA_LIVE_WALLPAPER_COMPONENT,
- mInfo.getComponent());
- a.startActivityForResultSafely(preview,
- WallpaperPickerActivity.PICK_WALLPAPER_THIRD_PARTY_ACTIVITY);
- }
- }
-
- private class LiveWallpaperEnumerator extends
- AsyncTask<List<ResolveInfo>, LiveWallpaperTile, Void> {
- private Context mContext;
- private int mWallpaperPosition;
-
- public LiveWallpaperEnumerator(Context context) {
- super();
- mContext = context;
- mWallpaperPosition = 0;
- }
-
- @Override
- protected Void doInBackground(List<ResolveInfo>... params) {
- final PackageManager packageManager = mContext.getPackageManager();
-
- List<ResolveInfo> list = params[0];
-
- Collections.sort(list, new Comparator<ResolveInfo>() {
- final Collator mCollator;
-
- {
- mCollator = Collator.getInstance();
- }
-
- public int compare(ResolveInfo info1, ResolveInfo info2) {
- return mCollator.compare(info1.loadLabel(packageManager),
- info2.loadLabel(packageManager));
- }
- });
-
- for (ResolveInfo resolveInfo : list) {
- WallpaperInfo info = null;
- try {
- info = new WallpaperInfo(mContext, resolveInfo);
- } catch (XmlPullParserException e) {
- Log.w(LOG_TAG, "Skipping wallpaper " + resolveInfo.serviceInfo, e);
- continue;
- } catch (IOException e) {
- Log.w(LOG_TAG, "Skipping wallpaper " + resolveInfo.serviceInfo, e);
- continue;
- }
-
-
- Drawable thumb = info.loadThumbnail(packageManager);
- Intent launchIntent = new Intent(WallpaperService.SERVICE_INTERFACE);
- launchIntent.setClassName(info.getPackageName(), info.getServiceName());
- LiveWallpaperTile wallpaper = new LiveWallpaperTile(thumb, info, launchIntent);
- publishProgress(wallpaper);
- }
- // Send a null object to show loading is finished
- publishProgress((LiveWallpaperTile) null);
-
- return null;
- }
-
- @Override
- protected void onProgressUpdate(LiveWallpaperTile...infos) {
- for (LiveWallpaperTile info : infos) {
- if (info == null) {
- LiveWallpaperListAdapter.this.notifyDataSetChanged();
- break;
- }
- if (info.mThumbnail != null) {
- info.mThumbnail.setDither(true);
- }
- if (mWallpaperPosition < mWallpapers.size()) {
- mWallpapers.set(mWallpaperPosition, info);
- } else {
- mWallpapers.add(info);
- }
- mWallpaperPosition++;
- }
- }
- }
-}
diff --git a/WallpaperPicker/src/com/android/launcher3/SavedWallpaperImages.java b/WallpaperPicker/src/com/android/launcher3/SavedWallpaperImages.java
index 64b0ac466..9124e414a 100644
--- a/WallpaperPicker/src/com/android/launcher3/SavedWallpaperImages.java
+++ b/WallpaperPicker/src/com/android/launcher3/SavedWallpaperImages.java
@@ -26,29 +26,24 @@ import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.Log;
-import android.util.Pair;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.BaseAdapter;
-import android.widget.ListAdapter;
+
+import com.android.launcher3.wallpapertileinfo.FileWallpaperInfo;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.List;
+public class SavedWallpaperImages {
-public class SavedWallpaperImages extends BaseAdapter implements ListAdapter {
private static String TAG = "Launcher3.SavedWallpaperImages";
- private ImageDb mDb;
- ArrayList<SavedWallpaperTile> mImages;
- Context mContext;
- LayoutInflater mLayoutInflater;
- public static class SavedWallpaperTile extends WallpaperPickerActivity.FileWallpaperInfo {
+ public static class SavedWallpaperInfo extends FileWallpaperInfo {
+
private int mDbId;
- public SavedWallpaperTile(int dbId, File target, Drawable thumb) {
+
+ public SavedWallpaperInfo(int dbId, File target, Drawable thumb) {
super(target, thumb);
mDbId = dbId;
}
@@ -59,19 +54,22 @@ public class SavedWallpaperImages extends BaseAdapter implements ListAdapter {
}
}
+ private final ImageDb mDb;
+ private final Context mContext;
+
public SavedWallpaperImages(Context context) {
// We used to store the saved images in the cache directory, but that meant they'd get
// deleted sometimes-- move them to the data directory
ImageDb.moveFromCacheDirectoryIfNecessary(context);
mDb = new ImageDb(context);
mContext = context;
- mLayoutInflater = LayoutInflater.from(context);
}
- public void loadThumbnailsAndImageIdList() {
- mImages = new ArrayList<SavedWallpaperTile>();
+ public List<SavedWallpaperInfo> loadThumbnailsAndImageIdList() {
+ List<SavedWallpaperInfo> result = new ArrayList<SavedWallpaperInfo>();
+
SQLiteDatabase db = mDb.getReadableDatabase();
- Cursor result = db.query(ImageDb.TABLE_NAME,
+ Cursor c = db.query(ImageDb.TABLE_NAME,
new String[] { ImageDb.COLUMN_ID,
ImageDb.COLUMN_IMAGE_THUMBNAIL_FILENAME,
ImageDb.COLUMN_IMAGE_FILENAME}, // cols to return
@@ -82,43 +80,24 @@ public class SavedWallpaperImages extends BaseAdapter implements ListAdapter {
ImageDb.COLUMN_ID + " DESC",
null);
- while (result.moveToNext()) {
- String filename = result.getString(1);
+ while (c.moveToNext()) {
+ String filename = c.getString(1);
File file = new File(mContext.getFilesDir(), filename);
Bitmap thumb = BitmapFactory.decodeFile(file.getAbsolutePath());
if (thumb != null) {
- mImages.add(new SavedWallpaperTile(result.getInt(0),
- new File(mContext.getFilesDir(), result.getString(2)),
- new BitmapDrawable(thumb)));
+ result.add(new SavedWallpaperInfo(c.getInt(0),
+ new File(mContext.getFilesDir(), c.getString(2)),
+ new BitmapDrawable(mContext.getResources(), thumb)));
}
}
- result.close();
- }
-
- public int getCount() {
- return mImages.size();
+ c.close();
+ return result;
}
- public SavedWallpaperTile getItem(int position) {
- return mImages.get(position);
- }
-
- public long getItemId(int position) {
- return position;
- }
-
- public View getView(int position, View convertView, ViewGroup parent) {
- Drawable thumbDrawable = mImages.get(position).mThumb;
- if (thumbDrawable == null) {
- Log.e(TAG, "Error decoding thumbnail for wallpaper #" + position);
- }
- return WallpaperPickerActivity.createImageTileView(
- mLayoutInflater, convertView, parent, thumbDrawable);
- }
+ public void deleteImage(int id) {
+ SQLiteDatabase db = mDb.getWritableDatabase();
- private Pair<String, String> getImageFilenames(int id) {
- SQLiteDatabase db = mDb.getReadableDatabase();
Cursor result = db.query(ImageDb.TABLE_NAME,
new String[] { ImageDb.COLUMN_IMAGE_THUMBNAIL_FILENAME,
ImageDb.COLUMN_IMAGE_FILENAME }, // cols to return
@@ -128,24 +107,12 @@ public class SavedWallpaperImages extends BaseAdapter implements ListAdapter {
null,
null,
null);
- if (result.getCount() > 0) {
- result.moveToFirst();
- String thumbFilename = result.getString(0);
- String imageFilename = result.getString(1);
- result.close();
- return new Pair<String, String>(thumbFilename, imageFilename);
- } else {
- return null;
+ if (result.moveToFirst()) {
+ new File(mContext.getFilesDir(), result.getString(0)).delete();
+ new File(mContext.getFilesDir(), result.getString(1)).delete();
}
- }
+ result.close();
- public void deleteImage(int id) {
- Pair<String, String> filenames = getImageFilenames(id);
- File imageFile = new File(mContext.getFilesDir(), filenames.first);
- imageFile.delete();
- File thumbFile = new File(mContext.getFilesDir(), filenames.second);
- thumbFile.delete();
- SQLiteDatabase db = mDb.getWritableDatabase();
db.delete(ImageDb.TABLE_NAME,
ImageDb.COLUMN_ID + " = ?", // SELECT query
new String[] {
@@ -177,20 +144,16 @@ public class SavedWallpaperImages extends BaseAdapter implements ListAdapter {
}
}
- static class ImageDb extends SQLiteOpenHelper {
+ private static class ImageDb extends SQLiteOpenHelper {
final static int DB_VERSION = 1;
final static String TABLE_NAME = "saved_wallpaper_images";
final static String COLUMN_ID = "id";
final static String COLUMN_IMAGE_THUMBNAIL_FILENAME = "image_thumbnail";
final static String COLUMN_IMAGE_FILENAME = "image";
- Context mContext;
-
public ImageDb(Context context) {
super(context, context.getDatabasePath(LauncherFiles.WALLPAPER_IMAGES_DB).getPath(),
null, DB_VERSION);
- // Store the context for later use
- mContext = context;
}
public static void moveFromCacheDirectoryIfNecessary(Context context) {
diff --git a/WallpaperPicker/src/com/android/launcher3/ThirdPartyWallpaperPickerListAdapter.java b/WallpaperPicker/src/com/android/launcher3/ThirdPartyWallpaperPickerListAdapter.java
deleted file mode 100644
index 099bbda7b..000000000
--- a/WallpaperPicker/src/com/android/launcher3/ThirdPartyWallpaperPickerListAdapter.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (C) 2010 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.launcher3;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.BaseAdapter;
-import android.widget.ListAdapter;
-import android.widget.TextView;
-
-import com.android.launcher3.util.Thunk;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class ThirdPartyWallpaperPickerListAdapter extends BaseAdapter implements ListAdapter {
- private final LayoutInflater mInflater;
- private final PackageManager mPackageManager;
- private final int mIconSize;
-
- private List<ThirdPartyWallpaperTile> mThirdPartyWallpaperPickers =
- new ArrayList<ThirdPartyWallpaperTile>();
-
- public static class ThirdPartyWallpaperTile extends WallpaperPickerActivity.WallpaperTileInfo {
- @Thunk ResolveInfo mResolveInfo;
- public ThirdPartyWallpaperTile(ResolveInfo resolveInfo) {
- mResolveInfo = resolveInfo;
- }
- @Override
- public void onClick(WallpaperPickerActivity a) {
- final ComponentName itemComponentName = new ComponentName(
- mResolveInfo.activityInfo.packageName, mResolveInfo.activityInfo.name);
- Intent launchIntent = new Intent(Intent.ACTION_SET_WALLPAPER);
- launchIntent.setComponent(itemComponentName)
- .putExtra(WallpaperPickerActivity.EXTRA_WALLPAPER_OFFSET,
- a.getWallpaperParallaxOffset());
- a.startActivityForResultSafely(
- launchIntent, WallpaperPickerActivity.PICK_WALLPAPER_THIRD_PARTY_ACTIVITY);
- }
- }
-
- public ThirdPartyWallpaperPickerListAdapter(Context context) {
- mInflater = LayoutInflater.from(context);
- mPackageManager = context.getPackageManager();
- mIconSize = context.getResources().getDimensionPixelSize(R.dimen.wallpaperItemIconSize);
- final PackageManager pm = mPackageManager;
-
- final Intent pickWallpaperIntent = new Intent(Intent.ACTION_SET_WALLPAPER);
- final List<ResolveInfo> apps =
- pm.queryIntentActivities(pickWallpaperIntent, 0);
-
- // Get list of image picker intents
- Intent pickImageIntent = new Intent(Intent.ACTION_GET_CONTENT);
- pickImageIntent.setType("image/*");
- final List<ResolveInfo> imagePickerActivities =
- pm.queryIntentActivities(pickImageIntent, 0);
- final ComponentName[] imageActivities = new ComponentName[imagePickerActivities.size()];
- for (int i = 0; i < imagePickerActivities.size(); i++) {
- ActivityInfo activityInfo = imagePickerActivities.get(i).activityInfo;
- imageActivities[i] = new ComponentName(activityInfo.packageName, activityInfo.name);
- }
-
- outerLoop:
- for (ResolveInfo info : apps) {
- final ComponentName itemComponentName =
- new ComponentName(info.activityInfo.packageName, info.activityInfo.name);
- final String itemPackageName = itemComponentName.getPackageName();
- // Exclude anything from our own package, and the old Launcher,
- // and live wallpaper picker
- if (itemPackageName.equals(context.getPackageName()) ||
- itemPackageName.equals("com.android.launcher") ||
- itemPackageName.equals("com.android.wallpaper.livepicker")) {
- continue;
- }
- // Exclude any package that already responds to the image picker intent
- for (ResolveInfo imagePickerActivityInfo : imagePickerActivities) {
- if (itemPackageName.equals(
- imagePickerActivityInfo.activityInfo.packageName)) {
- continue outerLoop;
- }
- }
- mThirdPartyWallpaperPickers.add(new ThirdPartyWallpaperTile(info));
- }
- }
-
- public int getCount() {
- return mThirdPartyWallpaperPickers.size();
- }
-
- public ThirdPartyWallpaperTile getItem(int position) {
- return mThirdPartyWallpaperPickers.get(position);
- }
-
- public long getItemId(int position) {
- return position;
- }
-
- public View getView(int position, View convertView, ViewGroup parent) {
- View view;
-
- if (convertView == null) {
- view = mInflater.inflate(R.layout.wallpaper_picker_third_party_item, parent, false);
- } else {
- view = convertView;
- }
-
- ResolveInfo info = mThirdPartyWallpaperPickers.get(position).mResolveInfo;
- TextView label = (TextView) view.findViewById(R.id.wallpaper_item_label);
- label.setText(info.loadLabel(mPackageManager));
- Drawable icon = info.loadIcon(mPackageManager);
- icon.setBounds(new Rect(0, 0, mIconSize, mIconSize));
- label.setCompoundDrawables(null, icon, null, null);
- return view;
- }
-}
diff --git a/WallpaperPicker/src/com/android/launcher3/ToggleOnTapCallback.java b/WallpaperPicker/src/com/android/launcher3/ToggleOnTapCallback.java
new file mode 100644
index 000000000..2bc48ee17
--- /dev/null
+++ b/WallpaperPicker/src/com/android/launcher3/ToggleOnTapCallback.java
@@ -0,0 +1,67 @@
+package com.android.launcher3;
+
+import android.view.View;
+import android.view.ViewPropertyAnimator;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.DecelerateInterpolator;
+
+import com.android.launcher3.util.Thunk;
+
+/**
+ * Callback that toggles the visibility of the target view when crop view is tapped.
+ */
+public class ToggleOnTapCallback implements CropView.TouchCallback {
+
+ @Thunk final View mViewtoToggle;
+
+ private ViewPropertyAnimator mAnim;
+ private boolean mIgnoreNextTap;
+
+ public ToggleOnTapCallback(View viewtoHide) {
+ mViewtoToggle = viewtoHide;
+ }
+
+ @Override
+ public void onTouchDown() {
+ if (mAnim != null) {
+ mAnim.cancel();
+ }
+ if (mViewtoToggle.getAlpha() == 1f) {
+ mIgnoreNextTap = true;
+ }
+
+ mAnim = mViewtoToggle.animate();
+ mAnim.alpha(0f)
+ .setDuration(150)
+ .withEndAction(new Runnable() {
+ public void run() {
+ mViewtoToggle.setVisibility(View.INVISIBLE);
+ }
+ });
+
+ mAnim.setInterpolator(new AccelerateInterpolator(0.75f));
+ mAnim.start();
+ }
+
+ @Override
+ public void onTouchUp() {
+ mIgnoreNextTap = false;
+ }
+
+ @Override
+ public void onTap() {
+ boolean ignoreTap = mIgnoreNextTap;
+ mIgnoreNextTap = false;
+ if (!ignoreTap) {
+ if (mAnim != null) {
+ mAnim.cancel();
+ }
+ mViewtoToggle.setVisibility(View.VISIBLE);
+ mAnim = mViewtoToggle.animate();
+ mAnim.alpha(1f)
+ .setDuration(150)
+ .setInterpolator(new DecelerateInterpolator(0.75f));
+ mAnim.start();
+ }
+ }
+}
diff --git a/WallpaperPicker/src/com/android/launcher3/WallpaperCropActivity.java b/WallpaperPicker/src/com/android/launcher3/WallpaperCropActivity.java
index b717b597c..4be6f17ac 100644
--- a/WallpaperPicker/src/com/android/launcher3/WallpaperCropActivity.java
+++ b/WallpaperPicker/src/com/android/launcher3/WallpaperCropActivity.java
@@ -20,15 +20,14 @@ import android.annotation.TargetApi;
import android.app.ActionBar;
import android.app.Activity;
import android.app.WallpaperManager;
-import android.content.Context;
import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.res.Configuration;
+import android.content.pm.ActivityInfo;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.RectF;
+import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
@@ -58,24 +57,10 @@ import java.util.WeakHashMap;
public class WallpaperCropActivity extends BaseActivity implements Handler.Callback {
private static final String LOGTAG = "Launcher3.CropActivity";
- protected static final String WALLPAPER_WIDTH_KEY = WallpaperUtils.WALLPAPER_WIDTH_KEY;
- protected static final String WALLPAPER_HEIGHT_KEY = WallpaperUtils.WALLPAPER_HEIGHT_KEY;
-
- /**
- * The maximum bitmap size we allow to be returned through the intent.
- * Intents have a maximum of 1MB in total size. However, the Bitmap seems to
- * have some overhead to hit so that we go way below the limit here to make
- * sure the intent stays below 1MB.We should consider just returning a byte
- * array instead of a Bitmap instance to avoid overhead.
- */
- public static final int MAX_BMAP_IN_INTENT = 750000;
- public static final float WALLPAPER_SCREENS_SPAN = WallpaperUtils.WALLPAPER_SCREENS_SPAN;
-
private static final int MSG_LOAD_IMAGE = 1;
protected CropView mCropView;
protected View mProgressView;
- protected Uri mUri;
protected View mSetWallpaperButton;
private HandlerThread mLoaderThread;
@@ -96,7 +81,7 @@ public class WallpaperCropActivity extends BaseActivity implements Handler.Callb
init();
if (!enableRotation()) {
- setRequestedOrientation(Configuration.ORIENTATION_PORTRAIT);
+ setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
}
@@ -123,12 +108,9 @@ public class WallpaperCropActivity extends BaseActivity implements Handler.Callb
new View.OnClickListener() {
@Override
public void onClick(View v) {
- boolean finishActivityWhenDone = true;
// Never fade on finish because we return to the app that started us (e.g.
// Photos), not the home screen.
- boolean shouldFadeOutOnFinish = false;
- cropImageAndSetWallpaper(imageUri, null, finishActivityWhenDone,
- shouldFadeOutOnFinish);
+ cropImageAndSetWallpaper(imageUri, null, false /* shouldFadeOutOnFinish */);
}
});
mSetWallpaperButton = findViewById(R.id.set_wallpaper_button);
@@ -169,52 +151,71 @@ public class WallpaperCropActivity extends BaseActivity implements Handler.Callb
public boolean handleMessage(Message msg) {
if (msg.what == MSG_LOAD_IMAGE) {
final LoadRequest req = (LoadRequest) msg.obj;
- try {
- req.src.loadInBackground(new InBitmapProvider() {
+ final boolean loadSuccess;
- @Override
- public Bitmap forPixelCount(int count) {
- Bitmap bitmapToReuse = null;
- // Find the smallest bitmap that satisfies the pixel count limit
- synchronized (mReusableBitmaps) {
- int currentBitmapSize = Integer.MAX_VALUE;
- for (Bitmap b : mReusableBitmaps) {
- int bitmapSize = b.getWidth() * b.getHeight();
- if ((bitmapSize >= count) && (bitmapSize < currentBitmapSize)) {
- bitmapToReuse = b;
- currentBitmapSize = bitmapSize;
+ if (req.src == null) {
+ Drawable defaultWallpaper = WallpaperManager.getInstance(this)
+ .getBuiltInDrawable(mCropView.getWidth(), mCropView.getHeight(),
+ false, 0.5f, 0.5f);
+
+ if (defaultWallpaper == null) {
+ loadSuccess = false;
+ Log.w(LOGTAG, "Null default wallpaper encountered.");
+ } else {
+ loadSuccess = true;
+ req.result = new DrawableTileSource(this,
+ defaultWallpaper, DrawableTileSource.MAX_PREVIEW_SIZE);
+ }
+ } else {
+ try {
+ req.src.loadInBackground(new InBitmapProvider() {
+
+ @Override
+ public Bitmap forPixelCount(int count) {
+ Bitmap bitmapToReuse = null;
+ // Find the smallest bitmap that satisfies the pixel count limit
+ synchronized (mReusableBitmaps) {
+ int currentBitmapSize = Integer.MAX_VALUE;
+ for (Bitmap b : mReusableBitmaps) {
+ int bitmapSize = b.getWidth() * b.getHeight();
+ if ((bitmapSize >= count) && (bitmapSize < currentBitmapSize)) {
+ bitmapToReuse = b;
+ currentBitmapSize = bitmapSize;
+ }
}
- }
- if (bitmapToReuse != null) {
- mReusableBitmaps.remove(bitmapToReuse);
+ if (bitmapToReuse != null) {
+ mReusableBitmaps.remove(bitmapToReuse);
+ }
}
+ return bitmapToReuse;
}
- return bitmapToReuse;
+ });
+ } catch (SecurityException securityException) {
+ if (isActivityDestroyed()) {
+ // Temporarily granted permissions are revoked when the activity
+ // finishes, potentially resulting in a SecurityException here.
+ // Even though {@link #isDestroyed} might also return true in different
+ // situations where the configuration changes, we are fine with
+ // catching these cases here as well.
+ return true;
+ } else {
+ // otherwise it had a different cause and we throw it further
+ throw securityException;
}
- });
- } catch (SecurityException securityException) {
- if (isActivityDestroyed()) {
- // Temporarily granted permissions are revoked when the activity
- // finishes, potentially resulting in a SecurityException here.
- // Even though {@link #isDestroyed} might also return true in different
- // situations where the configuration changes, we are fine with
- // catching these cases here as well.
- return true;
- } else {
- // otherwise it had a different cause and we throw it further
- throw securityException;
}
+
+ req.result = new BitmapRegionTileSource(getContext(), req.src,
+ mTempStorageForDecoding);
+ loadSuccess = req.src.getLoadingState() == BitmapSource.State.LOADED;
}
- req.result = new BitmapRegionTileSource(getContext(), req.src, mTempStorageForDecoding);
runOnUiThread(new Runnable() {
@Override
public void run() {
if (req == mCurrentLoadRequest) {
- onLoadRequestComplete(req,
- req.src.getLoadingState() == BitmapSource.State.LOADED);
+ onLoadRequestComplete(req, loadSuccess);
} else {
addReusableBitmap(req.result);
}
@@ -226,7 +227,7 @@ public class WallpaperCropActivity extends BaseActivity implements Handler.Callb
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
- protected boolean isActivityDestroyed() {
+ public boolean isActivityDestroyed() {
return Utilities.ATLEAST_JB_MR1 && isDestroyed();
}
@@ -274,14 +275,16 @@ public class WallpaperCropActivity extends BaseActivity implements Handler.Callb
mProgressView.setVisibility(View.GONE);
}
+ @TargetApi(Build.VERSION_CODES.KITKAT)
public final void setCropViewTileSource(BitmapSource bitmapSource, boolean touchEnabled,
- boolean moveToLeft, CropViewScaleAndOffsetProvider scaleProvider, Runnable postExecute) {
+ boolean moveToLeft, CropViewScaleAndOffsetProvider scaleAndOffsetProvider,
+ Runnable postExecute) {
final LoadRequest req = new LoadRequest();
req.moveToLeft = moveToLeft;
req.src = bitmapSource;
req.touchEnabled = touchEnabled;
req.postExecute = postExecute;
- req.scaleAndOffsetProvider = scaleProvider;
+ req.scaleAndOffsetProvider = scaleAndOffsetProvider;
mCurrentLoadRequest = req;
// Remove any pending requests
@@ -305,62 +308,39 @@ public class WallpaperCropActivity extends BaseActivity implements Handler.Callb
return getResources().getBoolean(R.bool.allow_rotation);
}
- protected void setWallpaper(Uri uri, final boolean finishActivityWhenDone,
- final boolean shouldFadeOutOnFinish) {
+ public void setWallpaper(Uri uri, boolean shouldFadeOutOnFinish) {
int rotation = BitmapUtils.getRotationFromExif(getContext(), uri);
BitmapCropTask cropTask = new BitmapCropTask(
getContext(), uri, null, rotation, 0, 0, true, false, null);
- final Point bounds = cropTask.getImageBounds();
- BitmapCropTask.OnEndCropHandler onEndCrop = new BitmapCropTask.OnEndCropHandler() {
- public void run(boolean cropSucceeded) {
- updateWallpaperDimensions(bounds.x, bounds.y);
- if (finishActivityWhenDone) {
- setResult(Activity.RESULT_OK);
- finish();
- if (cropSucceeded && shouldFadeOutOnFinish) {
- overridePendingTransition(0, R.anim.fade_out);
- }
- }
- }
- };
- cropTask.setOnEndRunnable(onEndCrop);
+ BitmapCropTask.OnEndCropHandler onEndCrop = new CropAndFinishHandler(
+ cropTask.getImageBounds(), shouldFadeOutOnFinish);
+ cropTask.setOnEndCropHandler(onEndCrop);
cropTask.setNoCrop(true);
cropTask.execute();
}
- protected void cropImageAndSetWallpaper(Resources res, int resId,
- final boolean finishActivityWhenDone, final boolean shouldFadeOutOnFinish) {
+ public void cropImageAndSetWallpaper(Resources res, int resId, boolean shouldFadeOutOnFinish) {
// crop this image and scale it down to the default wallpaper size for
// this device
- int rotation = BitmapUtils.getRotationFromExif(res, resId);
+ int rotation = BitmapUtils.getRotationFromExif(res, resId, this);
Point inSize = mCropView.getSourceDimensions();
Point outSize = WallpaperUtils.getDefaultWallpaperSize(getResources(),
getWindowManager());
RectF crop = Utils.getMaxCropRect(
inSize.x, inSize.y, outSize.x, outSize.y, false);
- BitmapCropTask.OnEndCropHandler onEndCrop = new BitmapCropTask.OnEndCropHandler() {
- public void run(boolean cropSucceeded) {
- // Passing 0, 0 will cause launcher to revert to using the
- // default wallpaper size
- updateWallpaperDimensions(0, 0);
- if (finishActivityWhenDone) {
- setResult(Activity.RESULT_OK);
- finish();
- if (cropSucceeded && shouldFadeOutOnFinish) {
- overridePendingTransition(0, R.anim.fade_out);
- }
- }
- }
- };
+ // Passing 0, 0 will cause launcher to revert to using the
+ // default wallpaper size
+ CropAndFinishHandler onEndCrop = new CropAndFinishHandler(new Point(0, 0),
+ shouldFadeOutOnFinish);
BitmapCropTask cropTask = new BitmapCropTask(getContext(), res, resId,
crop, rotation, outSize.x, outSize.y, true, false, onEndCrop);
cropTask.execute();
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
- protected void cropImageAndSetWallpaper(Uri uri,
+ public void cropImageAndSetWallpaper(Uri uri,
BitmapCropTask.OnBitmapCroppedHandler onBitmapCroppedHandler,
- final boolean finishActivityWhenDone, final boolean shouldFadeOutOnFinish) {
+ boolean shouldFadeOutOnFinish) {
// Give some feedback so user knows something is happening.
mProgressView.setVisibility(View.VISIBLE);
@@ -436,21 +416,12 @@ public class WallpaperCropActivity extends BaseActivity implements Handler.Callb
cropRect.top -= expandHeight;
cropRect.bottom += expandHeight;
}
+
final int outWidth = (int) Math.round(cropRect.width() * cropScale);
final int outHeight = (int) Math.round(cropRect.height() * cropScale);
+ CropAndFinishHandler onEndCrop = new CropAndFinishHandler(new Point(outWidth, outHeight),
+ shouldFadeOutOnFinish);
- BitmapCropTask.OnEndCropHandler onEndCrop = new BitmapCropTask.OnEndCropHandler() {
- public void run(boolean cropSucceeded) {
- updateWallpaperDimensions(outWidth, outHeight);
- if (finishActivityWhenDone) {
- setResult(Activity.RESULT_OK);
- finish();
- }
- if (cropSucceeded && shouldFadeOutOnFinish) {
- overridePendingTransition(0, R.anim.fade_out);
- }
- }
- };
BitmapCropTask cropTask = new BitmapCropTask(getContext(), uri,
cropRect, cropRotation, outWidth, outHeight, true, false, onEndCrop);
if (onBitmapCroppedHandler != null) {
@@ -459,20 +430,30 @@ public class WallpaperCropActivity extends BaseActivity implements Handler.Callb
cropTask.execute();
}
- protected void updateWallpaperDimensions(int width, int height) {
- String spKey = LauncherFiles.WALLPAPER_CROP_PREFERENCES_KEY;
- SharedPreferences sp = getContext().getSharedPreferences(spKey, Context.MODE_MULTI_PROCESS);
- SharedPreferences.Editor editor = sp.edit();
- if (width != 0 && height != 0) {
- editor.putInt(WALLPAPER_WIDTH_KEY, width);
- editor.putInt(WALLPAPER_HEIGHT_KEY, height);
- } else {
- editor.remove(WALLPAPER_WIDTH_KEY);
- editor.remove(WALLPAPER_HEIGHT_KEY);
+ public class CropAndFinishHandler implements BitmapCropTask.OnEndCropHandler {
+ private final Point mBounds;
+ private boolean mShouldFadeOutOnFinish;
+
+ /**
+ * @param shouldFadeOutOnFinish Whether the wallpaper picker should override the default
+ * exit animation to fade out instead. This should only be set to true if the wallpaper
+ * preview will exactly match the actual wallpaper on the page we are returning to.
+ */
+ public CropAndFinishHandler(Point bounds, boolean shouldFadeOutOnFinish) {
+ mBounds = bounds;
+ mShouldFadeOutOnFinish = shouldFadeOutOnFinish;
+ }
+
+ @Override
+ public void run(boolean cropSucceeded) {
+ WallpaperUtils.saveWallpaperDimensions(mBounds.x, mBounds.y,
+ WallpaperCropActivity.this);
+ setResult(Activity.RESULT_OK);
+ finish();
+ if (cropSucceeded && mShouldFadeOutOnFinish) {
+ overridePendingTransition(0, R.anim.fade_out);
+ }
}
- editor.commit();
- WallpaperUtils.suggestWallpaperDimension(getResources(),
- sp, getWindowManager(), WallpaperManager.getInstance(getContext()), true);
}
static class LoadRequest {
@@ -485,7 +466,7 @@ public class WallpaperCropActivity extends BaseActivity implements Handler.Callb
TileSource result;
}
- interface CropViewScaleAndOffsetProvider {
+ public interface CropViewScaleAndOffsetProvider {
float getScale(Point wallpaperSize, RectF crop);
float getParallaxOffset();
}
diff --git a/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java b/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java
index b40e4bd80..27d60f8b8 100644
--- a/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java
+++ b/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java
@@ -16,38 +16,22 @@
package com.android.launcher3;
-import android.Manifest;
import android.animation.LayoutTransition;
-import android.annotation.TargetApi;
+import android.annotation.SuppressLint;
import android.app.ActionBar;
import android.app.Activity;
-import android.app.WallpaperManager;
-import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
-import android.database.Cursor;
-import android.database.DataSetObserver;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
-import android.graphics.Canvas;
-import android.graphics.Matrix;
-import android.graphics.Point;
-import android.graphics.PorterDuff;
-import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
import android.net.Uri;
-import android.os.AsyncTask;
-import android.os.Build;
import android.os.Bundle;
-import android.os.Process;
-import android.provider.MediaStore;
import android.util.Log;
import android.util.Pair;
import android.view.ActionMode;
-import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
@@ -55,34 +39,30 @@ import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLayoutChangeListener;
+import android.view.View.OnLongClickListener;
import android.view.ViewGroup;
-import android.view.ViewPropertyAnimator;
import android.view.ViewTreeObserver;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.view.WindowManager;
-import android.view.animation.AccelerateInterpolator;
-import android.view.animation.DecelerateInterpolator;
-import android.widget.ArrayAdapter;
-import android.widget.BaseAdapter;
-import android.widget.FrameLayout;
import android.widget.HorizontalScrollView;
-import android.widget.ImageView;
import android.widget.LinearLayout;
-import android.widget.Toast;
-import com.android.gallery3d.common.BitmapCropTask;
-import com.android.gallery3d.common.BitmapUtils;
-import com.android.gallery3d.common.Utils;
import com.android.launcher3.util.Thunk;
-import com.android.photos.BitmapRegionTileSource;
-import com.android.photos.BitmapRegionTileSource.BitmapSource;
+import com.android.launcher3.wallpapertileinfo.DefaultWallpaperInfo;
+import com.android.launcher3.wallpapertileinfo.FileWallpaperInfo;
+import com.android.launcher3.wallpapertileinfo.LiveWallpaperInfo;
+import com.android.launcher3.wallpapertileinfo.PickImageInfo;
+import com.android.launcher3.wallpapertileinfo.ResourceWallpaperInfo;
+import com.android.launcher3.wallpapertileinfo.ThirdPartyWallpaperInfo;
+import com.android.launcher3.wallpapertileinfo.UriWallpaperInfo;
+import com.android.launcher3.wallpapertileinfo.WallpaperTileInfo;
import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
import java.util.ArrayList;
+import java.util.List;
-public class WallpaperPickerActivity extends WallpaperCropActivity {
+public class WallpaperPickerActivity extends WallpaperCropActivity
+ implements OnClickListener, OnLongClickListener, ActionMode.Callback {
static final String TAG = "Launcher.WallpaperPickerActivity";
public static final int IMAGE_PICK = 5;
@@ -93,252 +73,22 @@ public class WallpaperPickerActivity extends WallpaperCropActivity {
private static final String SELECTED_INDEX = "SELECTED_INDEX";
private static final int FLAG_POST_DELAY_MILLIS = 200;
- @Thunk View mSelectedTile;
- @Thunk boolean mIgnoreNextTap;
- @Thunk OnClickListener mThumbnailOnClickListener;
+ @Thunk
+ View mSelectedTile;
@Thunk LinearLayout mWallpapersView;
@Thunk HorizontalScrollView mWallpaperScrollContainer;
@Thunk View mWallpaperStrip;
- @Thunk ActionMode.Callback mActionModeCallback;
@Thunk ActionMode mActionMode;
- @Thunk View.OnLongClickListener mLongClickListener;
-
ArrayList<Uri> mTempWallpaperTiles = new ArrayList<Uri>();
private SavedWallpaperImages mSavedImages;
@Thunk int mSelectedIndex = -1;
private float mWallpaperParallaxOffset;
- public static abstract class WallpaperTileInfo {
- protected View mView;
- public Drawable mThumb;
-
- public void setView(View v) {
- mView = v;
- }
- public void onClick(WallpaperPickerActivity a) {}
- public void onSave(WallpaperPickerActivity a) {}
- public void onDelete(WallpaperPickerActivity a) {}
- public boolean isSelectable() { return false; }
- public boolean isNamelessWallpaper() { return false; }
- public void onIndexUpdated(CharSequence label) {
- if (isNamelessWallpaper()) {
- mView.setContentDescription(label);
- }
- }
- }
-
- public static class PickImageInfo extends WallpaperTileInfo {
- @Override
- public void onClick(WallpaperPickerActivity a) {
- Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
- intent.setType("image/*");
- a.startActivityForResultSafely(intent, IMAGE_PICK);
- }
- }
-
- public static class UriWallpaperInfo extends WallpaperTileInfo {
- private Uri mUri;
- public UriWallpaperInfo(Uri uri) {
- mUri = uri;
- }
- @Override
- public void onClick(final WallpaperPickerActivity a) {
- a.setWallpaperButtonEnabled(false);
- final BitmapRegionTileSource.UriBitmapSource bitmapSource =
- new BitmapRegionTileSource.UriBitmapSource(a.getContext(), mUri);
- a.setCropViewTileSource(bitmapSource, true, false, null, new Runnable() {
-
- @Override
- public void run() {
- if (bitmapSource.getLoadingState() == BitmapSource.State.LOADED) {
- a.selectTile(mView);
- a.setWallpaperButtonEnabled(true);
- } else {
- ViewGroup parent = (ViewGroup) mView.getParent();
- if (parent != null) {
- parent.removeView(mView);
- Toast.makeText(a.getContext(), R.string.image_load_fail,
- Toast.LENGTH_SHORT).show();
- }
- }
- }
- });
- }
- @Override
- public void onSave(final WallpaperPickerActivity a) {
- boolean finishActivityWhenDone = true;
- BitmapCropTask.OnBitmapCroppedHandler h = new BitmapCropTask.OnBitmapCroppedHandler() {
- public void onBitmapCropped(byte[] imageBytes) {
- Point thumbSize = getDefaultThumbnailSize(a.getResources());
- // rotation is set to 0 since imageBytes has already been correctly rotated
- Bitmap thumb = createThumbnail(
- thumbSize, null, null, imageBytes, null, 0, 0, true);
- a.getSavedImages().writeImage(thumb, imageBytes);
- }
- };
- boolean shouldFadeOutOnFinish = a.getWallpaperParallaxOffset() == 0f;
- a.cropImageAndSetWallpaper(mUri, h, finishActivityWhenDone, shouldFadeOutOnFinish);
- }
- @Override
- public boolean isSelectable() {
- return true;
- }
- @Override
- public boolean isNamelessWallpaper() {
- return true;
- }
- }
-
- public static class FileWallpaperInfo extends WallpaperTileInfo {
- private File mFile;
-
- public FileWallpaperInfo(File target, Drawable thumb) {
- mFile = target;
- mThumb = thumb;
- }
- @Override
- public void onClick(final WallpaperPickerActivity a) {
- a.setWallpaperButtonEnabled(false);
- final BitmapRegionTileSource.UriBitmapSource bitmapSource =
- new BitmapRegionTileSource.UriBitmapSource(a.getContext(), Uri.fromFile(mFile));
- a.setCropViewTileSource(bitmapSource, false, true, null, new Runnable() {
-
- @Override
- public void run() {
- if (bitmapSource.getLoadingState() == BitmapSource.State.LOADED) {
- a.setWallpaperButtonEnabled(true);
- }
- }
- });
- }
- @Override
- public void onSave(WallpaperPickerActivity a) {
- boolean shouldFadeOutOnFinish = a.getWallpaperParallaxOffset() == 0f;
- a.setWallpaper(Uri.fromFile(mFile), true, shouldFadeOutOnFinish);
- }
- @Override
- public boolean isSelectable() {
- return true;
- }
- @Override
- public boolean isNamelessWallpaper() {
- return true;
- }
- }
-
- public static class ResourceWallpaperInfo extends WallpaperTileInfo {
- private Resources mResources;
- private int mResId;
-
- public ResourceWallpaperInfo(Resources res, int resId, Drawable thumb) {
- mResources = res;
- mResId = resId;
- mThumb = thumb;
- }
- @Override
- public void onClick(final WallpaperPickerActivity a) {
- a.setWallpaperButtonEnabled(false);
- final BitmapRegionTileSource.ResourceBitmapSource bitmapSource =
- new BitmapRegionTileSource.ResourceBitmapSource(mResources, mResId);
- a.setCropViewTileSource(bitmapSource, false, false, new CropViewScaleAndOffsetProvider() {
-
- @Override
- public float getScale(Point wallpaperSize, RectF crop) {
- return wallpaperSize.x /crop.width();
- }
-
- @Override
- public float getParallaxOffset() {
- return a.getWallpaperParallaxOffset();
- }
- }, new Runnable() {
-
- @Override
- public void run() {
- if (bitmapSource.getLoadingState() == BitmapSource.State.LOADED) {
- a.setWallpaperButtonEnabled(true);
- }
- }
- });
- }
- @Override
- public void onSave(WallpaperPickerActivity a) {
- boolean finishActivityWhenDone = true;
- boolean shouldFadeOutOnFinish = true;
- a.cropImageAndSetWallpaper(mResources, mResId, finishActivityWhenDone,
- shouldFadeOutOnFinish);
- }
- @Override
- public boolean isSelectable() {
- return true;
- }
- @Override
- public boolean isNamelessWallpaper() {
- return true;
- }
- }
-
- @TargetApi(Build.VERSION_CODES.KITKAT)
- public static class DefaultWallpaperInfo extends WallpaperTileInfo {
- public DefaultWallpaperInfo(Drawable thumb) {
- mThumb = thumb;
- }
- @Override
- public void onClick(WallpaperPickerActivity a) {
- CropView c = a.getCropView();
- Drawable defaultWallpaper = WallpaperManager.getInstance(a.getContext())
- .getBuiltInDrawable(c.getWidth(), c.getHeight(), false, 0.5f, 0.5f);
- if (defaultWallpaper == null) {
- Log.w(TAG, "Null default wallpaper encountered.");
- c.setTileSource(null, null);
- return;
- }
-
- LoadRequest req = new LoadRequest();
- req.moveToLeft = false;
- req.touchEnabled = false;
- req.scaleAndOffsetProvider = new CropViewScaleAndOffsetProvider() {
-
- @Override
- public float getScale(Point wallpaperSize, RectF crop) {
- return 1f;
- }
-
- @Override
- public float getParallaxOffset() {
- return 0;
- }
- };
- req.result = new DrawableTileSource(a.getContext(),
- defaultWallpaper, DrawableTileSource.MAX_PREVIEW_SIZE);
- a.onLoadRequestComplete(req, true);
- }
- @Override
- public void onSave(WallpaperPickerActivity a) {
- try {
- WallpaperManager.getInstance(a.getContext()).clear();
- a.setResult(Activity.RESULT_OK);
- } catch (IOException e) {
- Log.w("Setting wallpaper to default threw exception", e);
- }
- a.finish();
- }
- @Override
- public boolean isSelectable() {
- return true;
- }
- @Override
- public boolean isNamelessWallpaper() {
- return true;
- }
- }
-
/**
- * shows the system wallpaper behind the window and hides the {@link
- * #mCropView} if visible
+ * shows the system wallpaper behind the window and hides the {@link #mCropView} if visible
* @param visible should the system wallpaper be shown
*/
protected void setSystemWallpaperVisiblity(final boolean visible) {
@@ -380,7 +130,9 @@ public class WallpaperPickerActivity extends WallpaperCropActivity {
}
}
- // called by onCreate; this is subclassed to overwrite WallpaperCropActivity
+ /**
+ * called by onCreate; this is sub-classed to overwrite WallpaperCropActivity
+ */
protected void init() {
setContentView(R.layout.wallpaper_picker);
@@ -390,139 +142,39 @@ public class WallpaperPickerActivity extends WallpaperCropActivity {
mProgressView = findViewById(R.id.loading);
mWallpaperScrollContainer = (HorizontalScrollView) findViewById(R.id.wallpaper_scroll_container);
mWallpaperStrip = findViewById(R.id.wallpaper_strip);
- mCropView.setTouchCallback(new CropView.TouchCallback() {
- ViewPropertyAnimator mAnim;
- @Override
- public void onTouchDown() {
- if (mAnim != null) {
- mAnim.cancel();
- }
- if (mWallpaperStrip.getAlpha() == 1f) {
- mIgnoreNextTap = true;
- }
- mAnim = mWallpaperStrip.animate();
- mAnim.alpha(0f)
- .setDuration(150)
- .withEndAction(new Runnable() {
- public void run() {
- mWallpaperStrip.setVisibility(View.INVISIBLE);
- }
- });
- mAnim.setInterpolator(new AccelerateInterpolator(0.75f));
- mAnim.start();
- }
- @Override
- public void onTouchUp() {
- mIgnoreNextTap = false;
- }
- @Override
- public void onTap() {
- boolean ignoreTap = mIgnoreNextTap;
- mIgnoreNextTap = false;
- if (!ignoreTap) {
- if (mAnim != null) {
- mAnim.cancel();
- }
- mWallpaperStrip.setVisibility(View.VISIBLE);
- mAnim = mWallpaperStrip.animate();
- mAnim.alpha(1f)
- .setDuration(150)
- .setInterpolator(new DecelerateInterpolator(0.75f));
- mAnim.start();
- }
- }
- });
-
- mThumbnailOnClickListener = new OnClickListener() {
- public void onClick(View v) {
- if (mActionMode != null) {
- // When CAB is up, clicking toggles the item instead
- if (v.isLongClickable()) {
- mLongClickListener.onLongClick(v);
- }
- return;
- }
- setWallpaperButtonEnabled(true);
- WallpaperTileInfo info = (WallpaperTileInfo) v.getTag();
- if (info.isSelectable() && v.getVisibility() == View.VISIBLE) {
- selectTile(v);
- }
- info.onClick(WallpaperPickerActivity.this);
- }
- };
- mLongClickListener = new View.OnLongClickListener() {
- // Called when the user long-clicks on someView
- public boolean onLongClick(View view) {
- CheckableFrameLayout c = (CheckableFrameLayout) view;
- c.toggle();
-
- if (mActionMode != null) {
- mActionMode.invalidate();
- } else {
- // Start the CAB using the ActionMode.Callback defined below
- mActionMode = startActionMode(mActionModeCallback);
- int childCount = mWallpapersView.getChildCount();
- for (int i = 0; i < childCount; i++) {
- mWallpapersView.getChildAt(i).setSelected(false);
- }
- }
- return true;
- }
- };
+ mCropView.setTouchCallback(new ToggleOnTapCallback(mWallpaperStrip));
mWallpaperParallaxOffset = getIntent().getFloatExtra(EXTRA_WALLPAPER_OFFSET, 0);
- // Populate the built-in wallpapers
- ArrayList<WallpaperTileInfo> wallpapers = findBundledWallpapers();
mWallpapersView = (LinearLayout) findViewById(R.id.wallpaper_list);
- SimpleWallpapersAdapter ia = new SimpleWallpapersAdapter(getContext(), wallpapers);
- populateWallpapersFromAdapter(mWallpapersView, ia, false);
-
// Populate the saved wallpapers
mSavedImages = new SavedWallpaperImages(getContext());
- mSavedImages.loadThumbnailsAndImageIdList();
- populateWallpapersFromAdapter(mWallpapersView, mSavedImages, true);
-
- // Populate the live wallpapers
- final LinearLayout liveWallpapersView =
- (LinearLayout) findViewById(R.id.live_wallpaper_list);
- final LiveWallpaperListAdapter a = new LiveWallpaperListAdapter(getContext());
- a.registerDataSetObserver(new DataSetObserver() {
- public void onChanged() {
- liveWallpapersView.removeAllViews();
- populateWallpapersFromAdapter(liveWallpapersView, a, false);
+ populateWallpapers(mWallpapersView, mSavedImages.loadThumbnailsAndImageIdList(), true);
+
+ // Populate the built-in wallpapers
+ ArrayList<WallpaperTileInfo> wallpapers = findBundledWallpapers();
+ populateWallpapers(mWallpapersView, wallpapers, false);
+
+ // Load live wallpapers asynchronously
+ new LiveWallpaperInfo.LoaderTask(this) {
+
+ @Override
+ protected void onPostExecute(List<LiveWallpaperInfo> result) {
+ populateWallpapers((LinearLayout) findViewById(R.id.live_wallpaper_list),
+ result, false);
initializeScrollForRtl();
updateTileIndices();
}
- });
+ }.execute();
// Populate the third-party wallpaper pickers
- final LinearLayout thirdPartyWallpapersView =
- (LinearLayout) findViewById(R.id.third_party_wallpaper_list);
- final ThirdPartyWallpaperPickerListAdapter ta =
- new ThirdPartyWallpaperPickerListAdapter(getContext());
- populateWallpapersFromAdapter(thirdPartyWallpapersView, ta, false);
+ populateWallpapers((LinearLayout) findViewById(R.id.third_party_wallpaper_list),
+ ThirdPartyWallpaperInfo.getAll(this), false /* addLongPressHandler */);
// Add a tile for the Gallery
LinearLayout masterWallpaperList = (LinearLayout) findViewById(R.id.master_wallpaper_list);
- FrameLayout pickImageTile = (FrameLayout) getLayoutInflater().
- inflate(R.layout.wallpaper_picker_image_picker_item, masterWallpaperList, false);
- masterWallpaperList.addView(pickImageTile, 0);
-
- // Make its background the last photo taken on external storage
- Bitmap lastPhoto = getThumbnailOfLastPhoto();
- if (lastPhoto != null) {
- ImageView galleryThumbnailBg =
- (ImageView) pickImageTile.findViewById(R.id.wallpaper_image);
- galleryThumbnailBg.setImageBitmap(lastPhoto);
- int colorOverlay = getResources().getColor(R.color.wallpaper_picker_translucent_gray);
- galleryThumbnailBg.setColorFilter(colorOverlay, PorterDuff.Mode.SRC_ATOP);
- }
-
- PickImageInfo pickImageInfo = new PickImageInfo();
- pickImageTile.setTag(pickImageInfo);
- pickImageInfo.setView(pickImageTile);
- pickImageTile.setOnClickListener(mThumbnailOnClickListener);
+ masterWallpaperList.addView(
+ createTileView(masterWallpaperList, new PickImageInfo(), false), 0);
// Select the first item; wait for a layout pass so that we initialize the dimensions of
// cropView or the defaultWallpaperView first
@@ -532,8 +184,7 @@ public class WallpaperPickerActivity extends WallpaperCropActivity {
int oldLeft, int oldTop, int oldRight, int oldBottom) {
if ((right - left) > 0 && (bottom - top) > 0) {
if (mSelectedIndex >= 0 && mSelectedIndex < mWallpapersView.getChildCount()) {
- mThumbnailOnClickListener.onClick(
- mWallpapersView.getChildAt(mSelectedIndex));
+ onClick(mWallpapersView.getChildAt(mSelectedIndex));
setSystemWallpaperVisiblity(false);
}
v.removeOnLayoutChangeListener(this);
@@ -577,95 +228,47 @@ public class WallpaperPickerActivity extends WallpaperCropActivity {
}
});
mSetWallpaperButton = findViewById(R.id.set_wallpaper_button);
+ }
- // CAB for deleting items
- mActionModeCallback = new ActionMode.Callback() {
- // Called when the action mode is created; startActionMode() was called
- @Override
- public boolean onCreateActionMode(ActionMode mode, Menu menu) {
- // Inflate a menu resource providing context menu items
- MenuInflater inflater = mode.getMenuInflater();
- inflater.inflate(R.menu.cab_delete_wallpapers, menu);
- return true;
- }
-
- private int numCheckedItems() {
- int childCount = mWallpapersView.getChildCount();
- int numCheckedItems = 0;
- for (int i = 0; i < childCount; i++) {
- CheckableFrameLayout c = (CheckableFrameLayout) mWallpapersView.getChildAt(i);
- if (c.isChecked()) {
- numCheckedItems++;
- }
- }
- return numCheckedItems;
- }
-
- // Called each time the action mode is shown. Always called after onCreateActionMode,
- // but may be called multiple times if the mode is invalidated.
- @Override
- public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
- int numCheckedItems = numCheckedItems();
- if (numCheckedItems == 0) {
- mode.finish();
- return true;
- } else {
- mode.setTitle(getResources().getQuantityString(
- R.plurals.number_of_items_selected, numCheckedItems, numCheckedItems));
- return true;
- }
+ /**
+ * Called when a wallpaper tile is clicked
+ */
+ @Override
+ public void onClick(View v) {
+ if (mActionMode != null) {
+ // When CAB is up, clicking toggles the item instead
+ if (v.isLongClickable()) {
+ onLongClick(v);
}
+ return;
+ }
+ setWallpaperButtonEnabled(true);
+ WallpaperTileInfo info = (WallpaperTileInfo) v.getTag();
+ if (info.isSelectable() && v.getVisibility() == View.VISIBLE) {
+ selectTile(v);
+ }
+ info.onClick(this);
+ }
- // Called when the user selects a contextual menu item
- @Override
- public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
- int itemId = item.getItemId();
- if (itemId == R.id.menu_delete) {
- int childCount = mWallpapersView.getChildCount();
- ArrayList<View> viewsToRemove = new ArrayList<View>();
- boolean selectedTileRemoved = false;
- for (int i = 0; i < childCount; i++) {
- CheckableFrameLayout c =
- (CheckableFrameLayout) mWallpapersView.getChildAt(i);
- if (c.isChecked()) {
- WallpaperTileInfo info = (WallpaperTileInfo) c.getTag();
- info.onDelete(WallpaperPickerActivity.this);
- viewsToRemove.add(c);
- if (i == mSelectedIndex) {
- selectedTileRemoved = true;
- }
- }
- }
- for (View v : viewsToRemove) {
- mWallpapersView.removeView(v);
- }
- if (selectedTileRemoved) {
- mSelectedIndex = -1;
- mSelectedTile = null;
- setSystemWallpaperVisiblity(true);
- }
- updateTileIndices();
- mode.finish(); // Action picked, so close the CAB
- return true;
- } else {
- return false;
- }
- }
+ /**
+ * Called when a view is long clicked
+ */
+ @Override
+ public boolean onLongClick(View v) {
+ CheckableFrameLayout c = (CheckableFrameLayout) v;
+ c.toggle();
- // Called when the user exits the action mode
- @Override
- public void onDestroyActionMode(ActionMode mode) {
- int childCount = mWallpapersView.getChildCount();
- for (int i = 0; i < childCount; i++) {
- CheckableFrameLayout c = (CheckableFrameLayout) mWallpapersView.getChildAt(i);
- c.setChecked(false);
- }
- if (mSelectedTile != null) {
- mSelectedTile.setSelected(true);
- }
- mActionMode = null;
+ if (mActionMode != null) {
+ mActionMode.invalidate();
+ } else {
+ // Start the CAB using the ActionMode.Callback defined below
+ mActionMode = startActionMode(this);
+ int childCount = mWallpapersView.getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ mWallpapersView.getChildAt(i).setSelected(false);
}
- };
+ }
+ return true;
}
public void setWallpaperButtonEnabled(boolean enabled) {
@@ -676,7 +279,7 @@ public class WallpaperPickerActivity extends WallpaperCropActivity {
return mWallpaperParallaxOffset;
}
- @Thunk void selectTile(View v) {
+ public void selectTile(View v) {
if (mSelectedTile != null) {
mSelectedTile.setSelected(false);
mSelectedTile = null;
@@ -704,35 +307,6 @@ public class WallpaperPickerActivity extends WallpaperCropActivity {
}
}
- protected Bitmap getThumbnailOfLastPhoto() {
- boolean canReadExternalStorage = getActivity().checkPermission(
- Manifest.permission.READ_EXTERNAL_STORAGE, Process.myPid(), Process.myUid()) ==
- PackageManager.PERMISSION_GRANTED;
-
- if (!canReadExternalStorage) {
- // MediaStore.Images.Media.EXTERNAL_CONTENT_URI requires
- // the READ_EXTERNAL_STORAGE permission
- return null;
- }
-
- Cursor cursor = MediaStore.Images.Media.query(getContext().getContentResolver(),
- MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
- new String[] { MediaStore.Images.ImageColumns._ID,
- MediaStore.Images.ImageColumns.DATE_TAKEN},
- null, null, MediaStore.Images.ImageColumns.DATE_TAKEN + " DESC LIMIT 1");
-
- Bitmap thumb = null;
- if (cursor != null) {
- if (cursor.moveToNext()) {
- int id = cursor.getInt(0);
- thumb = MediaStore.Images.Thumbnails.getThumbnail(getContext().getContentResolver(),
- id, MediaStore.Images.Thumbnails.MINI_KIND, null);
- }
- cursor.close();
- }
- return thumb;
- }
-
public void onStop() {
super.onStop();
mWallpaperStrip = findViewById(R.id.wallpaper_strip);
@@ -755,21 +329,6 @@ public class WallpaperPickerActivity extends WallpaperCropActivity {
mSelectedIndex = savedInstanceState.getInt(SELECTED_INDEX, -1);
}
- @Thunk void populateWallpapersFromAdapter(ViewGroup parent, BaseAdapter adapter,
- boolean addLongPressHandler) {
- for (int i = 0; i < adapter.getCount(); i++) {
- FrameLayout thumbnail = (FrameLayout) adapter.getView(i, null, parent);
- parent.addView(thumbnail, i);
- WallpaperTileInfo info = (WallpaperTileInfo) adapter.getItem(i);
- thumbnail.setTag(info);
- info.setView(thumbnail);
- if (addLongPressHandler) {
- addLongPressHandler(thumbnail);
- }
- thumbnail.setOnClickListener(mThumbnailOnClickListener);
- }
- }
-
@Thunk void updateTileIndices() {
LinearLayout masterWallpaperList = (LinearLayout) findViewById(R.id.master_wallpaper_list);
final int childCount = masterWallpaperList.getChildCount();
@@ -811,126 +370,68 @@ public class WallpaperPickerActivity extends WallpaperCropActivity {
}
}
- @Thunk static Point getDefaultThumbnailSize(Resources res) {
- return new Point(res.getDimensionPixelSize(R.dimen.wallpaperThumbnailWidth),
- res.getDimensionPixelSize(R.dimen.wallpaperThumbnailHeight));
-
- }
-
- @Thunk static Bitmap createThumbnail(Point size, Context context, Uri uri, byte[] imageBytes,
- Resources res, int resId, int rotation, boolean leftAligned) {
- int width = size.x;
- int height = size.y;
-
- BitmapCropTask cropTask;
- if (uri != null) {
- cropTask = new BitmapCropTask(
- context, uri, null, rotation, width, height, false, true, null);
- } else if (imageBytes != null) {
- cropTask = new BitmapCropTask(
- imageBytes, null, rotation, width, height, false, true, null);
- } else {
- cropTask = new BitmapCropTask(
- context, res, resId, null, rotation, width, height, false, true, null);
- }
- Point bounds = cropTask.getImageBounds();
- if (bounds == null || bounds.x == 0 || bounds.y == 0) {
- return null;
- }
-
- Matrix rotateMatrix = new Matrix();
- rotateMatrix.setRotate(rotation);
- float[] rotatedBounds = new float[] { bounds.x, bounds.y };
- rotateMatrix.mapPoints(rotatedBounds);
- rotatedBounds[0] = Math.abs(rotatedBounds[0]);
- rotatedBounds[1] = Math.abs(rotatedBounds[1]);
-
- RectF cropRect = Utils.getMaxCropRect(
- (int) rotatedBounds[0], (int) rotatedBounds[1], width, height, leftAligned);
- cropTask.setCropBounds(cropRect);
-
- if (cropTask.cropBitmap()) {
- return cropTask.getCroppedBitmap();
- } else {
- return null;
- }
- }
-
private void addTemporaryWallpaperTile(final Uri uri, boolean fromRestore) {
+
// Add a tile for the image picked from Gallery, reusing the existing tile if there is one.
- FrameLayout existingImageThumbnail = null;
+ View imageTile = null;
int indexOfExistingTile = 0;
for (; indexOfExistingTile < mWallpapersView.getChildCount(); indexOfExistingTile++) {
- FrameLayout thumbnail = (FrameLayout) mWallpapersView.getChildAt(indexOfExistingTile);
+ View thumbnail = mWallpapersView.getChildAt(indexOfExistingTile);
Object tag = thumbnail.getTag();
if (tag instanceof UriWallpaperInfo && ((UriWallpaperInfo) tag).mUri.equals(uri)) {
- existingImageThumbnail = thumbnail;
+ imageTile = thumbnail;
break;
}
}
- final FrameLayout pickedImageThumbnail;
- if (existingImageThumbnail != null) {
- pickedImageThumbnail = existingImageThumbnail;
+ final UriWallpaperInfo info;
+ if (imageTile != null) {
// Always move the existing wallpaper to the front so user can see it without scrolling.
mWallpapersView.removeViewAt(indexOfExistingTile);
- mWallpapersView.addView(existingImageThumbnail, 0);
+ info = (UriWallpaperInfo) imageTile.getTag();
} else {
// This is the first time this temporary wallpaper has been added
- pickedImageThumbnail = (FrameLayout) getLayoutInflater()
- .inflate(R.layout.wallpaper_picker_item, mWallpapersView, false);
- pickedImageThumbnail.setVisibility(View.GONE);
- mWallpapersView.addView(pickedImageThumbnail, 0);
+ info = new UriWallpaperInfo(uri);
+ imageTile = createTileView(mWallpapersView, info, true);
mTempWallpaperTiles.add(uri);
}
+ mWallpapersView.addView(imageTile, 0);
+ info.loadThumbnaleAsync(this);
- // Load the thumbnail
- final ImageView image = (ImageView) pickedImageThumbnail.findViewById(R.id.wallpaper_image);
- final Point defaultSize = getDefaultThumbnailSize(this.getResources());
- final Context context = getContext();
- new AsyncTask<Void, Bitmap, Bitmap>() {
- protected Bitmap doInBackground(Void...args) {
- try {
- int rotation = BitmapUtils.getRotationFromExif(context, uri);
- return createThumbnail(defaultSize, context, uri, null, null, 0, rotation,
- false);
- } catch (SecurityException securityException) {
- if (isActivityDestroyed()) {
- // Temporarily granted permissions are revoked when the activity
- // finishes, potentially resulting in a SecurityException here.
- // Even though {@link #isDestroyed} might also return true in different
- // situations where the configuration changes, we are fine with
- // catching these cases here as well.
- cancel(false);
- } else {
- // otherwise it had a different cause and we throw it further
- throw securityException;
- }
- return null;
- }
- }
- protected void onPostExecute(Bitmap thumb) {
- if (!isCancelled() && thumb != null) {
- image.setImageBitmap(thumb);
- Drawable thumbDrawable = image.getDrawable();
- thumbDrawable.setDither(true);
- pickedImageThumbnail.setVisibility(View.VISIBLE);
- } else {
- Log.e(TAG, "Error loading thumbnail for uri=" + uri);
- }
- }
- }.execute();
-
- UriWallpaperInfo info = new UriWallpaperInfo(uri);
- pickedImageThumbnail.setTag(info);
- info.setView(pickedImageThumbnail);
- addLongPressHandler(pickedImageThumbnail);
updateTileIndices();
- pickedImageThumbnail.setOnClickListener(mThumbnailOnClickListener);
if (!fromRestore) {
- mThumbnailOnClickListener.onClick(pickedImageThumbnail);
+ onClick(imageTile);
}
}
+ @Thunk void populateWallpapers(ViewGroup parent, List<? extends WallpaperTileInfo> wallpapers,
+ boolean addLongPressHandler) {
+ for (WallpaperTileInfo info : wallpapers) {
+ parent.addView(createTileView(parent, info, addLongPressHandler));
+ }
+ }
+
+ private View createTileView(ViewGroup parent, WallpaperTileInfo info, boolean addLongPress) {
+ View view = info.createView(this, getLayoutInflater(), parent);
+ view.setTag(info);
+
+ if (addLongPress) {
+ view.setOnLongClickListener(this);
+
+ // Enable stylus button to also trigger long click.
+ final StylusEventHelper stylusEventHelper =
+ new StylusEventHelper(new SimpleOnStylusPressListener(view), view);
+ view.setOnTouchListener(new View.OnTouchListener() {
+ @SuppressLint("ClickableViewAccessibility")
+ @Override
+ public boolean onTouch(View view, MotionEvent event) {
+ return stylusEventHelper.onMotionEvent(event);
+ }
+ });
+ }
+ view.setOnClickListener(this);
+ return view;
+ }
+
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == IMAGE_PICK && resultCode == Activity.RESULT_OK) {
if (data != null && data.getData() != null) {
@@ -945,19 +446,6 @@ public class WallpaperPickerActivity extends WallpaperCropActivity {
}
}
- private void addLongPressHandler(View v) {
- v.setOnLongClickListener(mLongClickListener);
-
- // Enable stylus button to also trigger long click.
- final StylusEventHelper stylusEventHelper = new StylusEventHelper(v);
- v.setOnTouchListener(new View.OnTouchListener() {
- @Override
- public boolean onTouch(View view, MotionEvent event) {
- return stylusEventHelper.checkAndPerformStylusEvent(event);
- }
- });
- }
-
private ArrayList<WallpaperTileInfo> findBundledWallpapers() {
final PackageManager pm = getContext().getPackageManager();
final ArrayList<WallpaperTileInfo> bundled = new ArrayList<WallpaperTileInfo>(24);
@@ -994,7 +482,8 @@ public class WallpaperPickerActivity extends WallpaperCropActivity {
File thumbnail = new File(systemDir, name + "_small" + extension);
Bitmap thumb = BitmapFactory.decodeFile(thumbnail.getAbsolutePath());
if (thumb != null) {
- bundled.add(new FileWallpaperInfo(file, new BitmapDrawable(thumb)));
+ bundled.add(new FileWallpaperInfo(
+ file, new BitmapDrawable(getResources(), thumb)));
}
}
}
@@ -1012,8 +501,7 @@ public class WallpaperPickerActivity extends WallpaperCropActivity {
if (partner == null || !partner.hideDefaultWallpaper()) {
// Add an entry for the default wallpaper (stored in system resources)
- WallpaperTileInfo defaultWallpaperInfo = Utilities.ATLEAST_KITKAT
- ? getDefaultWallpaper() : getPreKKDefaultWallpaperInfo();
+ WallpaperTileInfo defaultWallpaperInfo = DefaultWallpaperInfo.get(this);
if (defaultWallpaperInfo != null) {
bundled.add(0, defaultWallpaperInfo);
}
@@ -1021,95 +509,6 @@ public class WallpaperPickerActivity extends WallpaperCropActivity {
return bundled;
}
- private boolean writeImageToFileAsJpeg(File f, Bitmap b) {
- try {
- f.createNewFile();
- FileOutputStream thumbFileStream =
- getContext().openFileOutput(f.getName(), Context.MODE_PRIVATE);
- b.compress(Bitmap.CompressFormat.JPEG, 95, thumbFileStream);
- thumbFileStream.close();
- return true;
- } catch (IOException e) {
- Log.e(TAG, "Error while writing bitmap to file " + e);
- f.delete();
- }
- return false;
- }
-
- private File getDefaultThumbFile() {
- return new File(getContext().getFilesDir(), Build.VERSION.SDK_INT
- + "_" + LauncherFiles.DEFAULT_WALLPAPER_THUMBNAIL);
- }
-
- private boolean saveDefaultWallpaperThumb(Bitmap b) {
- // Delete old thumbnails.
- new File(getContext().getFilesDir(), LauncherFiles.DEFAULT_WALLPAPER_THUMBNAIL_OLD).delete();
- new File(getContext().getFilesDir(), LauncherFiles.DEFAULT_WALLPAPER_THUMBNAIL).delete();
-
- for (int i = Build.VERSION_CODES.JELLY_BEAN; i < Build.VERSION.SDK_INT; i++) {
- new File(getContext().getFilesDir(), i + "_"
- + LauncherFiles.DEFAULT_WALLPAPER_THUMBNAIL).delete();
- }
- return writeImageToFileAsJpeg(getDefaultThumbFile(), b);
- }
-
- private ResourceWallpaperInfo getPreKKDefaultWallpaperInfo() {
- Resources sysRes = Resources.getSystem();
- int resId = sysRes.getIdentifier("default_wallpaper", "drawable", "android");
-
- File defaultThumbFile = getDefaultThumbFile();
- Bitmap thumb = null;
- boolean defaultWallpaperExists = false;
- if (defaultThumbFile.exists()) {
- thumb = BitmapFactory.decodeFile(defaultThumbFile.getAbsolutePath());
- defaultWallpaperExists = true;
- } else {
- Resources res = getResources();
- Point defaultThumbSize = getDefaultThumbnailSize(res);
- int rotation = BitmapUtils.getRotationFromExif(res, resId);
- thumb = createThumbnail(
- defaultThumbSize, getContext(), null, null, sysRes, resId, rotation, false);
- if (thumb != null) {
- defaultWallpaperExists = saveDefaultWallpaperThumb(thumb);
- }
- }
- if (defaultWallpaperExists) {
- return new ResourceWallpaperInfo(sysRes, resId, new BitmapDrawable(thumb));
- }
- return null;
- }
-
- @TargetApi(Build.VERSION_CODES.KITKAT)
- private DefaultWallpaperInfo getDefaultWallpaper() {
- File defaultThumbFile = getDefaultThumbFile();
- Bitmap thumb = null;
- boolean defaultWallpaperExists = false;
- if (defaultThumbFile.exists()) {
- thumb = BitmapFactory.decodeFile(defaultThumbFile.getAbsolutePath());
- defaultWallpaperExists = true;
- } else {
- Resources res = getResources();
- Point defaultThumbSize = getDefaultThumbnailSize(res);
- Drawable wallpaperDrawable = WallpaperManager.getInstance(getContext()).getBuiltInDrawable(
- defaultThumbSize.x, defaultThumbSize.y, true, 0.5f, 0.5f);
- if (wallpaperDrawable != null) {
- thumb = Bitmap.createBitmap(
- defaultThumbSize.x, defaultThumbSize.y, Bitmap.Config.ARGB_8888);
- Canvas c = new Canvas(thumb);
- wallpaperDrawable.setBounds(0, 0, defaultThumbSize.x, defaultThumbSize.y);
- wallpaperDrawable.draw(c);
- c.setBitmap(null);
- }
- if (thumb != null) {
- defaultWallpaperExists = saveDefaultWallpaperThumb(thumb);
- }
- }
- if (defaultWallpaperExists) {
- return new DefaultWallpaperInfo(new BitmapDrawable(thumb));
- }
- return null;
- }
-
public Pair<ApplicationInfo, Integer> getWallpaperArrayResourceId() {
// Context.getPackageName() may return the "original" package name,
// com.android.launcher3; Resources needs the real package name,
@@ -1144,62 +543,111 @@ public class WallpaperPickerActivity extends WallpaperCropActivity {
}
}
- public CropView getCropView() {
- return mCropView;
- }
-
public SavedWallpaperImages getSavedImages() {
return mSavedImages;
}
- private static class SimpleWallpapersAdapter extends ArrayAdapter<WallpaperTileInfo> {
- private final LayoutInflater mLayoutInflater;
-
- SimpleWallpapersAdapter(Context context, ArrayList<WallpaperTileInfo> wallpapers) {
- super(context, R.layout.wallpaper_picker_item, wallpapers);
- mLayoutInflater = LayoutInflater.from(context);
- }
+ public void startActivityForResultSafely(Intent intent, int requestCode) {
+ Utilities.startActivityForResultSafely(getActivity(), intent, requestCode);
+ }
- public View getView(int position, View convertView, ViewGroup parent) {
- Drawable thumb = getItem(position).mThumb;
- if (thumb == null) {
- Log.e(TAG, "Error decoding thumbnail for wallpaper #" + position);
- }
- return createImageTileView(mLayoutInflater, convertView, parent, thumb);
- }
+ @Override
+ public boolean enableRotation() {
+ return super.enableRotation() ||
+ getContentResolver().call(LauncherSettings.Settings.CONTENT_URI,
+ LauncherSettings.Settings.METHOD_GET_BOOLEAN,
+ Utilities.ALLOW_ROTATION_PREFERENCE_KEY, new Bundle())
+ .getBoolean(LauncherSettings.Settings.EXTRA_VALUE);
}
- public static View createImageTileView(LayoutInflater layoutInflater,
- View convertView, ViewGroup parent, Drawable thumb) {
- View view;
+ // CAB for deleting items
+ /**
+ * Called when the action mode is created; startActionMode() was called
+ */
+ @Override
+ public boolean onCreateActionMode(ActionMode mode, Menu menu) {
+ // Inflate a menu resource providing context menu items
+ MenuInflater inflater = mode.getMenuInflater();
+ inflater.inflate(R.menu.cab_delete_wallpapers, menu);
+ return true;
+ }
- if (convertView == null) {
- view = layoutInflater.inflate(R.layout.wallpaper_picker_item, parent, false);
- } else {
- view = convertView;
+ /**
+ * Called each time the action mode is shown. Always called after onCreateActionMode,
+ * but may be called multiple times if the mode is invalidated.
+ */
+ @Override
+ public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
+ int childCount = mWallpapersView.getChildCount();
+ int numCheckedItems = 0;
+ for (int i = 0; i < childCount; i++) {
+ CheckableFrameLayout c = (CheckableFrameLayout) mWallpapersView.getChildAt(i);
+ if (c.isChecked()) {
+ numCheckedItems++;
+ }
}
- ImageView image = (ImageView) view.findViewById(R.id.wallpaper_image);
-
- if (thumb != null) {
- image.setImageDrawable(thumb);
- thumb.setDither(true);
+ if (numCheckedItems == 0) {
+ mode.finish();
+ return true;
+ } else {
+ mode.setTitle(getResources().getQuantityString(
+ R.plurals.number_of_items_selected, numCheckedItems, numCheckedItems));
+ return true;
}
-
- return view;
- }
-
- public void startActivityForResultSafely(Intent intent, int requestCode) {
- Utilities.startActivityForResultSafely(getActivity(), intent, requestCode);
}
+ /**
+ * Called when the user selects a contextual menu item
+ */
@Override
- public boolean enableRotation() {
- // Check if rotation is enabled for this device.
- if (Utilities.isRotationAllowedForDevice(getContext()))
+ public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
+ int itemId = item.getItemId();
+ if (itemId == R.id.menu_delete) {
+ int childCount = mWallpapersView.getChildCount();
+ ArrayList<View> viewsToRemove = new ArrayList<View>();
+ boolean selectedTileRemoved = false;
+ for (int i = 0; i < childCount; i++) {
+ CheckableFrameLayout c =
+ (CheckableFrameLayout) mWallpapersView.getChildAt(i);
+ if (c.isChecked()) {
+ WallpaperTileInfo info = (WallpaperTileInfo) c.getTag();
+ info.onDelete(WallpaperPickerActivity.this);
+ viewsToRemove.add(c);
+ if (i == mSelectedIndex) {
+ selectedTileRemoved = true;
+ }
+ }
+ }
+ for (View v : viewsToRemove) {
+ mWallpapersView.removeView(v);
+ }
+ if (selectedTileRemoved) {
+ mSelectedIndex = -1;
+ mSelectedTile = null;
+ setSystemWallpaperVisiblity(true);
+ }
+ updateTileIndices();
+ mode.finish(); // Action picked, so close the CAB
return true;
+ } else {
+ return false;
+ }
+ }
- // Check if the user has specifically enabled rotation via preferences.
- return Utilities.isAllowRotationPrefEnabled(getApplicationContext(), true);
+ /**
+ * Called when the user exits the action mode
+ */
+ @Override
+ public void onDestroyActionMode(ActionMode mode) {
+ int childCount = mWallpapersView.getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ CheckableFrameLayout c = (CheckableFrameLayout) mWallpapersView.getChildAt(i);
+ c.setChecked(false);
+ }
+ if (mSelectedTile != null) {
+ mSelectedTile.setSelected(true);
+ }
+ mActionMode = null;
}
}
diff --git a/WallpaperPicker/src/com/android/launcher3/wallpapertileinfo/DefaultWallpaperInfo.java b/WallpaperPicker/src/com/android/launcher3/wallpapertileinfo/DefaultWallpaperInfo.java
new file mode 100644
index 000000000..7ede26096
--- /dev/null
+++ b/WallpaperPicker/src/com/android/launcher3/wallpapertileinfo/DefaultWallpaperInfo.java
@@ -0,0 +1,164 @@
+package com.android.launcher3.wallpapertileinfo;
+
+import android.annotation.TargetApi;
+import android.app.Activity;
+import android.app.WallpaperManager;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Point;
+import android.graphics.RectF;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.util.Log;
+
+import com.android.gallery3d.common.BitmapUtils;
+import com.android.launcher3.LauncherFiles;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.WallpaperCropActivity.CropViewScaleAndOffsetProvider;
+import com.android.launcher3.WallpaperPickerActivity;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+public class DefaultWallpaperInfo extends DrawableThumbWallpaperInfo {
+
+ private static final String TAG = "DefaultWallpaperInfo";
+
+ public DefaultWallpaperInfo(Drawable thumb) {
+ super(thumb);
+ }
+
+ @Override
+ public void onClick(WallpaperPickerActivity a) {
+ a.setCropViewTileSource(null, false, false, new CropViewScaleAndOffsetProvider() {
+
+ @Override
+ public float getScale(Point wallpaperSize, RectF crop) {
+ return 1f;
+ }
+
+ @Override
+ public float getParallaxOffset() {
+ return 0;
+ }
+ }, null);
+ }
+
+ @Override
+ public void onSave(WallpaperPickerActivity a) {
+ try {
+ WallpaperManager.getInstance(a.getContext()).clear();
+ a.setResult(Activity.RESULT_OK);
+ } catch (IOException e) {
+ Log.w(TAG, "Setting wallpaper to default threw exception", e);
+ }
+ a.finish();
+ }
+
+ @Override
+ public boolean isSelectable() {
+ return true;
+ }
+
+ @Override
+ public boolean isNamelessWallpaper() {
+ return true;
+ }
+
+ /**
+ * @return the system default wallpaper tile or null
+ */
+ public static WallpaperTileInfo get(Context context) {
+ return Utilities.ATLEAST_KITKAT
+ ? getDefaultWallpaper(context) : getPreKKDefaultWallpaperInfo(context);
+ }
+
+ @TargetApi(Build.VERSION_CODES.KITKAT)
+ private static DefaultWallpaperInfo getDefaultWallpaper(Context context) {
+ File defaultThumbFile = getDefaultThumbFile(context);
+ Bitmap thumb = null;
+ boolean defaultWallpaperExists = false;
+ Resources res = context.getResources();
+
+ if (defaultThumbFile.exists()) {
+ thumb = BitmapFactory.decodeFile(defaultThumbFile.getAbsolutePath());
+ defaultWallpaperExists = true;
+ } else {
+ Point defaultThumbSize = getDefaultThumbSize(res);
+ Drawable wallpaperDrawable = WallpaperManager.getInstance(context).getBuiltInDrawable(
+ defaultThumbSize.x, defaultThumbSize.y, true, 0.5f, 0.5f);
+ if (wallpaperDrawable != null) {
+ thumb = Bitmap.createBitmap(
+ defaultThumbSize.x, defaultThumbSize.y, Bitmap.Config.ARGB_8888);
+ Canvas c = new Canvas(thumb);
+ wallpaperDrawable.setBounds(0, 0, defaultThumbSize.x, defaultThumbSize.y);
+ wallpaperDrawable.draw(c);
+ c.setBitmap(null);
+ }
+ if (thumb != null) {
+ defaultWallpaperExists = saveDefaultWallpaperThumb(context, thumb);
+ }
+ }
+ if (defaultWallpaperExists) {
+ return new DefaultWallpaperInfo(new BitmapDrawable(res, thumb));
+ }
+ return null;
+ }
+
+ private static ResourceWallpaperInfo getPreKKDefaultWallpaperInfo(Context context) {
+ Resources sysRes = Resources.getSystem();
+ Resources res = context.getResources();
+
+ int resId = sysRes.getIdentifier("default_wallpaper", "drawable", "android");
+
+ File defaultThumbFile = getDefaultThumbFile(context);
+ Bitmap thumb = null;
+ boolean defaultWallpaperExists = false;
+ if (defaultThumbFile.exists()) {
+ thumb = BitmapFactory.decodeFile(defaultThumbFile.getAbsolutePath());
+ defaultWallpaperExists = true;
+ } else {
+ int rotation = BitmapUtils.getRotationFromExif(res, resId, context);
+ thumb = createThumbnail(context, null, null, sysRes, resId, rotation, false);
+ if (thumb != null) {
+ defaultWallpaperExists = saveDefaultWallpaperThumb(context, thumb);
+ }
+ }
+ if (defaultWallpaperExists) {
+ return new ResourceWallpaperInfo(sysRes, resId, new BitmapDrawable(res, thumb));
+ }
+ return null;
+ }
+
+ private static File getDefaultThumbFile(Context context) {
+ return new File(context.getFilesDir(), Build.VERSION.SDK_INT
+ + "_" + LauncherFiles.DEFAULT_WALLPAPER_THUMBNAIL);
+ }
+
+ private static boolean saveDefaultWallpaperThumb(Context c, Bitmap b) {
+ // Delete old thumbnails.
+ new File(c.getFilesDir(), LauncherFiles.DEFAULT_WALLPAPER_THUMBNAIL_OLD).delete();
+ new File(c.getFilesDir(), LauncherFiles.DEFAULT_WALLPAPER_THUMBNAIL).delete();
+
+ for (int i = Build.VERSION_CODES.JELLY_BEAN; i < Build.VERSION.SDK_INT; i++) {
+ new File(c.getFilesDir(), i + "_" + LauncherFiles.DEFAULT_WALLPAPER_THUMBNAIL).delete();
+ }
+ File f = getDefaultThumbFile(c);
+ try {
+ f.createNewFile();
+ FileOutputStream thumbFileStream = c.openFileOutput(f.getName(), Context.MODE_PRIVATE);
+ b.compress(Bitmap.CompressFormat.JPEG, 95, thumbFileStream);
+ thumbFileStream.close();
+ return true;
+ } catch (IOException e) {
+ Log.e(TAG, "Error while writing bitmap to file " + e);
+ f.delete();
+ return false;
+ }
+ }
+} \ No newline at end of file
diff --git a/WallpaperPicker/src/com/android/launcher3/wallpapertileinfo/DrawableThumbWallpaperInfo.java b/WallpaperPicker/src/com/android/launcher3/wallpapertileinfo/DrawableThumbWallpaperInfo.java
new file mode 100644
index 000000000..a55375ddf
--- /dev/null
+++ b/WallpaperPicker/src/com/android/launcher3/wallpapertileinfo/DrawableThumbWallpaperInfo.java
@@ -0,0 +1,37 @@
+package com.android.launcher3.wallpapertileinfo;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+
+import com.android.launcher3.R;
+
+/**
+ * WallpaperTileInfo which uses drawable as the thumbnail.
+ */
+public abstract class DrawableThumbWallpaperInfo extends WallpaperTileInfo {
+
+ private final Drawable mThumb;
+
+ DrawableThumbWallpaperInfo(Drawable thumb) {
+ mThumb = thumb;
+ }
+
+ @Override
+ public View createView(Context context, LayoutInflater inflator, ViewGroup parent) {
+ mView = inflator.inflate(R.layout.wallpaper_picker_item, parent, false);
+ setThumb(mThumb);
+ return mView;
+ }
+
+ public void setThumb(Drawable thumb) {
+ if (mView != null && thumb != null) {
+ thumb.setDither(true);
+ ImageView image = (ImageView) mView.findViewById(R.id.wallpaper_image);
+ image.setImageDrawable(thumb);
+ }
+ }
+}
diff --git a/WallpaperPicker/src/com/android/launcher3/wallpapertileinfo/FileWallpaperInfo.java b/WallpaperPicker/src/com/android/launcher3/wallpapertileinfo/FileWallpaperInfo.java
new file mode 100644
index 000000000..f6a46fc48
--- /dev/null
+++ b/WallpaperPicker/src/com/android/launcher3/wallpapertileinfo/FileWallpaperInfo.java
@@ -0,0 +1,52 @@
+package com.android.launcher3.wallpapertileinfo;
+
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+
+import com.android.launcher3.WallpaperPickerActivity;
+import com.android.photos.BitmapRegionTileSource;
+import com.android.photos.BitmapRegionTileSource.BitmapSource;
+
+import java.io.File;
+
+public class FileWallpaperInfo extends DrawableThumbWallpaperInfo {
+
+ private final File mFile;
+
+ public FileWallpaperInfo(File target, Drawable thumb) {
+ super(thumb);
+ mFile = target;
+ }
+
+ @Override
+ public void onClick(final WallpaperPickerActivity a) {
+ a.setWallpaperButtonEnabled(false);
+ final BitmapRegionTileSource.FilePathBitmapSource bitmapSource =
+ new BitmapRegionTileSource.FilePathBitmapSource(mFile.getAbsolutePath());
+ a.setCropViewTileSource(bitmapSource, false, true, null, new Runnable() {
+
+ @Override
+ public void run() {
+ if (bitmapSource.getLoadingState() == BitmapSource.State.LOADED) {
+ a.setWallpaperButtonEnabled(true);
+ }
+ }
+ });
+ }
+
+ @Override
+ public void onSave(WallpaperPickerActivity a) {
+ boolean shouldFadeOutOnFinish = a.getWallpaperParallaxOffset() == 0f;
+ a.setWallpaper(Uri.fromFile(mFile), shouldFadeOutOnFinish);
+ }
+
+ @Override
+ public boolean isSelectable() {
+ return true;
+ }
+
+ @Override
+ public boolean isNamelessWallpaper() {
+ return true;
+ }
+} \ No newline at end of file
diff --git a/WallpaperPicker/src/com/android/launcher3/wallpapertileinfo/LiveWallpaperInfo.java b/WallpaperPicker/src/com/android/launcher3/wallpapertileinfo/LiveWallpaperInfo.java
new file mode 100644
index 000000000..d800ba6e1
--- /dev/null
+++ b/WallpaperPicker/src/com/android/launcher3/wallpapertileinfo/LiveWallpaperInfo.java
@@ -0,0 +1,118 @@
+package com.android.launcher3.wallpapertileinfo;
+
+import android.app.WallpaperInfo;
+import android.app.WallpaperManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.graphics.drawable.Drawable;
+import android.os.AsyncTask;
+import android.service.wallpaper.WallpaperService;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.launcher3.R;
+import com.android.launcher3.WallpaperPickerActivity;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.text.Collator;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+public class LiveWallpaperInfo extends WallpaperTileInfo {
+
+ private static final String TAG = "LiveWallpaperTile";
+
+ private Drawable mThumbnail;
+ private WallpaperInfo mInfo;
+
+ public LiveWallpaperInfo(Drawable thumbnail, WallpaperInfo info, Intent intent) {
+ mThumbnail = thumbnail;
+ mInfo = info;
+ }
+
+ @Override
+ public void onClick(WallpaperPickerActivity a) {
+ Intent preview = new Intent(WallpaperManager.ACTION_CHANGE_LIVE_WALLPAPER);
+ preview.putExtra(WallpaperManager.EXTRA_LIVE_WALLPAPER_COMPONENT,
+ mInfo.getComponent());
+ a.startActivityForResultSafely(preview,
+ WallpaperPickerActivity.PICK_WALLPAPER_THIRD_PARTY_ACTIVITY);
+ }
+
+ @Override
+ public View createView(Context context, LayoutInflater inflator, ViewGroup parent) {
+ mView = inflator.inflate(R.layout.wallpaper_picker_live_wallpaper_item, parent, false);
+
+ ImageView image = (ImageView) mView.findViewById(R.id.wallpaper_image);
+ ImageView icon = (ImageView) mView.findViewById(R.id.wallpaper_icon);
+ if (mThumbnail != null) {
+ image.setImageDrawable(mThumbnail);
+ icon.setVisibility(View.GONE);
+ } else {
+ icon.setImageDrawable(mInfo.loadIcon(context.getPackageManager()));
+ icon.setVisibility(View.VISIBLE);
+ }
+
+ TextView label = (TextView) mView.findViewById(R.id.wallpaper_item_label);
+ label.setText(mInfo.loadLabel(context.getPackageManager()));
+ return mView;
+ }
+
+ /**
+ * An async task to load various live wallpaper tiles.
+ */
+ public static class LoaderTask extends AsyncTask<Void, Void, List<LiveWallpaperInfo>> {
+ private final Context mContext;
+
+ public LoaderTask(Context context) {
+ mContext = context;
+ }
+
+ @Override
+ protected List<LiveWallpaperInfo> doInBackground(Void... params) {
+ final PackageManager pm = mContext.getPackageManager();
+
+ List<ResolveInfo> list = pm.queryIntentServices(
+ new Intent(WallpaperService.SERVICE_INTERFACE),
+ PackageManager.GET_META_DATA);
+
+ Collections.sort(list, new Comparator<ResolveInfo>() {
+ final Collator mCollator = Collator.getInstance();
+
+ public int compare(ResolveInfo info1, ResolveInfo info2) {
+ return mCollator.compare(info1.loadLabel(pm), info2.loadLabel(pm));
+ }
+ });
+
+ List<LiveWallpaperInfo> result = new ArrayList<>();
+
+ for (ResolveInfo resolveInfo : list) {
+ WallpaperInfo info = null;
+ try {
+ info = new WallpaperInfo(mContext, resolveInfo);
+ } catch (XmlPullParserException | IOException e) {
+ Log.w(TAG, "Skipping wallpaper " + resolveInfo.serviceInfo, e);
+ continue;
+ }
+
+
+ Drawable thumb = info.loadThumbnail(pm);
+ Intent launchIntent = new Intent(WallpaperService.SERVICE_INTERFACE);
+ launchIntent.setClassName(info.getPackageName(), info.getServiceName());
+ result.add(new LiveWallpaperInfo(thumb, info, launchIntent));
+ }
+
+ return result;
+ }
+ }
+} \ No newline at end of file
diff --git a/WallpaperPicker/src/com/android/launcher3/wallpapertileinfo/PickImageInfo.java b/WallpaperPicker/src/com/android/launcher3/wallpapertileinfo/PickImageInfo.java
new file mode 100644
index 000000000..9d8cc1cd7
--- /dev/null
+++ b/WallpaperPicker/src/com/android/launcher3/wallpapertileinfo/PickImageInfo.java
@@ -0,0 +1,74 @@
+package com.android.launcher3.wallpapertileinfo;
+
+import android.Manifest;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.PorterDuff;
+import android.os.Process;
+import android.provider.MediaStore;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+
+import com.android.launcher3.R;
+import com.android.launcher3.WallpaperPickerActivity;
+
+public class PickImageInfo extends WallpaperTileInfo {
+
+ @Override
+ public void onClick(WallpaperPickerActivity a) {
+ Intent intent = new Intent(Intent.ACTION_GET_CONTENT).setType("image/*");
+ a.startActivityForResultSafely(intent, WallpaperPickerActivity.IMAGE_PICK);
+ }
+
+ @Override
+ public View createView(Context context, LayoutInflater inflator, ViewGroup parent) {
+ mView = inflator.inflate(R.layout.wallpaper_picker_image_picker_item, parent, false);
+
+ // Make its background the last photo taken on external storage
+ Bitmap lastPhoto = getThumbnailOfLastPhoto(context);
+ if (lastPhoto != null) {
+ ImageView galleryThumbnailBg =
+ (ImageView) mView.findViewById(R.id.wallpaper_image);
+ galleryThumbnailBg.setImageBitmap(lastPhoto);
+ int colorOverlay = context.getResources().getColor(R.color.wallpaper_picker_translucent_gray);
+ galleryThumbnailBg.setColorFilter(colorOverlay, PorterDuff.Mode.SRC_ATOP);
+ }
+
+ mView.setTag(this);
+ return mView;
+ }
+
+ private Bitmap getThumbnailOfLastPhoto(Context context) {
+ boolean canReadExternalStorage = context.checkPermission(
+ Manifest.permission.READ_EXTERNAL_STORAGE, Process.myPid(), Process.myUid()) ==
+ PackageManager.PERMISSION_GRANTED;
+
+ if (!canReadExternalStorage) {
+ // MediaStore.Images.Media.EXTERNAL_CONTENT_URI requires
+ // the READ_EXTERNAL_STORAGE permission
+ return null;
+ }
+
+ Cursor cursor = MediaStore.Images.Media.query(context.getContentResolver(),
+ MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
+ new String[] { MediaStore.Images.ImageColumns._ID,
+ MediaStore.Images.ImageColumns.DATE_TAKEN},
+ null, null, MediaStore.Images.ImageColumns.DATE_TAKEN + " DESC LIMIT 1");
+
+ Bitmap thumb = null;
+ if (cursor != null) {
+ if (cursor.moveToNext()) {
+ int id = cursor.getInt(0);
+ thumb = MediaStore.Images.Thumbnails.getThumbnail(context.getContentResolver(),
+ id, MediaStore.Images.Thumbnails.MINI_KIND, null);
+ }
+ cursor.close();
+ }
+ return thumb;
+ }
+} \ No newline at end of file
diff --git a/WallpaperPicker/src/com/android/launcher3/wallpapertileinfo/ResourceWallpaperInfo.java b/WallpaperPicker/src/com/android/launcher3/wallpapertileinfo/ResourceWallpaperInfo.java
new file mode 100644
index 000000000..d63714c22
--- /dev/null
+++ b/WallpaperPicker/src/com/android/launcher3/wallpapertileinfo/ResourceWallpaperInfo.java
@@ -0,0 +1,65 @@
+package com.android.launcher3.wallpapertileinfo;
+
+import android.content.res.Resources;
+import android.graphics.Point;
+import android.graphics.RectF;
+import android.graphics.drawable.Drawable;
+
+import com.android.launcher3.WallpaperCropActivity.CropViewScaleAndOffsetProvider;
+import com.android.launcher3.WallpaperPickerActivity;
+import com.android.photos.BitmapRegionTileSource;
+import com.android.photos.BitmapRegionTileSource.BitmapSource;
+
+public class ResourceWallpaperInfo extends DrawableThumbWallpaperInfo {
+
+ private final Resources mResources;
+ private final int mResId;
+
+ public ResourceWallpaperInfo(Resources res, int resId, Drawable thumb) {
+ super(thumb);
+ mResources = res;
+ mResId = resId;
+ }
+
+ @Override
+ public void onClick(final WallpaperPickerActivity a) {
+ a.setWallpaperButtonEnabled(false);
+ final BitmapRegionTileSource.ResourceBitmapSource bitmapSource =
+ new BitmapRegionTileSource.ResourceBitmapSource(mResources, mResId, a);
+ a.setCropViewTileSource(bitmapSource, false, false, new CropViewScaleAndOffsetProvider() {
+
+ @Override
+ public float getScale(Point wallpaperSize, RectF crop) {
+ return wallpaperSize.x /crop.width();
+ }
+
+ @Override
+ public float getParallaxOffset() {
+ return a.getWallpaperParallaxOffset();
+ }
+ }, new Runnable() {
+
+ @Override
+ public void run() {
+ if (bitmapSource.getLoadingState() == BitmapSource.State.LOADED) {
+ a.setWallpaperButtonEnabled(true);
+ }
+ }
+ });
+ }
+
+ @Override
+ public void onSave(WallpaperPickerActivity a) {
+ a.cropImageAndSetWallpaper(mResources, mResId, true /* shouldFadeOutOnFinish */);
+ }
+
+ @Override
+ public boolean isSelectable() {
+ return true;
+ }
+
+ @Override
+ public boolean isNamelessWallpaper() {
+ return true;
+ }
+} \ No newline at end of file
diff --git a/WallpaperPicker/src/com/android/launcher3/wallpapertileinfo/ThirdPartyWallpaperInfo.java b/WallpaperPicker/src/com/android/launcher3/wallpapertileinfo/ThirdPartyWallpaperInfo.java
new file mode 100644
index 000000000..5e2538f84
--- /dev/null
+++ b/WallpaperPicker/src/com/android/launcher3/wallpapertileinfo/ThirdPartyWallpaperInfo.java
@@ -0,0 +1,78 @@
+package com.android.launcher3.wallpapertileinfo;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import com.android.launcher3.R;
+import com.android.launcher3.WallpaperPickerActivity;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+
+public class ThirdPartyWallpaperInfo extends WallpaperTileInfo {
+
+ private final ResolveInfo mResolveInfo;
+ private final int mIconSize;
+
+ public ThirdPartyWallpaperInfo(ResolveInfo resolveInfo, int iconSize) {
+ mResolveInfo = resolveInfo;
+ mIconSize = iconSize;
+ }
+
+ @Override
+ public void onClick(WallpaperPickerActivity a) {
+ final ComponentName itemComponentName = new ComponentName(
+ mResolveInfo.activityInfo.packageName, mResolveInfo.activityInfo.name);
+ Intent launchIntent = new Intent(Intent.ACTION_SET_WALLPAPER)
+ .setComponent(itemComponentName)
+ .putExtra(WallpaperPickerActivity.EXTRA_WALLPAPER_OFFSET,
+ a.getWallpaperParallaxOffset());
+ a.startActivityForResultSafely(
+ launchIntent, WallpaperPickerActivity.PICK_WALLPAPER_THIRD_PARTY_ACTIVITY);
+ }
+
+ @Override
+ public View createView(Context context, LayoutInflater inflator, ViewGroup parent) {
+ mView = inflator.inflate(R.layout.wallpaper_picker_third_party_item, parent, false);
+
+ TextView label = (TextView) mView.findViewById(R.id.wallpaper_item_label);
+ label.setText(mResolveInfo.loadLabel(context.getPackageManager()));
+ Drawable icon = mResolveInfo.loadIcon(context.getPackageManager());
+ icon.setBounds(new Rect(0, 0, mIconSize, mIconSize));
+ label.setCompoundDrawables(null, icon, null, null);
+ return mView;
+ }
+
+ public static List<ThirdPartyWallpaperInfo> getAll(Context context) {
+ ArrayList<ThirdPartyWallpaperInfo> result = new ArrayList<>();
+ int iconSize = context.getResources().getDimensionPixelSize(R.dimen.wallpaperItemIconSize);
+
+ final PackageManager pm = context.getPackageManager();
+ Intent pickImageIntent = new Intent(Intent.ACTION_GET_CONTENT).setType("image/*");
+ HashSet<String> excludePackages = new HashSet<>();
+ // Exclude packages which contain an image picker
+ for (ResolveInfo info : pm.queryIntentActivities(pickImageIntent, 0)) {
+ excludePackages.add(info.activityInfo.packageName);
+ }
+ excludePackages.add(context.getPackageName());
+ excludePackages.add("com.android.wallpaper.livepicker");
+
+ final Intent pickWallpaperIntent = new Intent(Intent.ACTION_SET_WALLPAPER);
+ for (ResolveInfo info : pm.queryIntentActivities(pickWallpaperIntent, 0)) {
+ if (!excludePackages.contains(info.activityInfo.packageName)) {
+ result.add(new ThirdPartyWallpaperInfo(info, iconSize));
+ }
+ }
+ return result;
+ }
+} \ No newline at end of file
diff --git a/WallpaperPicker/src/com/android/launcher3/wallpapertileinfo/UriWallpaperInfo.java b/WallpaperPicker/src/com/android/launcher3/wallpapertileinfo/UriWallpaperInfo.java
new file mode 100644
index 000000000..180eb93e0
--- /dev/null
+++ b/WallpaperPicker/src/com/android/launcher3/wallpapertileinfo/UriWallpaperInfo.java
@@ -0,0 +1,109 @@
+package com.android.launcher3.wallpapertileinfo;
+
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Toast;
+
+import com.android.gallery3d.common.BitmapCropTask;
+import com.android.gallery3d.common.BitmapUtils;
+import com.android.launcher3.R;
+import com.android.launcher3.WallpaperPickerActivity;
+import com.android.photos.BitmapRegionTileSource;
+import com.android.photos.BitmapRegionTileSource.BitmapSource;
+
+public class UriWallpaperInfo extends DrawableThumbWallpaperInfo {
+
+ private static final String TAG = "UriWallpaperInfo";
+
+ public final Uri mUri;
+
+ public UriWallpaperInfo(Uri uri) {
+ super(null);
+ mUri = uri;
+ }
+
+ @Override
+ public void onClick(final WallpaperPickerActivity a) {
+ a.setWallpaperButtonEnabled(false);
+ final BitmapRegionTileSource.UriBitmapSource bitmapSource =
+ new BitmapRegionTileSource.UriBitmapSource(a.getContext(), mUri);
+ a.setCropViewTileSource(bitmapSource, true, false, null, new Runnable() {
+
+ @Override
+ public void run() {
+ if (bitmapSource.getLoadingState() == BitmapSource.State.LOADED) {
+ a.selectTile(mView);
+ a.setWallpaperButtonEnabled(true);
+ } else {
+ ViewGroup parent = (ViewGroup) mView.getParent();
+ if (parent != null) {
+ parent.removeView(mView);
+ Toast.makeText(a.getContext(), R.string.image_load_fail,
+ Toast.LENGTH_SHORT).show();
+ }
+ }
+ }
+ });
+ }
+
+ @Override
+ public void onSave(final WallpaperPickerActivity a) {
+ BitmapCropTask.OnBitmapCroppedHandler h = new BitmapCropTask.OnBitmapCroppedHandler() {
+ public void onBitmapCropped(byte[] imageBytes) {
+ // rotation is set to 0 since imageBytes has already been correctly rotated
+ Bitmap thumb = createThumbnail(a, null, imageBytes, null, 0, 0, true);
+ a.getSavedImages().writeImage(thumb, imageBytes);
+ }
+ };
+ boolean shouldFadeOutOnFinish = a.getWallpaperParallaxOffset() == 0f;
+ a.cropImageAndSetWallpaper(mUri, h, shouldFadeOutOnFinish);
+ }
+
+ @Override
+ public boolean isSelectable() {
+ return true;
+ }
+
+ @Override
+ public boolean isNamelessWallpaper() {
+ return true;
+ }
+
+ public void loadThumbnaleAsync(final WallpaperPickerActivity activity) {
+ mView.setVisibility(View.GONE);
+ new AsyncTask<Void, Void, Bitmap>() {
+ protected Bitmap doInBackground(Void...args) {
+ try {
+ int rotation = BitmapUtils.getRotationFromExif(activity, mUri);
+ return createThumbnail(activity, mUri, null, null, 0, rotation, false);
+ } catch (SecurityException securityException) {
+ if (activity.isActivityDestroyed()) {
+ // Temporarily granted permissions are revoked when the activity
+ // finishes, potentially resulting in a SecurityException here.
+ // Even though {@link #isDestroyed} might also return true in different
+ // situations where the configuration changes, we are fine with
+ // catching these cases here as well.
+ cancel(false);
+ } else {
+ // otherwise it had a different cause and we throw it further
+ throw securityException;
+ }
+ return null;
+ }
+ }
+ protected void onPostExecute(Bitmap thumb) {
+ if (!isCancelled() && thumb != null) {
+ setThumb(new BitmapDrawable(activity.getResources(), thumb));
+ mView.setVisibility(View.VISIBLE);
+ } else {
+ Log.e(TAG, "Error loading thumbnail for uri=" + mUri);
+ }
+ }
+ }.execute();
+ }
+} \ No newline at end of file
diff --git a/WallpaperPicker/src/com/android/launcher3/wallpapertileinfo/WallpaperTileInfo.java b/WallpaperPicker/src/com/android/launcher3/wallpapertileinfo/WallpaperTileInfo.java
new file mode 100644
index 000000000..5fc317c3a
--- /dev/null
+++ b/WallpaperPicker/src/com/android/launcher3/wallpapertileinfo/WallpaperTileInfo.java
@@ -0,0 +1,87 @@
+package com.android.launcher3.wallpapertileinfo;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Matrix;
+import android.graphics.Point;
+import android.graphics.RectF;
+import android.net.Uri;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.gallery3d.common.BitmapCropTask;
+import com.android.gallery3d.common.Utils;
+import com.android.launcher3.R;
+import com.android.launcher3.WallpaperPickerActivity;
+
+public abstract class WallpaperTileInfo {
+
+ protected View mView;
+
+ public void onClick(WallpaperPickerActivity a) {}
+
+ public void onSave(WallpaperPickerActivity a) {}
+
+ public void onDelete(WallpaperPickerActivity a) {}
+
+ public boolean isSelectable() { return false; }
+
+ public boolean isNamelessWallpaper() { return false; }
+
+ public void onIndexUpdated(CharSequence label) {
+ if (isNamelessWallpaper()) {
+ mView.setContentDescription(label);
+ }
+ }
+
+ public abstract View createView(Context context, LayoutInflater inflator, ViewGroup parent);
+
+ protected static Point getDefaultThumbSize(Resources res) {
+ return new Point(res.getDimensionPixelSize(R.dimen.wallpaperThumbnailWidth),
+ res.getDimensionPixelSize(R.dimen.wallpaperThumbnailHeight));
+
+ }
+
+ protected static Bitmap createThumbnail(Context context, Uri uri, byte[] imageBytes,
+ Resources res, int resId, int rotation, boolean leftAligned) {
+ Point size = getDefaultThumbSize(context.getResources());
+ int width = size.x;
+ int height = size.y;
+
+ BitmapCropTask cropTask;
+ if (uri != null) {
+ cropTask = new BitmapCropTask(
+ context, uri, null, rotation, width, height, false, true, null);
+ } else if (imageBytes != null) {
+ cropTask = new BitmapCropTask(
+ imageBytes, null, rotation, width, height, false, true, null);
+ } else {
+ cropTask = new BitmapCropTask(
+ context, res, resId, null, rotation, width, height, false, true, null);
+ }
+ Point bounds = cropTask.getImageBounds();
+ if (bounds == null || bounds.x == 0 || bounds.y == 0) {
+ return null;
+ }
+
+ Matrix rotateMatrix = new Matrix();
+ rotateMatrix.setRotate(rotation);
+ float[] rotatedBounds = new float[] { bounds.x, bounds.y };
+ rotateMatrix.mapPoints(rotatedBounds);
+ rotatedBounds[0] = Math.abs(rotatedBounds[0]);
+ rotatedBounds[1] = Math.abs(rotatedBounds[1]);
+
+ RectF cropRect = Utils.getMaxCropRect(
+ (int) rotatedBounds[0], (int) rotatedBounds[1], width, height, leftAligned);
+ cropTask.setCropBounds(cropRect);
+
+ if (cropTask.cropBitmap()) {
+ return cropTask.getCroppedBitmap();
+ } else {
+ return null;
+ }
+ }
+
+} \ No newline at end of file
diff --git a/WallpaperPicker/src/com/android/photos/BitmapRegionTileSource.java b/WallpaperPicker/src/com/android/photos/BitmapRegionTileSource.java
index 2d496a5a6..2f9c9a343 100644
--- a/WallpaperPicker/src/com/android/photos/BitmapRegionTileSource.java
+++ b/WallpaperPicker/src/com/android/photos/BitmapRegionTileSource.java
@@ -31,8 +31,8 @@ import android.os.Build;
import android.util.Log;
import com.android.gallery3d.common.BitmapUtils;
+import com.android.gallery3d.common.ExifOrientation;
import com.android.gallery3d.common.Utils;
-import com.android.gallery3d.exif.ExifInterface;
import com.android.gallery3d.glrenderer.BasicTexture;
import com.android.gallery3d.glrenderer.BitmapTexture;
import com.android.photos.views.TiledImageRenderer;
@@ -160,13 +160,7 @@ public class BitmapRegionTileSource implements TiledImageRenderer.TileSource {
private State mState = State.NOT_LOADED;
public boolean loadInBackground(InBitmapProvider bitmapProvider) {
- ExifInterface ei = new ExifInterface();
- if (readExif(ei)) {
- Integer ori = ei.getTagIntValue(ExifInterface.TAG_ORIENTATION);
- if (ori != null) {
- mRotation = ExifInterface.getRotationForOrientationValue(ori.shortValue());
- }
- }
+ mRotation = getExifRotation();
mDecoder = loadBitmapRegionDecoder();
if (mDecoder == null) {
mState = State.ERROR_LOADING;
@@ -232,7 +226,7 @@ public class BitmapRegionTileSource implements TiledImageRenderer.TileSource {
return mRotation;
}
- public abstract boolean readExif(ExifInterface ei);
+ public abstract int getExifRotation();
public abstract SimpleBitmapRegionDecoder loadBitmapRegionDecoder();
public abstract Bitmap loadPreviewBitmap(BitmapFactory.Options options);
@@ -259,18 +253,10 @@ public class BitmapRegionTileSource implements TiledImageRenderer.TileSource {
public Bitmap loadPreviewBitmap(BitmapFactory.Options options) {
return BitmapFactory.decodeFile(mPath, options);
}
+
@Override
- public boolean readExif(ExifInterface ei) {
- try {
- ei.readExif(mPath);
- return true;
- } catch (NullPointerException e) {
- Log.w("BitmapRegionTileSource", "reading exif failed", e);
- return false;
- } catch (IOException e) {
- Log.w("BitmapRegionTileSource", "getting decoder failed", e);
- return false;
- }
+ public int getExifRotation() {
+ return ExifOrientation.readRotation(mPath);
}
}
@@ -315,35 +301,22 @@ public class BitmapRegionTileSource implements TiledImageRenderer.TileSource {
return null;
}
}
+
@Override
- public boolean readExif(ExifInterface ei) {
- InputStream is = null;
- try {
- is = regenerateInputStream();
- ei.readExif(is);
- Utils.closeSilently(is);
- return true;
- } catch (FileNotFoundException e) {
- Log.d("BitmapRegionTileSource", "Failed to load URI " + mUri, e);
- return false;
- } catch (IOException e) {
- Log.d("BitmapRegionTileSource", "Failed to load URI " + mUri, e);
- return false;
- } catch (NullPointerException e) {
- Log.d("BitmapRegionTileSource", "Failed to read EXIF for URI " + mUri, e);
- return false;
- } finally {
- Utils.closeSilently(is);
- }
+ public int getExifRotation() {
+ return BitmapUtils.getRotationFromExif(mContext, mUri);
}
}
public static class ResourceBitmapSource extends BitmapSource {
private Resources mRes;
private int mResId;
- public ResourceBitmapSource(Resources res, int resId) {
+ private Context mContext;
+
+ public ResourceBitmapSource(Resources res, int resId, Context context) {
mRes = res;
mResId = resId;
+ mContext = context;
}
private InputStream regenerateInputStream() {
InputStream is = mRes.openRawResource(mResId);
@@ -366,17 +339,10 @@ public class BitmapRegionTileSource implements TiledImageRenderer.TileSource {
public Bitmap loadPreviewBitmap(BitmapFactory.Options options) {
return BitmapFactory.decodeResource(mRes, mResId, options);
}
+
@Override
- public boolean readExif(ExifInterface ei) {
- try {
- InputStream is = regenerateInputStream();
- ei.readExif(is);
- Utils.closeSilently(is);
- return true;
- } catch (IOException e) {
- Log.e("BitmapRegionTileSource", "Error reading resource", e);
- return false;
- }
+ public int getExifRotation() {
+ return BitmapUtils.getRotationFromExif(mRes, mResId, mContext);
}
}
diff --git a/WallpaperPicker/src/com/android/photos/views/TiledImageView.java b/WallpaperPicker/src/com/android/photos/views/TiledImageView.java
index 7e3e1a936..6f7a5303c 100644
--- a/WallpaperPicker/src/com/android/photos/views/TiledImageView.java
+++ b/WallpaperPicker/src/com/android/photos/views/TiledImageView.java
@@ -17,12 +17,7 @@
package com.android.photos.views;
import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
import android.graphics.Matrix;
-import android.graphics.Paint;
-import android.graphics.Paint.Align;
import android.graphics.RectF;
import android.opengl.GLSurfaceView;
import android.opengl.GLSurfaceView.Renderer;
@@ -82,7 +77,6 @@ public class TiledImageView extends FrameLayout {
mGLSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
addView(mGLSurfaceView, new LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
- //setTileSource(new ColoredTiles());
}
@Override
@@ -247,66 +241,4 @@ public class TiledImageView extends FrameLayout {
}
}
-
- @SuppressWarnings("unused")
- private static class ColoredTiles implements TileSource {
- private static final int[] COLORS = new int[] {
- Color.RED,
- Color.BLUE,
- Color.YELLOW,
- Color.GREEN,
- Color.CYAN,
- Color.MAGENTA,
- Color.WHITE,
- };
-
- private Paint mPaint = new Paint();
- private Canvas mCanvas = new Canvas();
-
- @Override
- public int getTileSize() {
- return 256;
- }
-
- @Override
- public int getImageWidth() {
- return 16384;
- }
-
- @Override
- public int getImageHeight() {
- return 8192;
- }
-
- @Override
- public int getRotation() {
- return 0;
- }
-
- @Override
- public Bitmap getTile(int level, int x, int y, Bitmap bitmap) {
- int tileSize = getTileSize();
- if (bitmap == null) {
- bitmap = Bitmap.createBitmap(tileSize, tileSize,
- Bitmap.Config.ARGB_8888);
- }
- mCanvas.setBitmap(bitmap);
- mCanvas.drawColor(COLORS[level]);
- mPaint.setColor(Color.BLACK);
- mPaint.setTextSize(20);
- mPaint.setTextAlign(Align.CENTER);
- mCanvas.drawText(x + "x" + y, 128, 128, mPaint);
- tileSize <<= level;
- x /= tileSize;
- y /= tileSize;
- mCanvas.drawText(x + "x" + y + " @ " + level, 128, 30, mPaint);
- mCanvas.setBitmap(null);
- return bitmap;
- }
-
- @Override
- public BasicTexture getPreview() {
- return null;
- }
- }
}