summaryrefslogtreecommitdiffstats
path: root/src/com/android/gallery3d/data
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/gallery3d/data')
-rw-r--r--src/com/android/gallery3d/data/ActionImage.java103
-rw-r--r--src/com/android/gallery3d/data/BucketHelper.java241
-rw-r--r--src/com/android/gallery3d/data/BytesBufferPool.java91
-rw-r--r--src/com/android/gallery3d/data/CameraShortcutImage.java34
-rw-r--r--src/com/android/gallery3d/data/ChangeNotifier.java57
-rw-r--r--src/com/android/gallery3d/data/ClusterAlbum.java143
-rw-r--r--src/com/android/gallery3d/data/ClusterAlbumSet.java159
-rw-r--r--src/com/android/gallery3d/data/ClusterSource.java86
-rw-r--r--src/com/android/gallery3d/data/Clustering.java29
-rw-r--r--src/com/android/gallery3d/data/ComboAlbum.java103
-rw-r--r--src/com/android/gallery3d/data/ComboAlbumSet.java96
-rw-r--r--src/com/android/gallery3d/data/ComboSource.java55
-rw-r--r--src/com/android/gallery3d/data/ContentListener.java21
-rw-r--r--src/com/android/gallery3d/data/DataManager.java371
-rw-r--r--src/com/android/gallery3d/data/DataSourceType.java45
-rw-r--r--src/com/android/gallery3d/data/DecodeUtils.java312
-rw-r--r--src/com/android/gallery3d/data/DownloadCache.java370
-rw-r--r--src/com/android/gallery3d/data/DownloadEntry.java72
-rw-r--r--src/com/android/gallery3d/data/DownloadUtils.java79
-rw-r--r--src/com/android/gallery3d/data/EmptyAlbumImage.java34
-rw-r--r--src/com/android/gallery3d/data/Exif.java48
-rw-r--r--src/com/android/gallery3d/data/Face.java65
-rw-r--r--src/com/android/gallery3d/data/FaceClustering.java142
-rw-r--r--src/com/android/gallery3d/data/FilterDeleteSet.java256
-rw-r--r--src/com/android/gallery3d/data/FilterEmptyPromptSet.java82
-rw-r--r--src/com/android/gallery3d/data/FilterSource.java94
-rw-r--r--src/com/android/gallery3d/data/FilterTypeSet.java137
-rw-r--r--src/com/android/gallery3d/data/ImageCacheRequest.java102
-rw-r--r--src/com/android/gallery3d/data/ImageCacheService.java123
-rw-r--r--src/com/android/gallery3d/data/LocalAlbum.java325
-rw-r--r--src/com/android/gallery3d/data/LocalAlbumSet.java211
-rw-r--r--src/com/android/gallery3d/data/LocalImage.java355
-rw-r--r--src/com/android/gallery3d/data/LocalMediaItem.java109
-rw-r--r--src/com/android/gallery3d/data/LocalMergeAlbum.java257
-rw-r--r--src/com/android/gallery3d/data/LocalSource.java275
-rw-r--r--src/com/android/gallery3d/data/LocalVideo.java242
-rw-r--r--src/com/android/gallery3d/data/LocationClustering.java316
-rw-r--r--src/com/android/gallery3d/data/Log.java53
-rw-r--r--src/com/android/gallery3d/data/MediaDetails.java170
-rw-r--r--src/com/android/gallery3d/data/MediaItem.java134
-rw-r--r--src/com/android/gallery3d/data/MediaObject.java166
-rw-r--r--src/com/android/gallery3d/data/MediaSet.java348
-rw-r--r--src/com/android/gallery3d/data/MediaSource.java96
-rw-r--r--src/com/android/gallery3d/data/MtpClient.java443
-rw-r--r--src/com/android/gallery3d/data/PanoramaMetadataJob.java40
-rw-r--r--src/com/android/gallery3d/data/Path.java241
-rw-r--r--src/com/android/gallery3d/data/PathMatcher.java102
-rw-r--r--src/com/android/gallery3d/data/SecureAlbum.java206
-rw-r--r--src/com/android/gallery3d/data/SecureSource.java56
-rw-r--r--src/com/android/gallery3d/data/SingleItemAlbum.java68
-rw-r--r--src/com/android/gallery3d/data/SizeClustering.java141
-rw-r--r--src/com/android/gallery3d/data/SnailAlbum.java44
-rw-r--r--src/com/android/gallery3d/data/SnailItem.java95
-rw-r--r--src/com/android/gallery3d/data/SnailSource.java70
-rw-r--r--src/com/android/gallery3d/data/TagClustering.java95
-rw-r--r--src/com/android/gallery3d/data/TimeClustering.java439
-rw-r--r--src/com/android/gallery3d/data/UnlockImage.java34
-rw-r--r--src/com/android/gallery3d/data/UriImage.java298
-rw-r--r--src/com/android/gallery3d/data/UriSource.java95
59 files changed, 0 insertions, 9074 deletions
diff --git a/src/com/android/gallery3d/data/ActionImage.java b/src/com/android/gallery3d/data/ActionImage.java
deleted file mode 100644
index 58e30b146..000000000
--- a/src/com/android/gallery3d/data/ActionImage.java
+++ /dev/null
@@ -1,103 +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.data;
-
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.BitmapRegionDecoder;
-import android.net.Uri;
-
-import com.android.gallery3d.app.GalleryApp;
-import com.android.gallery3d.common.BitmapUtils;
-import com.android.gallery3d.common.Utils;
-import com.android.gallery3d.util.ThreadPool.Job;
-import com.android.gallery3d.util.ThreadPool.JobContext;
-
-public class ActionImage extends MediaItem {
- @SuppressWarnings("unused")
- private static final String TAG = "ActionImage";
- private GalleryApp mApplication;
- private int mResourceId;
-
- public ActionImage(Path path, GalleryApp application, int resourceId) {
- super(path, nextVersionNumber());
- mApplication = Utils.checkNotNull(application);
- mResourceId = resourceId;
- }
-
- @Override
- public Job<Bitmap> requestImage(int type) {
- return new BitmapJob(type);
- }
-
- @Override
- public Job<BitmapRegionDecoder> requestLargeImage() {
- return null;
- }
-
- private class BitmapJob implements Job<Bitmap> {
- private int mType;
-
- protected BitmapJob(int type) {
- mType = type;
- }
-
- @Override
- public Bitmap run(JobContext jc) {
- int targetSize = MediaItem.getTargetSize(mType);
- Bitmap bitmap = BitmapFactory.decodeResource(mApplication.getResources(),
- mResourceId);
-
- if (mType == MediaItem.TYPE_MICROTHUMBNAIL) {
- bitmap = BitmapUtils.resizeAndCropCenter(bitmap, targetSize, true);
- } else {
- bitmap = BitmapUtils.resizeDownBySideLength(bitmap, targetSize, true);
- }
- return bitmap;
- }
- }
-
- @Override
- public int getSupportedOperations() {
- return SUPPORT_ACTION;
- }
-
- @Override
- public int getMediaType() {
- return MEDIA_TYPE_UNKNOWN;
- }
-
- @Override
- public Uri getContentUri() {
- return null;
- }
-
- @Override
- public String getMimeType() {
- return "";
- }
-
- @Override
- public int getWidth() {
- return 0;
- }
-
- @Override
- public int getHeight() {
- return 0;
- }
-}
diff --git a/src/com/android/gallery3d/data/BucketHelper.java b/src/com/android/gallery3d/data/BucketHelper.java
deleted file mode 100644
index 3418dafb7..000000000
--- a/src/com/android/gallery3d/data/BucketHelper.java
+++ /dev/null
@@ -1,241 +0,0 @@
-package com.android.gallery3d.data;
-
-import android.annotation.TargetApi;
-import android.content.ContentResolver;
-import android.database.Cursor;
-import android.net.Uri;
-import android.provider.MediaStore.Files;
-import android.provider.MediaStore.Files.FileColumns;
-import android.provider.MediaStore.Images;
-import android.provider.MediaStore.Images.ImageColumns;
-import android.provider.MediaStore.Video;
-import android.util.Log;
-
-import com.android.gallery3d.common.ApiHelper;
-import com.android.gallery3d.common.Utils;
-import com.android.gallery3d.util.ThreadPool.JobContext;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Comparator;
-import java.util.HashMap;
-
-class BucketHelper {
-
- private static final String TAG = "BucketHelper";
- private static final String EXTERNAL_MEDIA = "external";
-
- // BUCKET_DISPLAY_NAME is a string like "Camera" which is the directory
- // name of where an image or video is in. BUCKET_ID is a hash of the path
- // name of that directory (see computeBucketValues() in MediaProvider for
- // details). MEDIA_TYPE is video, image, audio, etc.
- //
- // The "albums" are not explicitly recorded in the database, but each image
- // or video has the two columns (BUCKET_ID, MEDIA_TYPE). We define an
- // "album" to be the collection of images/videos which have the same value
- // for the two columns.
- //
- // The goal of the query (used in loadSubMediaSetsFromFilesTable()) is to
- // find all albums, that is, all unique values for (BUCKET_ID, MEDIA_TYPE).
- // In the meantime sort them by the timestamp of the latest image/video in
- // each of the album.
- //
- // The order of columns below is important: it must match to the index in
- // MediaStore.
- private static final String[] PROJECTION_BUCKET = {
- ImageColumns.BUCKET_ID,
- FileColumns.MEDIA_TYPE,
- ImageColumns.BUCKET_DISPLAY_NAME};
-
- // The indices should match the above projections.
- private static final int INDEX_BUCKET_ID = 0;
- private static final int INDEX_MEDIA_TYPE = 1;
- private static final int INDEX_BUCKET_NAME = 2;
-
- // We want to order the albums by reverse chronological order. We abuse the
- // "WHERE" parameter to insert a "GROUP BY" clause into the SQL statement.
- // The template for "WHERE" parameter is like:
- // SELECT ... FROM ... WHERE (%s)
- // and we make it look like:
- // SELECT ... FROM ... WHERE (1) GROUP BY 1,(2)
- // The "(1)" means true. The "1,(2)" means the first two columns specified
- // after SELECT. Note that because there is a ")" in the template, we use
- // "(2" to match it.
- private static final String BUCKET_GROUP_BY = "1) GROUP BY 1,(2";
-
- private static final String BUCKET_ORDER_BY = "MAX(datetaken) DESC";
-
- // Before HoneyComb there is no Files table. Thus, we need to query the
- // bucket info from the Images and Video tables and then merge them
- // together.
- //
- // A bucket can exist in both tables. In this case, we need to find the
- // latest timestamp from the two tables and sort ourselves. So we add the
- // MAX(date_taken) to the projection and remove the media_type since we
- // already know the media type from the table we query from.
- private static final String[] PROJECTION_BUCKET_IN_ONE_TABLE = {
- ImageColumns.BUCKET_ID,
- "MAX(datetaken)",
- ImageColumns.BUCKET_DISPLAY_NAME};
-
- // We keep the INDEX_BUCKET_ID and INDEX_BUCKET_NAME the same as
- // PROJECTION_BUCKET so we can reuse the values defined before.
- private static final int INDEX_DATE_TAKEN = 1;
-
- // When query from the Images or Video tables, we only need to group by BUCKET_ID.
- private static final String BUCKET_GROUP_BY_IN_ONE_TABLE = "1) GROUP BY (1";
-
- public static BucketEntry[] loadBucketEntries(
- JobContext jc, ContentResolver resolver, int type) {
- if (ApiHelper.HAS_MEDIA_PROVIDER_FILES_TABLE) {
- return loadBucketEntriesFromFilesTable(jc, resolver, type);
- } else {
- return loadBucketEntriesFromImagesAndVideoTable(jc, resolver, type);
- }
- }
-
- private static void updateBucketEntriesFromTable(JobContext jc,
- ContentResolver resolver, Uri tableUri, HashMap<Integer, BucketEntry> buckets) {
- Cursor cursor = resolver.query(tableUri, PROJECTION_BUCKET_IN_ONE_TABLE,
- BUCKET_GROUP_BY_IN_ONE_TABLE, null, null);
- if (cursor == null) {
- Log.w(TAG, "cannot open media database: " + tableUri);
- return;
- }
- try {
- while (cursor.moveToNext()) {
- int bucketId = cursor.getInt(INDEX_BUCKET_ID);
- int dateTaken = cursor.getInt(INDEX_DATE_TAKEN);
- BucketEntry entry = buckets.get(bucketId);
- if (entry == null) {
- entry = new BucketEntry(bucketId, cursor.getString(INDEX_BUCKET_NAME));
- buckets.put(bucketId, entry);
- entry.dateTaken = dateTaken;
- } else {
- entry.dateTaken = Math.max(entry.dateTaken, dateTaken);
- }
- }
- } finally {
- Utils.closeSilently(cursor);
- }
- }
-
- private static BucketEntry[] loadBucketEntriesFromImagesAndVideoTable(
- JobContext jc, ContentResolver resolver, int type) {
- HashMap<Integer, BucketEntry> buckets = new HashMap<Integer, BucketEntry>(64);
- if ((type & MediaObject.MEDIA_TYPE_IMAGE) != 0) {
- updateBucketEntriesFromTable(
- jc, resolver, Images.Media.EXTERNAL_CONTENT_URI, buckets);
- }
- if ((type & MediaObject.MEDIA_TYPE_VIDEO) != 0) {
- updateBucketEntriesFromTable(
- jc, resolver, Video.Media.EXTERNAL_CONTENT_URI, buckets);
- }
- BucketEntry[] entries = buckets.values().toArray(new BucketEntry[buckets.size()]);
- Arrays.sort(entries, new Comparator<BucketEntry>() {
- @Override
- public int compare(BucketEntry a, BucketEntry b) {
- // sorted by dateTaken in descending order
- return b.dateTaken - a.dateTaken;
- }
- });
- return entries;
- }
-
- private static BucketEntry[] loadBucketEntriesFromFilesTable(
- JobContext jc, ContentResolver resolver, int type) {
- Uri uri = getFilesContentUri();
-
- Cursor cursor = resolver.query(uri,
- PROJECTION_BUCKET, BUCKET_GROUP_BY,
- null, BUCKET_ORDER_BY);
- if (cursor == null) {
- Log.w(TAG, "cannot open local database: " + uri);
- return new BucketEntry[0];
- }
- ArrayList<BucketEntry> buffer = new ArrayList<BucketEntry>();
- int typeBits = 0;
- if ((type & MediaObject.MEDIA_TYPE_IMAGE) != 0) {
- typeBits |= (1 << FileColumns.MEDIA_TYPE_IMAGE);
- }
- if ((type & MediaObject.MEDIA_TYPE_VIDEO) != 0) {
- typeBits |= (1 << FileColumns.MEDIA_TYPE_VIDEO);
- }
- try {
- while (cursor.moveToNext()) {
- if ((typeBits & (1 << cursor.getInt(INDEX_MEDIA_TYPE))) != 0) {
- BucketEntry entry = new BucketEntry(
- cursor.getInt(INDEX_BUCKET_ID),
- cursor.getString(INDEX_BUCKET_NAME));
- if (!buffer.contains(entry)) {
- buffer.add(entry);
- }
- }
- if (jc.isCancelled()) return null;
- }
- } finally {
- Utils.closeSilently(cursor);
- }
- return buffer.toArray(new BucketEntry[buffer.size()]);
- }
-
- private static String getBucketNameInTable(
- ContentResolver resolver, Uri tableUri, int bucketId) {
- String selectionArgs[] = new String[] {String.valueOf(bucketId)};
- Uri uri = tableUri.buildUpon()
- .appendQueryParameter("limit", "1")
- .build();
- Cursor cursor = resolver.query(uri, PROJECTION_BUCKET_IN_ONE_TABLE,
- "bucket_id = ?", selectionArgs, null);
- try {
- if (cursor != null && cursor.moveToNext()) {
- return cursor.getString(INDEX_BUCKET_NAME);
- }
- } finally {
- Utils.closeSilently(cursor);
- }
- return null;
- }
-
- @TargetApi(ApiHelper.VERSION_CODES.HONEYCOMB)
- private static Uri getFilesContentUri() {
- return Files.getContentUri(EXTERNAL_MEDIA);
- }
-
- public static String getBucketName(ContentResolver resolver, int bucketId) {
- if (ApiHelper.HAS_MEDIA_PROVIDER_FILES_TABLE) {
- String result = getBucketNameInTable(resolver, getFilesContentUri(), bucketId);
- return result == null ? "" : result;
- } else {
- String result = getBucketNameInTable(
- resolver, Images.Media.EXTERNAL_CONTENT_URI, bucketId);
- if (result != null) return result;
- result = getBucketNameInTable(
- resolver, Video.Media.EXTERNAL_CONTENT_URI, bucketId);
- return result == null ? "" : result;
- }
- }
-
- public static class BucketEntry {
- public String bucketName;
- public int bucketId;
- public int dateTaken;
-
- public BucketEntry(int id, String name) {
- bucketId = id;
- bucketName = Utils.ensureNotNull(name);
- }
-
- @Override
- public int hashCode() {
- return bucketId;
- }
-
- @Override
- public boolean equals(Object object) {
- if (!(object instanceof BucketEntry)) return false;
- BucketEntry entry = (BucketEntry) object;
- return bucketId == entry.bucketId;
- }
- }
-}
diff --git a/src/com/android/gallery3d/data/BytesBufferPool.java b/src/com/android/gallery3d/data/BytesBufferPool.java
deleted file mode 100644
index d2da323fc..000000000
--- a/src/com/android/gallery3d/data/BytesBufferPool.java
+++ /dev/null
@@ -1,91 +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.data;
-
-import com.android.gallery3d.util.ThreadPool.JobContext;
-
-import java.io.FileDescriptor;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-
-public class BytesBufferPool {
-
- private static final int READ_STEP = 4096;
-
- public static class BytesBuffer {
- public byte[] data;
- public int offset;
- public int length;
-
- private BytesBuffer(int capacity) {
- this.data = new byte[capacity];
- }
-
- // an helper function to read content from FileDescriptor
- public void readFrom(JobContext jc, FileDescriptor fd) throws IOException {
- FileInputStream fis = new FileInputStream(fd);
- length = 0;
- try {
- int capacity = data.length;
- while (true) {
- int step = Math.min(READ_STEP, capacity - length);
- int rc = fis.read(data, length, step);
- if (rc < 0 || jc.isCancelled()) return;
- length += rc;
-
- if (length == capacity) {
- byte[] newData = new byte[data.length * 2];
- System.arraycopy(data, 0, newData, 0, data.length);
- data = newData;
- capacity = data.length;
- }
- }
- } finally {
- fis.close();
- }
- }
- }
-
- private final int mPoolSize;
- private final int mBufferSize;
- private final ArrayList<BytesBuffer> mList;
-
- public BytesBufferPool(int poolSize, int bufferSize) {
- mList = new ArrayList<BytesBuffer>(poolSize);
- mPoolSize = poolSize;
- mBufferSize = bufferSize;
- }
-
- public synchronized BytesBuffer get() {
- int n = mList.size();
- return n > 0 ? mList.remove(n - 1) : new BytesBuffer(mBufferSize);
- }
-
- public synchronized void recycle(BytesBuffer buffer) {
- if (buffer.data.length != mBufferSize) return;
- if (mList.size() < mPoolSize) {
- buffer.offset = 0;
- buffer.length = 0;
- mList.add(buffer);
- }
- }
-
- public synchronized void clear() {
- mList.clear();
- }
-}
diff --git a/src/com/android/gallery3d/data/CameraShortcutImage.java b/src/com/android/gallery3d/data/CameraShortcutImage.java
deleted file mode 100644
index 865270b4c..000000000
--- a/src/com/android/gallery3d/data/CameraShortcutImage.java
+++ /dev/null
@@ -1,34 +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.data;
-
-import com.android.gallery3d.R;
-import com.android.gallery3d.app.GalleryApp;
-
-public class CameraShortcutImage extends ActionImage {
- @SuppressWarnings("unused")
- private static final String TAG = "CameraShortcutImage";
-
- public CameraShortcutImage(Path path, GalleryApp application) {
- super(path, application, R.drawable.placeholder_camera);
- }
-
- @Override
- public int getSupportedOperations() {
- return super.getSupportedOperations() | SUPPORT_CAMERA_SHORTCUT;
- }
-}
diff --git a/src/com/android/gallery3d/data/ChangeNotifier.java b/src/com/android/gallery3d/data/ChangeNotifier.java
deleted file mode 100644
index 558a8648e..000000000
--- a/src/com/android/gallery3d/data/ChangeNotifier.java
+++ /dev/null
@@ -1,57 +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.data;
-
-import android.net.Uri;
-
-import com.android.gallery3d.app.GalleryApp;
-
-import java.util.concurrent.atomic.AtomicBoolean;
-
-// This handles change notification for media sets.
-public class ChangeNotifier {
-
- private MediaSet mMediaSet;
- private AtomicBoolean mContentDirty = new AtomicBoolean(true);
-
- public ChangeNotifier(MediaSet set, Uri uri, GalleryApp application) {
- mMediaSet = set;
- application.getDataManager().registerChangeNotifier(uri, this);
- }
-
- public ChangeNotifier(MediaSet set, Uri[] uris, GalleryApp application) {
- mMediaSet = set;
- for (int i = 0; i < uris.length; i++) {
- application.getDataManager().registerChangeNotifier(uris[i], this);
- }
- }
-
- // Returns the dirty flag and clear it.
- public boolean isDirty() {
- return mContentDirty.compareAndSet(true, false);
- }
-
- public void fakeChange() {
- onChange(false);
- }
-
- protected void onChange(boolean selfChange) {
- if (mContentDirty.compareAndSet(false, true)) {
- mMediaSet.notifyContentChanged();
- }
- }
-} \ No newline at end of file
diff --git a/src/com/android/gallery3d/data/ClusterAlbum.java b/src/com/android/gallery3d/data/ClusterAlbum.java
deleted file mode 100644
index 8681952bf..000000000
--- a/src/com/android/gallery3d/data/ClusterAlbum.java
+++ /dev/null
@@ -1,143 +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.data;
-
-import java.util.ArrayList;
-
-public class ClusterAlbum extends MediaSet implements ContentListener {
- @SuppressWarnings("unused")
- private static final String TAG = "ClusterAlbum";
- private ArrayList<Path> mPaths = new ArrayList<Path>();
- private String mName = "";
- private DataManager mDataManager;
- private MediaSet mClusterAlbumSet;
- private MediaItem mCover;
-
- public ClusterAlbum(Path path, DataManager dataManager,
- MediaSet clusterAlbumSet) {
- super(path, nextVersionNumber());
- mDataManager = dataManager;
- mClusterAlbumSet = clusterAlbumSet;
- mClusterAlbumSet.addContentListener(this);
- }
-
- public void setCoverMediaItem(MediaItem cover) {
- mCover = cover;
- }
-
- @Override
- public MediaItem getCoverMediaItem() {
- return mCover != null ? mCover : super.getCoverMediaItem();
- }
-
- void setMediaItems(ArrayList<Path> paths) {
- mPaths = paths;
- }
-
- ArrayList<Path> getMediaItems() {
- return mPaths;
- }
-
- public void setName(String name) {
- mName = name;
- }
-
- @Override
- public String getName() {
- return mName;
- }
-
- @Override
- public int getMediaItemCount() {
- return mPaths.size();
- }
-
- @Override
- public ArrayList<MediaItem> getMediaItem(int start, int count) {
- return getMediaItemFromPath(mPaths, start, count, mDataManager);
- }
-
- public static ArrayList<MediaItem> getMediaItemFromPath(
- ArrayList<Path> paths, int start, int count,
- DataManager dataManager) {
- if (start >= paths.size()) {
- return new ArrayList<MediaItem>();
- }
- int end = Math.min(start + count, paths.size());
- ArrayList<Path> subset = new ArrayList<Path>(paths.subList(start, end));
- final MediaItem[] buf = new MediaItem[end - start];
- ItemConsumer consumer = new ItemConsumer() {
- @Override
- public void consume(int index, MediaItem item) {
- buf[index] = item;
- }
- };
- dataManager.mapMediaItems(subset, consumer, 0);
- ArrayList<MediaItem> result = new ArrayList<MediaItem>(end - start);
- for (int i = 0; i < buf.length; i++) {
- result.add(buf[i]);
- }
- return result;
- }
-
- @Override
- protected int enumerateMediaItems(ItemConsumer consumer, int startIndex) {
- mDataManager.mapMediaItems(mPaths, consumer, startIndex);
- return mPaths.size();
- }
-
- @Override
- public int getTotalMediaItemCount() {
- return mPaths.size();
- }
-
- @Override
- public long reload() {
- if (mClusterAlbumSet.reload() > mDataVersion) {
- mDataVersion = nextVersionNumber();
- }
- return mDataVersion;
- }
-
- @Override
- public void onContentDirty() {
- notifyContentChanged();
- }
-
- @Override
- public int getSupportedOperations() {
- return SUPPORT_SHARE | SUPPORT_DELETE | SUPPORT_INFO;
- }
-
- @Override
- public void delete() {
- ItemConsumer consumer = new ItemConsumer() {
- @Override
- public void consume(int index, MediaItem item) {
- if ((item.getSupportedOperations() & SUPPORT_DELETE) != 0) {
- item.delete();
- }
- }
- };
- mDataManager.mapMediaItems(mPaths, consumer, 0);
- }
-
- @Override
- public boolean isLeafAlbum() {
- return true;
- }
-}
diff --git a/src/com/android/gallery3d/data/ClusterAlbumSet.java b/src/com/android/gallery3d/data/ClusterAlbumSet.java
deleted file mode 100644
index cb212ba36..000000000
--- a/src/com/android/gallery3d/data/ClusterAlbumSet.java
+++ /dev/null
@@ -1,159 +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.data;
-
-import android.content.Context;
-import android.net.Uri;
-
-import com.android.gallery3d.app.GalleryApp;
-
-import java.util.ArrayList;
-import java.util.HashSet;
-
-public class ClusterAlbumSet extends MediaSet implements ContentListener {
- @SuppressWarnings("unused")
- private static final String TAG = "ClusterAlbumSet";
- private GalleryApp mApplication;
- private MediaSet mBaseSet;
- private int mKind;
- private ArrayList<ClusterAlbum> mAlbums = new ArrayList<ClusterAlbum>();
- private boolean mFirstReloadDone;
-
- public ClusterAlbumSet(Path path, GalleryApp application,
- MediaSet baseSet, int kind) {
- super(path, INVALID_DATA_VERSION);
- mApplication = application;
- mBaseSet = baseSet;
- mKind = kind;
- baseSet.addContentListener(this);
- }
-
- @Override
- public MediaSet getSubMediaSet(int index) {
- return mAlbums.get(index);
- }
-
- @Override
- public int getSubMediaSetCount() {
- return mAlbums.size();
- }
-
- @Override
- public String getName() {
- return mBaseSet.getName();
- }
-
- @Override
- public long reload() {
- if (mBaseSet.reload() > mDataVersion) {
- if (mFirstReloadDone) {
- updateClustersContents();
- } else {
- updateClusters();
- mFirstReloadDone = true;
- }
- mDataVersion = nextVersionNumber();
- }
- return mDataVersion;
- }
-
- @Override
- public void onContentDirty() {
- notifyContentChanged();
- }
-
- private void updateClusters() {
- mAlbums.clear();
- Clustering clustering;
- Context context = mApplication.getAndroidContext();
- switch (mKind) {
- case ClusterSource.CLUSTER_ALBUMSET_TIME:
- clustering = new TimeClustering(context);
- break;
- case ClusterSource.CLUSTER_ALBUMSET_LOCATION:
- clustering = new LocationClustering(context);
- break;
- case ClusterSource.CLUSTER_ALBUMSET_TAG:
- clustering = new TagClustering(context);
- break;
- case ClusterSource.CLUSTER_ALBUMSET_FACE:
- clustering = new FaceClustering(context);
- break;
- default: /* CLUSTER_ALBUMSET_SIZE */
- clustering = new SizeClustering(context);
- break;
- }
-
- clustering.run(mBaseSet);
- int n = clustering.getNumberOfClusters();
- DataManager dataManager = mApplication.getDataManager();
- for (int i = 0; i < n; i++) {
- Path childPath;
- String childName = clustering.getClusterName(i);
- if (mKind == ClusterSource.CLUSTER_ALBUMSET_TAG) {
- childPath = mPath.getChild(Uri.encode(childName));
- } else if (mKind == ClusterSource.CLUSTER_ALBUMSET_SIZE) {
- long minSize = ((SizeClustering) clustering).getMinSize(i);
- childPath = mPath.getChild(minSize);
- } else {
- childPath = mPath.getChild(i);
- }
-
- ClusterAlbum album;
- synchronized (DataManager.LOCK) {
- album = (ClusterAlbum) dataManager.peekMediaObject(childPath);
- if (album == null) {
- album = new ClusterAlbum(childPath, dataManager, this);
- }
- }
- album.setMediaItems(clustering.getCluster(i));
- album.setName(childName);
- album.setCoverMediaItem(clustering.getClusterCover(i));
- mAlbums.add(album);
- }
- }
-
- private void updateClustersContents() {
- final HashSet<Path> existing = new HashSet<Path>();
- mBaseSet.enumerateTotalMediaItems(new MediaSet.ItemConsumer() {
- @Override
- public void consume(int index, MediaItem item) {
- existing.add(item.getPath());
- }
- });
-
- int n = mAlbums.size();
-
- // The loop goes backwards because we may remove empty albums from
- // mAlbums.
- for (int i = n - 1; i >= 0; i--) {
- ArrayList<Path> oldPaths = mAlbums.get(i).getMediaItems();
- ArrayList<Path> newPaths = new ArrayList<Path>();
- int m = oldPaths.size();
- for (int j = 0; j < m; j++) {
- Path p = oldPaths.get(j);
- if (existing.contains(p)) {
- newPaths.add(p);
- }
- }
- mAlbums.get(i).setMediaItems(newPaths);
- if (newPaths.isEmpty()) {
- mAlbums.remove(i);
- }
- }
- }
-}
diff --git a/src/com/android/gallery3d/data/ClusterSource.java b/src/com/android/gallery3d/data/ClusterSource.java
deleted file mode 100644
index a1f22e57a..000000000
--- a/src/com/android/gallery3d/data/ClusterSource.java
+++ /dev/null
@@ -1,86 +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.data;
-
-import com.android.gallery3d.app.GalleryApp;
-
-class ClusterSource extends MediaSource {
- static final int CLUSTER_ALBUMSET_TIME = 0;
- static final int CLUSTER_ALBUMSET_LOCATION = 1;
- static final int CLUSTER_ALBUMSET_TAG = 2;
- static final int CLUSTER_ALBUMSET_SIZE = 3;
- static final int CLUSTER_ALBUMSET_FACE = 4;
-
- static final int CLUSTER_ALBUM_TIME = 0x100;
- static final int CLUSTER_ALBUM_LOCATION = 0x101;
- static final int CLUSTER_ALBUM_TAG = 0x102;
- static final int CLUSTER_ALBUM_SIZE = 0x103;
- static final int CLUSTER_ALBUM_FACE = 0x104;
-
- GalleryApp mApplication;
- PathMatcher mMatcher;
-
- public ClusterSource(GalleryApp application) {
- super("cluster");
- mApplication = application;
- mMatcher = new PathMatcher();
- mMatcher.add("/cluster/*/time", CLUSTER_ALBUMSET_TIME);
- mMatcher.add("/cluster/*/location", CLUSTER_ALBUMSET_LOCATION);
- mMatcher.add("/cluster/*/tag", CLUSTER_ALBUMSET_TAG);
- mMatcher.add("/cluster/*/size", CLUSTER_ALBUMSET_SIZE);
- mMatcher.add("/cluster/*/face", CLUSTER_ALBUMSET_FACE);
-
- mMatcher.add("/cluster/*/time/*", CLUSTER_ALBUM_TIME);
- mMatcher.add("/cluster/*/location/*", CLUSTER_ALBUM_LOCATION);
- mMatcher.add("/cluster/*/tag/*", CLUSTER_ALBUM_TAG);
- mMatcher.add("/cluster/*/size/*", CLUSTER_ALBUM_SIZE);
- mMatcher.add("/cluster/*/face/*", CLUSTER_ALBUM_FACE);
- }
-
- // The names we accept are:
- // /cluster/{set}/time /cluster/{set}/time/k
- // /cluster/{set}/location /cluster/{set}/location/k
- // /cluster/{set}/tag /cluster/{set}/tag/encoded_tag
- // /cluster/{set}/size /cluster/{set}/size/min_size
- @Override
- public MediaObject createMediaObject(Path path) {
- int matchType = mMatcher.match(path);
- String setsName = mMatcher.getVar(0);
- DataManager dataManager = mApplication.getDataManager();
- MediaSet[] sets = dataManager.getMediaSetsFromString(setsName);
- switch (matchType) {
- case CLUSTER_ALBUMSET_TIME:
- case CLUSTER_ALBUMSET_LOCATION:
- case CLUSTER_ALBUMSET_TAG:
- case CLUSTER_ALBUMSET_SIZE:
- case CLUSTER_ALBUMSET_FACE:
- return new ClusterAlbumSet(path, mApplication, sets[0], matchType);
- case CLUSTER_ALBUM_TIME:
- case CLUSTER_ALBUM_LOCATION:
- case CLUSTER_ALBUM_TAG:
- case CLUSTER_ALBUM_SIZE:
- case CLUSTER_ALBUM_FACE: {
- MediaSet parent = dataManager.getMediaSet(path.getParent());
- // The actual content in the ClusterAlbum will be filled later
- // when the reload() method in the parent is run.
- return new ClusterAlbum(path, dataManager, parent);
- }
- default:
- throw new RuntimeException("bad path: " + path);
- }
- }
-}
diff --git a/src/com/android/gallery3d/data/Clustering.java b/src/com/android/gallery3d/data/Clustering.java
deleted file mode 100644
index 4072bf57b..000000000
--- a/src/com/android/gallery3d/data/Clustering.java
+++ /dev/null
@@ -1,29 +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.data;
-
-import java.util.ArrayList;
-
-public abstract class Clustering {
- public abstract void run(MediaSet baseSet);
- public abstract int getNumberOfClusters();
- public abstract ArrayList<Path> getCluster(int index);
- public abstract String getClusterName(int index);
- public MediaItem getClusterCover(int index) {
- return null;
- }
-}
diff --git a/src/com/android/gallery3d/data/ComboAlbum.java b/src/com/android/gallery3d/data/ComboAlbum.java
deleted file mode 100644
index cadd9f8af..000000000
--- a/src/com/android/gallery3d/data/ComboAlbum.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (C) 2011 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.data;
-
-import com.android.gallery3d.util.Future;
-
-import java.util.ArrayList;
-
-// ComboAlbum combines multiple media sets into one. It lists all media items
-// from the input albums.
-// This only handles SubMediaSets, not MediaItems. (That's all we need now)
-public class ComboAlbum extends MediaSet implements ContentListener {
- @SuppressWarnings("unused")
- private static final String TAG = "ComboAlbum";
- private final MediaSet[] mSets;
- private String mName;
-
- public ComboAlbum(Path path, MediaSet[] mediaSets, String name) {
- super(path, nextVersionNumber());
- mSets = mediaSets;
- for (MediaSet set : mSets) {
- set.addContentListener(this);
- }
- mName = name;
- }
-
- @Override
- public ArrayList<MediaItem> getMediaItem(int start, int count) {
- ArrayList<MediaItem> items = new ArrayList<MediaItem>();
- for (MediaSet set : mSets) {
- int size = set.getMediaItemCount();
- if (count < 1) break;
- if (start < size) {
- int fetchCount = (start + count <= size) ? count : size - start;
- ArrayList<MediaItem> fetchItems = set.getMediaItem(start, fetchCount);
- items.addAll(fetchItems);
- count -= fetchItems.size();
- start = 0;
- } else {
- start -= size;
- }
- }
- return items;
- }
-
- @Override
- public int getMediaItemCount() {
- int count = 0;
- for (MediaSet set : mSets) {
- count += set.getMediaItemCount();
- }
- return count;
- }
-
- @Override
- public boolean isLeafAlbum() {
- return true;
- }
-
- @Override
- public String getName() {
- return mName;
- }
-
- public void useNameOfChild(int i) {
- if (i < mSets.length) mName = mSets[i].getName();
- }
-
- @Override
- public long reload() {
- boolean changed = false;
- for (int i = 0, n = mSets.length; i < n; ++i) {
- long version = mSets[i].reload();
- if (version > mDataVersion) changed = true;
- }
- if (changed) mDataVersion = nextVersionNumber();
- return mDataVersion;
- }
-
- @Override
- public void onContentDirty() {
- notifyContentChanged();
- }
-
- @Override
- public Future<Integer> requestSync(SyncListener listener) {
- return requestSyncOnMultipleSets(mSets, listener);
- }
-}
diff --git a/src/com/android/gallery3d/data/ComboAlbumSet.java b/src/com/android/gallery3d/data/ComboAlbumSet.java
deleted file mode 100644
index 3f3674500..000000000
--- a/src/com/android/gallery3d/data/ComboAlbumSet.java
+++ /dev/null
@@ -1,96 +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.data;
-
-import com.android.gallery3d.R;
-import com.android.gallery3d.app.GalleryApp;
-import com.android.gallery3d.util.Future;
-
-// ComboAlbumSet combines multiple media sets into one. It lists all sub
-// media sets from the input album sets.
-// This only handles SubMediaSets, not MediaItems. (That's all we need now)
-public class ComboAlbumSet extends MediaSet implements ContentListener {
- @SuppressWarnings("unused")
- private static final String TAG = "ComboAlbumSet";
- private final MediaSet[] mSets;
- private final String mName;
-
- public ComboAlbumSet(Path path, GalleryApp application, MediaSet[] mediaSets) {
- super(path, nextVersionNumber());
- mSets = mediaSets;
- for (MediaSet set : mSets) {
- set.addContentListener(this);
- }
- mName = application.getResources().getString(
- R.string.set_label_all_albums);
- }
-
- @Override
- public MediaSet getSubMediaSet(int index) {
- for (MediaSet set : mSets) {
- int size = set.getSubMediaSetCount();
- if (index < size) {
- return set.getSubMediaSet(index);
- }
- index -= size;
- }
- return null;
- }
-
- @Override
- public int getSubMediaSetCount() {
- int count = 0;
- for (MediaSet set : mSets) {
- count += set.getSubMediaSetCount();
- }
- return count;
- }
-
- @Override
- public String getName() {
- return mName;
- }
-
- @Override
- public boolean isLoading() {
- for (int i = 0, n = mSets.length; i < n; ++i) {
- if (mSets[i].isLoading()) return true;
- }
- return false;
- }
-
- @Override
- public long reload() {
- boolean changed = false;
- for (int i = 0, n = mSets.length; i < n; ++i) {
- long version = mSets[i].reload();
- if (version > mDataVersion) changed = true;
- }
- if (changed) mDataVersion = nextVersionNumber();
- return mDataVersion;
- }
-
- @Override
- public void onContentDirty() {
- notifyContentChanged();
- }
-
- @Override
- public Future<Integer> requestSync(SyncListener listener) {
- return requestSyncOnMultipleSets(mSets, listener);
- }
-}
diff --git a/src/com/android/gallery3d/data/ComboSource.java b/src/com/android/gallery3d/data/ComboSource.java
deleted file mode 100644
index 867d47e64..000000000
--- a/src/com/android/gallery3d/data/ComboSource.java
+++ /dev/null
@@ -1,55 +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.data;
-
-import com.android.gallery3d.app.GalleryApp;
-
-class ComboSource extends MediaSource {
- private static final int COMBO_ALBUMSET = 0;
- private static final int COMBO_ALBUM = 1;
- private GalleryApp mApplication;
- private PathMatcher mMatcher;
-
- public ComboSource(GalleryApp application) {
- super("combo");
- mApplication = application;
- mMatcher = new PathMatcher();
- mMatcher.add("/combo/*", COMBO_ALBUMSET);
- mMatcher.add("/combo/*/*", COMBO_ALBUM);
- }
-
- // The only path we accept is "/combo/{set1, set2, ...} and /combo/item/{set1, set2, ...}"
- @Override
- public MediaObject createMediaObject(Path path) {
- String[] segments = path.split();
- if (segments.length < 2) {
- throw new RuntimeException("bad path: " + path);
- }
-
- DataManager dataManager = mApplication.getDataManager();
- switch (mMatcher.match(path)) {
- case COMBO_ALBUMSET:
- return new ComboAlbumSet(path, mApplication,
- dataManager.getMediaSetsFromString(segments[1]));
-
- case COMBO_ALBUM:
- return new ComboAlbum(path,
- dataManager.getMediaSetsFromString(segments[2]), segments[1]);
- }
- return null;
- }
-}
diff --git a/src/com/android/gallery3d/data/ContentListener.java b/src/com/android/gallery3d/data/ContentListener.java
deleted file mode 100644
index 5e2952685..000000000
--- a/src/com/android/gallery3d/data/ContentListener.java
+++ /dev/null
@@ -1,21 +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.data;
-
-public interface ContentListener {
- public void onContentDirty();
-} \ No newline at end of file
diff --git a/src/com/android/gallery3d/data/DataManager.java b/src/com/android/gallery3d/data/DataManager.java
deleted file mode 100644
index 38865e9f1..000000000
--- a/src/com/android/gallery3d/data/DataManager.java
+++ /dev/null
@@ -1,371 +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.data;
-
-import android.content.Context;
-import android.database.ContentObserver;
-import android.net.Uri;
-import android.os.Handler;
-
-import com.android.gallery3d.app.GalleryApp;
-import com.android.gallery3d.app.StitchingChangeListener;
-import com.android.gallery3d.common.Utils;
-import com.android.gallery3d.data.MediaObject.PanoramaSupportCallback;
-import com.android.gallery3d.data.MediaSet.ItemConsumer;
-import com.android.gallery3d.data.MediaSource.PathId;
-import com.android.gallery3d.picasasource.PicasaSource;
-
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.Map.Entry;
-import java.util.WeakHashMap;
-
-// DataManager manages all media sets and media items in the system.
-//
-// Each MediaSet and MediaItem has a unique 64 bits id. The most significant
-// 32 bits represents its parent, and the least significant 32 bits represents
-// the self id. For MediaSet the self id is is globally unique, but for
-// MediaItem it's unique only relative to its parent.
-//
-// To make sure the id is the same when the MediaSet is re-created, a child key
-// is provided to obtainSetId() to make sure the same self id will be used as
-// when the parent and key are the same. A sequence of child keys is called a
-// path. And it's used to identify a specific media set even if the process is
-// killed and re-created, so child keys should be stable identifiers.
-
-public class DataManager implements StitchingChangeListener {
- public static final int INCLUDE_IMAGE = 1;
- public static final int INCLUDE_VIDEO = 2;
- public static final int INCLUDE_ALL = INCLUDE_IMAGE | INCLUDE_VIDEO;
- public static final int INCLUDE_LOCAL_ONLY = 4;
- public static final int INCLUDE_LOCAL_IMAGE_ONLY =
- INCLUDE_LOCAL_ONLY | INCLUDE_IMAGE;
- public static final int INCLUDE_LOCAL_VIDEO_ONLY =
- INCLUDE_LOCAL_ONLY | INCLUDE_VIDEO;
- public static final int INCLUDE_LOCAL_ALL_ONLY =
- INCLUDE_LOCAL_ONLY | INCLUDE_IMAGE | INCLUDE_VIDEO;
-
- // Any one who would like to access data should require this lock
- // to prevent concurrency issue.
- public static final Object LOCK = new Object();
-
- public static DataManager from(Context context) {
- GalleryApp app = (GalleryApp) context.getApplicationContext();
- return app.getDataManager();
- }
-
- private static final String TAG = "DataManager";
-
- // This is the path for the media set seen by the user at top level.
- private static final String TOP_SET_PATH = "/combo/{/local/all,/picasa/all}";
-
- private static final String TOP_IMAGE_SET_PATH = "/combo/{/local/image,/picasa/image}";
-
- private static final String TOP_VIDEO_SET_PATH =
- "/combo/{/local/video,/picasa/video}";
-
- private static final String TOP_LOCAL_SET_PATH = "/local/all";
-
- private static final String TOP_LOCAL_IMAGE_SET_PATH = "/local/image";
-
- private static final String TOP_LOCAL_VIDEO_SET_PATH = "/local/video";
-
- public static final Comparator<MediaItem> sDateTakenComparator =
- new DateTakenComparator();
-
- private static class DateTakenComparator implements Comparator<MediaItem> {
- @Override
- public int compare(MediaItem item1, MediaItem item2) {
- return -Utils.compare(item1.getDateInMs(), item2.getDateInMs());
- }
- }
-
- private final Handler mDefaultMainHandler;
-
- private GalleryApp mApplication;
- private int mActiveCount = 0;
-
- private HashMap<Uri, NotifyBroker> mNotifierMap =
- new HashMap<Uri, NotifyBroker>();
-
-
- private HashMap<String, MediaSource> mSourceMap =
- new LinkedHashMap<String, MediaSource>();
-
- public DataManager(GalleryApp application) {
- mApplication = application;
- mDefaultMainHandler = new Handler(application.getMainLooper());
- }
-
- public synchronized void initializeSourceMap() {
- if (!mSourceMap.isEmpty()) return;
-
- // the order matters, the UriSource must come last
- addSource(new LocalSource(mApplication));
- addSource(new PicasaSource(mApplication));
- addSource(new ComboSource(mApplication));
- addSource(new ClusterSource(mApplication));
- addSource(new FilterSource(mApplication));
- addSource(new SecureSource(mApplication));
- addSource(new UriSource(mApplication));
- addSource(new SnailSource(mApplication));
-
- if (mActiveCount > 0) {
- for (MediaSource source : mSourceMap.values()) {
- source.resume();
- }
- }
- }
-
- public String getTopSetPath(int typeBits) {
-
- switch (typeBits) {
- case INCLUDE_IMAGE: return TOP_IMAGE_SET_PATH;
- case INCLUDE_VIDEO: return TOP_VIDEO_SET_PATH;
- case INCLUDE_ALL: return TOP_SET_PATH;
- case INCLUDE_LOCAL_IMAGE_ONLY: return TOP_LOCAL_IMAGE_SET_PATH;
- case INCLUDE_LOCAL_VIDEO_ONLY: return TOP_LOCAL_VIDEO_SET_PATH;
- case INCLUDE_LOCAL_ALL_ONLY: return TOP_LOCAL_SET_PATH;
- default: throw new IllegalArgumentException();
- }
- }
-
- // open for debug
- void addSource(MediaSource source) {
- if (source == null) return;
- mSourceMap.put(source.getPrefix(), source);
- }
-
- // A common usage of this method is:
- // synchronized (DataManager.LOCK) {
- // MediaObject object = peekMediaObject(path);
- // if (object == null) {
- // object = createMediaObject(...);
- // }
- // }
- public MediaObject peekMediaObject(Path path) {
- return path.getObject();
- }
-
- public MediaObject getMediaObject(Path path) {
- synchronized (LOCK) {
- MediaObject obj = path.getObject();
- if (obj != null) return obj;
-
- MediaSource source = mSourceMap.get(path.getPrefix());
- if (source == null) {
- Log.w(TAG, "cannot find media source for path: " + path);
- return null;
- }
-
- try {
- MediaObject object = source.createMediaObject(path);
- if (object == null) {
- Log.w(TAG, "cannot create media object: " + path);
- }
- return object;
- } catch (Throwable t) {
- Log.w(TAG, "exception in creating media object: " + path, t);
- return null;
- }
- }
- }
-
- public MediaObject getMediaObject(String s) {
- return getMediaObject(Path.fromString(s));
- }
-
- public MediaSet getMediaSet(Path path) {
- return (MediaSet) getMediaObject(path);
- }
-
- public MediaSet getMediaSet(String s) {
- return (MediaSet) getMediaObject(s);
- }
-
- public MediaSet[] getMediaSetsFromString(String segment) {
- String[] seq = Path.splitSequence(segment);
- int n = seq.length;
- MediaSet[] sets = new MediaSet[n];
- for (int i = 0; i < n; i++) {
- sets[i] = getMediaSet(seq[i]);
- }
- return sets;
- }
-
- // Maps a list of Paths to MediaItems, and invoke consumer.consume()
- // for each MediaItem (may not be in the same order as the input list).
- // An index number is also passed to consumer.consume() to identify
- // the original position in the input list of the corresponding Path (plus
- // startIndex).
- public void mapMediaItems(ArrayList<Path> list, ItemConsumer consumer,
- int startIndex) {
- HashMap<String, ArrayList<PathId>> map =
- new HashMap<String, ArrayList<PathId>>();
-
- // Group the path by the prefix.
- int n = list.size();
- for (int i = 0; i < n; i++) {
- Path path = list.get(i);
- String prefix = path.getPrefix();
- ArrayList<PathId> group = map.get(prefix);
- if (group == null) {
- group = new ArrayList<PathId>();
- map.put(prefix, group);
- }
- group.add(new PathId(path, i + startIndex));
- }
-
- // For each group, ask the corresponding media source to map it.
- for (Entry<String, ArrayList<PathId>> entry : map.entrySet()) {
- String prefix = entry.getKey();
- MediaSource source = mSourceMap.get(prefix);
- source.mapMediaItems(entry.getValue(), consumer);
- }
- }
-
- // The following methods forward the request to the proper object.
- public int getSupportedOperations(Path path) {
- return getMediaObject(path).getSupportedOperations();
- }
-
- public void getPanoramaSupport(Path path, PanoramaSupportCallback callback) {
- getMediaObject(path).getPanoramaSupport(callback);
- }
-
- public void delete(Path path) {
- getMediaObject(path).delete();
- }
-
- public void rotate(Path path, int degrees) {
- getMediaObject(path).rotate(degrees);
- }
-
- public Uri getContentUri(Path path) {
- return getMediaObject(path).getContentUri();
- }
-
- public int getMediaType(Path path) {
- return getMediaObject(path).getMediaType();
- }
-
- public Path findPathByUri(Uri uri, String type) {
- if (uri == null) return null;
- for (MediaSource source : mSourceMap.values()) {
- Path path = source.findPathByUri(uri, type);
- if (path != null) return path;
- }
- return null;
- }
-
- public Path getDefaultSetOf(Path item) {
- MediaSource source = mSourceMap.get(item.getPrefix());
- return source == null ? null : source.getDefaultSetOf(item);
- }
-
- // Returns number of bytes used by cached pictures currently downloaded.
- public long getTotalUsedCacheSize() {
- long sum = 0;
- for (MediaSource source : mSourceMap.values()) {
- sum += source.getTotalUsedCacheSize();
- }
- return sum;
- }
-
- // Returns number of bytes used by cached pictures if all pending
- // downloads and removals are completed.
- public long getTotalTargetCacheSize() {
- long sum = 0;
- for (MediaSource source : mSourceMap.values()) {
- sum += source.getTotalTargetCacheSize();
- }
- return sum;
- }
-
- public void registerChangeNotifier(Uri uri, ChangeNotifier notifier) {
- NotifyBroker broker = null;
- synchronized (mNotifierMap) {
- broker = mNotifierMap.get(uri);
- if (broker == null) {
- broker = new NotifyBroker(mDefaultMainHandler);
- mApplication.getContentResolver()
- .registerContentObserver(uri, true, broker);
- mNotifierMap.put(uri, broker);
- }
- }
- broker.registerNotifier(notifier);
- }
-
- public void resume() {
- if (++mActiveCount == 1) {
- for (MediaSource source : mSourceMap.values()) {
- source.resume();
- }
- }
- }
-
- public void pause() {
- if (--mActiveCount == 0) {
- for (MediaSource source : mSourceMap.values()) {
- source.pause();
- }
- }
- }
-
- private static class NotifyBroker extends ContentObserver {
- private WeakHashMap<ChangeNotifier, Object> mNotifiers =
- new WeakHashMap<ChangeNotifier, Object>();
-
- public NotifyBroker(Handler handler) {
- super(handler);
- }
-
- public synchronized void registerNotifier(ChangeNotifier notifier) {
- mNotifiers.put(notifier, null);
- }
-
- @Override
- public synchronized void onChange(boolean selfChange) {
- for(ChangeNotifier notifier : mNotifiers.keySet()) {
- notifier.onChange(selfChange);
- }
- }
- }
-
- @Override
- public void onStitchingQueued(Uri uri) {
- // Do nothing.
- }
-
- @Override
- public void onStitchingResult(Uri uri) {
- Path path = findPathByUri(uri, null);
- if (path != null) {
- MediaObject mediaObject = getMediaObject(path);
- if (mediaObject != null) {
- mediaObject.clearCachedPanoramaSupport();
- }
- }
- }
-
- @Override
- public void onStitchingProgress(Uri uri, int progress) {
- // Do nothing.
- }
-}
diff --git a/src/com/android/gallery3d/data/DataSourceType.java b/src/com/android/gallery3d/data/DataSourceType.java
deleted file mode 100644
index ab534d0c3..000000000
--- a/src/com/android/gallery3d/data/DataSourceType.java
+++ /dev/null
@@ -1,45 +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.data;
-
-import com.android.gallery3d.util.MediaSetUtils;
-
-public final class DataSourceType {
- public static final int TYPE_NOT_CATEGORIZED = 0;
- public static final int TYPE_LOCAL = 1;
- public static final int TYPE_PICASA = 2;
- public static final int TYPE_CAMERA = 3;
-
- private static final Path PICASA_ROOT = Path.fromString("/picasa");
- private static final Path LOCAL_ROOT = Path.fromString("/local");
-
- public static int identifySourceType(MediaSet set) {
- if (set == null) {
- return TYPE_NOT_CATEGORIZED;
- }
-
- Path path = set.getPath();
- if (MediaSetUtils.isCameraSource(path)) return TYPE_CAMERA;
-
- Path prefix = path.getPrefixPath();
-
- if (prefix == PICASA_ROOT) return TYPE_PICASA;
- if (prefix == LOCAL_ROOT) return TYPE_LOCAL;
-
- return TYPE_NOT_CATEGORIZED;
- }
-}
diff --git a/src/com/android/gallery3d/data/DecodeUtils.java b/src/com/android/gallery3d/data/DecodeUtils.java
deleted file mode 100644
index fa709157d..000000000
--- a/src/com/android/gallery3d/data/DecodeUtils.java
+++ /dev/null
@@ -1,312 +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.data;
-
-import android.annotation.TargetApi;
-import android.graphics.Bitmap;
-import android.graphics.Bitmap.Config;
-import android.graphics.BitmapFactory;
-import android.graphics.BitmapFactory.Options;
-import android.graphics.BitmapRegionDecoder;
-import android.os.Build;
-import android.util.FloatMath;
-
-import com.android.gallery3d.common.ApiHelper;
-import com.android.gallery3d.common.BitmapUtils;
-import com.android.gallery3d.common.Utils;
-import com.android.photos.data.GalleryBitmapPool;
-import com.android.gallery3d.ui.Log;
-import com.android.gallery3d.util.ThreadPool.CancelListener;
-import com.android.gallery3d.util.ThreadPool.JobContext;
-
-import java.io.FileDescriptor;
-import java.io.FileInputStream;
-import java.io.InputStream;
-
-public class DecodeUtils {
- private static final String TAG = "DecodeUtils";
-
- private static class DecodeCanceller implements CancelListener {
- Options mOptions;
-
- public DecodeCanceller(Options options) {
- mOptions = options;
- }
-
- @Override
- public void onCancel() {
- mOptions.requestCancelDecode();
- }
- }
-
- @TargetApi(ApiHelper.VERSION_CODES.HONEYCOMB)
- public static void setOptionsMutable(Options options) {
- if (ApiHelper.HAS_OPTIONS_IN_MUTABLE) options.inMutable = true;
- }
-
- public static Bitmap decode(JobContext jc, FileDescriptor fd, Options options) {
- if (options == null) options = new Options();
- jc.setCancelListener(new DecodeCanceller(options));
- setOptionsMutable(options);
- return ensureGLCompatibleBitmap(
- BitmapFactory.decodeFileDescriptor(fd, null, options));
- }
-
- public static void decodeBounds(JobContext jc, FileDescriptor fd,
- Options options) {
- Utils.assertTrue(options != null);
- options.inJustDecodeBounds = true;
- jc.setCancelListener(new DecodeCanceller(options));
- BitmapFactory.decodeFileDescriptor(fd, null, options);
- options.inJustDecodeBounds = false;
- }
-
- public static Bitmap decode(JobContext jc, byte[] bytes, Options options) {
- return decode(jc, bytes, 0, bytes.length, options);
- }
-
- public static Bitmap decode(JobContext jc, byte[] bytes, int offset,
- int length, Options options) {
- if (options == null) options = new Options();
- jc.setCancelListener(new DecodeCanceller(options));
- setOptionsMutable(options);
- return ensureGLCompatibleBitmap(
- BitmapFactory.decodeByteArray(bytes, offset, length, options));
- }
-
- public static void decodeBounds(JobContext jc, byte[] bytes, int offset,
- int length, Options options) {
- Utils.assertTrue(options != null);
- options.inJustDecodeBounds = true;
- jc.setCancelListener(new DecodeCanceller(options));
- BitmapFactory.decodeByteArray(bytes, offset, length, options);
- options.inJustDecodeBounds = false;
- }
-
- public static Bitmap decodeThumbnail(
- JobContext jc, String filePath, Options options, int targetSize, int type) {
- FileInputStream fis = null;
- try {
- fis = new FileInputStream(filePath);
- FileDescriptor fd = fis.getFD();
- return decodeThumbnail(jc, fd, options, targetSize, type);
- } catch (Exception ex) {
- Log.w(TAG, ex);
- return null;
- } finally {
- Utils.closeSilently(fis);
- }
- }
-
- public static Bitmap decodeThumbnail(
- JobContext jc, FileDescriptor fd, Options options, int targetSize, int type) {
- if (options == null) options = new Options();
- jc.setCancelListener(new DecodeCanceller(options));
-
- options.inJustDecodeBounds = true;
- BitmapFactory.decodeFileDescriptor(fd, null, options);
- if (jc.isCancelled()) return null;
-
- int w = options.outWidth;
- int h = options.outHeight;
-
- if (type == MediaItem.TYPE_MICROTHUMBNAIL) {
- // We center-crop the original image as it's micro thumbnail. In this case,
- // we want to make sure the shorter side >= "targetSize".
- float scale = (float) targetSize / Math.min(w, h);
- options.inSampleSize = BitmapUtils.computeSampleSizeLarger(scale);
-
- // For an extremely wide image, e.g. 300x30000, we may got OOM when decoding
- // it for TYPE_MICROTHUMBNAIL. So we add a max number of pixels limit here.
- final int MAX_PIXEL_COUNT = 640000; // 400 x 1600
- if ((w / options.inSampleSize) * (h / options.inSampleSize) > MAX_PIXEL_COUNT) {
- options.inSampleSize = BitmapUtils.computeSampleSize(
- FloatMath.sqrt((float) MAX_PIXEL_COUNT / (w * h)));
- }
- } else {
- // For screen nail, we only want to keep the longer side >= targetSize.
- float scale = (float) targetSize / Math.max(w, h);
- options.inSampleSize = BitmapUtils.computeSampleSizeLarger(scale);
- }
-
- options.inJustDecodeBounds = false;
- setOptionsMutable(options);
-
- Bitmap result = BitmapFactory.decodeFileDescriptor(fd, null, options);
- if (result == null) return null;
-
- // We need to resize down if the decoder does not support inSampleSize
- // (For example, GIF images)
- float scale = (float) targetSize / (type == MediaItem.TYPE_MICROTHUMBNAIL
- ? Math.min(result.getWidth(), result.getHeight())
- : Math.max(result.getWidth(), result.getHeight()));
-
- if (scale <= 0.5) result = BitmapUtils.resizeBitmapByScale(result, scale, true);
- return ensureGLCompatibleBitmap(result);
- }
-
- /**
- * Decodes the bitmap from the given byte array if the image size is larger than the given
- * requirement.
- *
- * Note: The returned image may be resized down. However, both width and height must be
- * larger than the <code>targetSize</code>.
- */
- public static Bitmap decodeIfBigEnough(JobContext jc, byte[] data,
- Options options, int targetSize) {
- if (options == null) options = new Options();
- jc.setCancelListener(new DecodeCanceller(options));
-
- options.inJustDecodeBounds = true;
- BitmapFactory.decodeByteArray(data, 0, data.length, options);
- if (jc.isCancelled()) return null;
- if (options.outWidth < targetSize || options.outHeight < targetSize) {
- return null;
- }
- options.inSampleSize = BitmapUtils.computeSampleSizeLarger(
- options.outWidth, options.outHeight, targetSize);
- options.inJustDecodeBounds = false;
- setOptionsMutable(options);
-
- return ensureGLCompatibleBitmap(
- BitmapFactory.decodeByteArray(data, 0, data.length, options));
- }
-
- // TODO: This function should not be called directly from
- // DecodeUtils.requestDecode(...), since we don't have the knowledge
- // if the bitmap will be uploaded to GL.
- public static Bitmap ensureGLCompatibleBitmap(Bitmap bitmap) {
- if (bitmap == null || bitmap.getConfig() != null) return bitmap;
- Bitmap newBitmap = bitmap.copy(Config.ARGB_8888, false);
- bitmap.recycle();
- return newBitmap;
- }
-
- public static BitmapRegionDecoder createBitmapRegionDecoder(
- JobContext jc, byte[] bytes, int offset, int length,
- boolean shareable) {
- if (offset < 0 || length <= 0 || offset + length > bytes.length) {
- throw new IllegalArgumentException(String.format(
- "offset = %s, length = %s, bytes = %s",
- offset, length, bytes.length));
- }
-
- try {
- return BitmapRegionDecoder.newInstance(
- bytes, offset, length, shareable);
- } catch (Throwable t) {
- Log.w(TAG, t);
- return null;
- }
- }
-
- public static BitmapRegionDecoder createBitmapRegionDecoder(
- JobContext jc, String filePath, boolean shareable) {
- try {
- return BitmapRegionDecoder.newInstance(filePath, shareable);
- } catch (Throwable t) {
- Log.w(TAG, t);
- return null;
- }
- }
-
- public static BitmapRegionDecoder createBitmapRegionDecoder(
- JobContext jc, FileDescriptor fd, boolean shareable) {
- try {
- return BitmapRegionDecoder.newInstance(fd, shareable);
- } catch (Throwable t) {
- Log.w(TAG, t);
- return null;
- }
- }
-
- public static BitmapRegionDecoder createBitmapRegionDecoder(
- JobContext jc, InputStream is, boolean shareable) {
- try {
- return BitmapRegionDecoder.newInstance(is, shareable);
- } catch (Throwable t) {
- // We often cancel the creating of bitmap region decoder,
- // so just log one line.
- Log.w(TAG, "requestCreateBitmapRegionDecoder: " + t);
- return null;
- }
- }
-
- @TargetApi(Build.VERSION_CODES.HONEYCOMB)
- public static Bitmap decodeUsingPool(JobContext jc, byte[] data, int offset,
- int length, BitmapFactory.Options options) {
- if (options == null) options = new BitmapFactory.Options();
- if (options.inSampleSize < 1) options.inSampleSize = 1;
- options.inPreferredConfig = Bitmap.Config.ARGB_8888;
- options.inBitmap = (options.inSampleSize == 1)
- ? findCachedBitmap(jc, data, offset, length, options) : null;
- try {
- Bitmap bitmap = decode(jc, data, offset, length, options);
- if (options.inBitmap != null && options.inBitmap != bitmap) {
- GalleryBitmapPool.getInstance().put(options.inBitmap);
- options.inBitmap = null;
- }
- return bitmap;
- } catch (IllegalArgumentException e) {
- if (options.inBitmap == null) throw e;
-
- Log.w(TAG, "decode fail with a given bitmap, try decode to a new bitmap");
- GalleryBitmapPool.getInstance().put(options.inBitmap);
- options.inBitmap = null;
- return decode(jc, data, offset, length, options);
- }
- }
-
- // This is the same as the method above except the source data comes
- // from a file descriptor instead of a byte array.
- @TargetApi(Build.VERSION_CODES.HONEYCOMB)
- public static Bitmap decodeUsingPool(JobContext jc,
- FileDescriptor fileDescriptor, Options options) {
- if (options == null) options = new BitmapFactory.Options();
- if (options.inSampleSize < 1) options.inSampleSize = 1;
- options.inPreferredConfig = Bitmap.Config.ARGB_8888;
- options.inBitmap = (options.inSampleSize == 1)
- ? findCachedBitmap(jc, fileDescriptor, options) : null;
- try {
- Bitmap bitmap = DecodeUtils.decode(jc, fileDescriptor, options);
- if (options.inBitmap != null && options.inBitmap != bitmap) {
- GalleryBitmapPool.getInstance().put(options.inBitmap);
- options.inBitmap = null;
- }
- return bitmap;
- } catch (IllegalArgumentException e) {
- if (options.inBitmap == null) throw e;
-
- Log.w(TAG, "decode fail with a given bitmap, try decode to a new bitmap");
- GalleryBitmapPool.getInstance().put(options.inBitmap);
- options.inBitmap = null;
- return decode(jc, fileDescriptor, options);
- }
- }
-
- private static Bitmap findCachedBitmap(JobContext jc, byte[] data,
- int offset, int length, Options options) {
- decodeBounds(jc, data, offset, length, options);
- return GalleryBitmapPool.getInstance().get(options.outWidth, options.outHeight);
- }
-
- private static Bitmap findCachedBitmap(JobContext jc, FileDescriptor fileDescriptor,
- Options options) {
- decodeBounds(jc, fileDescriptor, options);
- return GalleryBitmapPool.getInstance().get(options.outWidth, options.outHeight);
- }
-}
diff --git a/src/com/android/gallery3d/data/DownloadCache.java b/src/com/android/gallery3d/data/DownloadCache.java
deleted file mode 100644
index be7820b01..000000000
--- a/src/com/android/gallery3d/data/DownloadCache.java
+++ /dev/null
@@ -1,370 +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.data;
-
-import android.content.ContentValues;
-import android.content.Context;
-import android.database.Cursor;
-import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteOpenHelper;
-
-import com.android.gallery3d.app.GalleryApp;
-import com.android.gallery3d.common.LruCache;
-import com.android.gallery3d.common.Utils;
-import com.android.gallery3d.data.DownloadEntry.Columns;
-import com.android.gallery3d.util.Future;
-import com.android.gallery3d.util.FutureListener;
-import com.android.gallery3d.util.ThreadPool;
-import com.android.gallery3d.util.ThreadPool.CancelListener;
-import com.android.gallery3d.util.ThreadPool.Job;
-import com.android.gallery3d.util.ThreadPool.JobContext;
-
-import java.io.File;
-import java.net.URL;
-import java.util.HashMap;
-import java.util.HashSet;
-
-public class DownloadCache {
- private static final String TAG = "DownloadCache";
- private static final int MAX_DELETE_COUNT = 16;
- private static final int LRU_CAPACITY = 4;
-
- private static final String TABLE_NAME = DownloadEntry.SCHEMA.getTableName();
-
- private static final String QUERY_PROJECTION[] = {Columns.ID, Columns.DATA};
- private static final String WHERE_HASH_AND_URL = String.format(
- "%s = ? AND %s = ?", Columns.HASH_CODE, Columns.CONTENT_URL);
- private static final int QUERY_INDEX_ID = 0;
- private static final int QUERY_INDEX_DATA = 1;
-
- private static final String FREESPACE_PROJECTION[] = {
- Columns.ID, Columns.DATA, Columns.CONTENT_URL, Columns.CONTENT_SIZE};
- private static final String FREESPACE_ORDER_BY =
- String.format("%s ASC", Columns.LAST_ACCESS);
- private static final int FREESPACE_IDNEX_ID = 0;
- private static final int FREESPACE_IDNEX_DATA = 1;
- private static final int FREESPACE_INDEX_CONTENT_URL = 2;
- private static final int FREESPACE_INDEX_CONTENT_SIZE = 3;
-
- private static final String ID_WHERE = Columns.ID + " = ?";
-
- private static final String SUM_PROJECTION[] =
- {String.format("sum(%s)", Columns.CONTENT_SIZE)};
- private static final int SUM_INDEX_SUM = 0;
-
- private final LruCache<String, Entry> mEntryMap =
- new LruCache<String, Entry>(LRU_CAPACITY);
- private final HashMap<String, DownloadTask> mTaskMap =
- new HashMap<String, DownloadTask>();
- private final File mRoot;
- private final GalleryApp mApplication;
- private final SQLiteDatabase mDatabase;
- private final long mCapacity;
-
- private long mTotalBytes = 0;
- private boolean mInitialized = false;
-
- public DownloadCache(GalleryApp application, File root, long capacity) {
- mRoot = Utils.checkNotNull(root);
- mApplication = Utils.checkNotNull(application);
- mCapacity = capacity;
- mDatabase = new DatabaseHelper(application.getAndroidContext())
- .getWritableDatabase();
- }
-
- private Entry findEntryInDatabase(String stringUrl) {
- long hash = Utils.crc64Long(stringUrl);
- String whereArgs[] = {String.valueOf(hash), stringUrl};
- Cursor cursor = mDatabase.query(TABLE_NAME, QUERY_PROJECTION,
- WHERE_HASH_AND_URL, whereArgs, null, null, null);
- try {
- if (cursor.moveToNext()) {
- File file = new File(cursor.getString(QUERY_INDEX_DATA));
- long id = cursor.getInt(QUERY_INDEX_ID);
- Entry entry = null;
- synchronized (mEntryMap) {
- entry = mEntryMap.get(stringUrl);
- if (entry == null) {
- entry = new Entry(id, file);
- mEntryMap.put(stringUrl, entry);
- }
- }
- return entry;
- }
- } finally {
- cursor.close();
- }
- return null;
- }
-
- public Entry download(JobContext jc, URL url) {
- if (!mInitialized) initialize();
-
- String stringUrl = url.toString();
-
- // First find in the entry-pool
- synchronized (mEntryMap) {
- Entry entry = mEntryMap.get(stringUrl);
- if (entry != null) {
- updateLastAccess(entry.mId);
- return entry;
- }
- }
-
- // Then, find it in database
- TaskProxy proxy = new TaskProxy();
- synchronized (mTaskMap) {
- Entry entry = findEntryInDatabase(stringUrl);
- if (entry != null) {
- updateLastAccess(entry.mId);
- return entry;
- }
-
- // Finally, we need to download the file ....
- // First check if we are downloading it now ...
- DownloadTask task = mTaskMap.get(stringUrl);
- if (task == null) { // if not, start the download task now
- task = new DownloadTask(stringUrl);
- mTaskMap.put(stringUrl, task);
- task.mFuture = mApplication.getThreadPool().submit(task, task);
- }
- task.addProxy(proxy);
- }
-
- return proxy.get(jc);
- }
-
- private void updateLastAccess(long id) {
- ContentValues values = new ContentValues();
- values.put(Columns.LAST_ACCESS, System.currentTimeMillis());
- mDatabase.update(TABLE_NAME, values,
- ID_WHERE, new String[] {String.valueOf(id)});
- }
-
- private synchronized void freeSomeSpaceIfNeed(int maxDeleteFileCount) {
- if (mTotalBytes <= mCapacity) return;
- Cursor cursor = mDatabase.query(TABLE_NAME,
- FREESPACE_PROJECTION, null, null, null, null, FREESPACE_ORDER_BY);
- try {
- while (maxDeleteFileCount > 0
- && mTotalBytes > mCapacity && cursor.moveToNext()) {
- long id = cursor.getLong(FREESPACE_IDNEX_ID);
- String url = cursor.getString(FREESPACE_INDEX_CONTENT_URL);
- long size = cursor.getLong(FREESPACE_INDEX_CONTENT_SIZE);
- String path = cursor.getString(FREESPACE_IDNEX_DATA);
- boolean containsKey;
- synchronized (mEntryMap) {
- containsKey = mEntryMap.containsKey(url);
- }
- if (!containsKey) {
- --maxDeleteFileCount;
- mTotalBytes -= size;
- new File(path).delete();
- mDatabase.delete(TABLE_NAME,
- ID_WHERE, new String[]{String.valueOf(id)});
- } else {
- // skip delete, since it is being used
- }
- }
- } finally {
- cursor.close();
- }
- }
-
- private synchronized long insertEntry(String url, File file) {
- long size = file.length();
- mTotalBytes += size;
-
- ContentValues values = new ContentValues();
- String hashCode = String.valueOf(Utils.crc64Long(url));
- values.put(Columns.DATA, file.getAbsolutePath());
- values.put(Columns.HASH_CODE, hashCode);
- values.put(Columns.CONTENT_URL, url);
- values.put(Columns.CONTENT_SIZE, size);
- values.put(Columns.LAST_UPDATED, System.currentTimeMillis());
- return mDatabase.insert(TABLE_NAME, "", values);
- }
-
- private synchronized void initialize() {
- if (mInitialized) return;
- mInitialized = true;
- if (!mRoot.isDirectory()) mRoot.mkdirs();
- if (!mRoot.isDirectory()) {
- throw new RuntimeException("cannot create " + mRoot.getAbsolutePath());
- }
-
- Cursor cursor = mDatabase.query(
- TABLE_NAME, SUM_PROJECTION, null, null, null, null, null);
- mTotalBytes = 0;
- try {
- if (cursor.moveToNext()) {
- mTotalBytes = cursor.getLong(SUM_INDEX_SUM);
- }
- } finally {
- cursor.close();
- }
- if (mTotalBytes > mCapacity) freeSomeSpaceIfNeed(MAX_DELETE_COUNT);
- }
-
- private final class DatabaseHelper extends SQLiteOpenHelper {
- public static final String DATABASE_NAME = "download.db";
- public static final int DATABASE_VERSION = 2;
-
- public DatabaseHelper(Context context) {
- super(context, DATABASE_NAME, null, DATABASE_VERSION);
- }
-
- @Override
- public void onCreate(SQLiteDatabase db) {
- DownloadEntry.SCHEMA.createTables(db);
- // Delete old files
- for (File file : mRoot.listFiles()) {
- if (!file.delete()) {
- Log.w(TAG, "fail to remove: " + file.getAbsolutePath());
- }
- }
- }
-
- @Override
- public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
- //reset everything
- DownloadEntry.SCHEMA.dropTables(db);
- onCreate(db);
- }
- }
-
- public class Entry {
- public File cacheFile;
- protected long mId;
-
- Entry(long id, File cacheFile) {
- mId = id;
- this.cacheFile = Utils.checkNotNull(cacheFile);
- }
- }
-
- private class DownloadTask implements Job<File>, FutureListener<File> {
- private HashSet<TaskProxy> mProxySet = new HashSet<TaskProxy>();
- private Future<File> mFuture;
- private final String mUrl;
-
- public DownloadTask(String url) {
- mUrl = Utils.checkNotNull(url);
- }
-
- public void removeProxy(TaskProxy proxy) {
- synchronized (mTaskMap) {
- Utils.assertTrue(mProxySet.remove(proxy));
- if (mProxySet.isEmpty()) {
- mFuture.cancel();
- mTaskMap.remove(mUrl);
- }
- }
- }
-
- // should be used in synchronized block of mDatabase
- public void addProxy(TaskProxy proxy) {
- proxy.mTask = this;
- mProxySet.add(proxy);
- }
-
- @Override
- public void onFutureDone(Future<File> future) {
- File file = future.get();
- long id = 0;
- if (file != null) { // insert to database
- id = insertEntry(mUrl, file);
- }
-
- if (future.isCancelled()) {
- Utils.assertTrue(mProxySet.isEmpty());
- return;
- }
-
- synchronized (mTaskMap) {
- Entry entry = null;
- synchronized (mEntryMap) {
- if (file != null) {
- entry = new Entry(id, file);
- Utils.assertTrue(mEntryMap.put(mUrl, entry) == null);
- }
- }
- for (TaskProxy proxy : mProxySet) {
- proxy.setResult(entry);
- }
- mTaskMap.remove(mUrl);
- freeSomeSpaceIfNeed(MAX_DELETE_COUNT);
- }
- }
-
- @Override
- public File run(JobContext jc) {
- // TODO: utilize etag
- jc.setMode(ThreadPool.MODE_NETWORK);
- File tempFile = null;
- try {
- URL url = new URL(mUrl);
- tempFile = File.createTempFile("cache", ".tmp", mRoot);
- // download from url to tempFile
- jc.setMode(ThreadPool.MODE_NETWORK);
- boolean downloaded = DownloadUtils.requestDownload(jc, url, tempFile);
- jc.setMode(ThreadPool.MODE_NONE);
- if (downloaded) return tempFile;
- } catch (Exception e) {
- Log.e(TAG, String.format("fail to download %s", mUrl), e);
- } finally {
- jc.setMode(ThreadPool.MODE_NONE);
- }
- if (tempFile != null) tempFile.delete();
- return null;
- }
- }
-
- public static class TaskProxy {
- private DownloadTask mTask;
- private boolean mIsCancelled = false;
- private Entry mEntry;
-
- synchronized void setResult(Entry entry) {
- if (mIsCancelled) return;
- mEntry = entry;
- notifyAll();
- }
-
- public synchronized Entry get(JobContext jc) {
- jc.setCancelListener(new CancelListener() {
- @Override
- public void onCancel() {
- mTask.removeProxy(TaskProxy.this);
- synchronized (TaskProxy.this) {
- mIsCancelled = true;
- TaskProxy.this.notifyAll();
- }
- }
- });
- while (!mIsCancelled && mEntry == null) {
- try {
- wait();
- } catch (InterruptedException e) {
- Log.w(TAG, "ignore interrupt", e);
- }
- }
- jc.setCancelListener(null);
- return mEntry;
- }
- }
-}
diff --git a/src/com/android/gallery3d/data/DownloadEntry.java b/src/com/android/gallery3d/data/DownloadEntry.java
deleted file mode 100644
index 578523f73..000000000
--- a/src/com/android/gallery3d/data/DownloadEntry.java
+++ /dev/null
@@ -1,72 +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.data;
-
-import com.android.gallery3d.common.Entry;
-import com.android.gallery3d.common.EntrySchema;
-
-
-@Entry.Table("download")
-public class DownloadEntry extends Entry {
- public static final EntrySchema SCHEMA = new EntrySchema(DownloadEntry.class);
-
- public static interface Columns extends Entry.Columns {
- public static final String HASH_CODE = "hash_code";
- public static final String CONTENT_URL = "content_url";
- public static final String CONTENT_SIZE = "_size";
- public static final String ETAG = "etag";
- public static final String LAST_ACCESS = "last_access";
- public static final String LAST_UPDATED = "last_updated";
- public static final String DATA = "_data";
- }
-
- @Column(value = "hash_code", indexed = true)
- public long hashCode;
-
- @Column("content_url")
- public String contentUrl;
-
- @Column("_size")
- public long contentSize;
-
- @Column("etag")
- public String eTag;
-
- @Column(value = "last_access", indexed = true)
- public long lastAccessTime;
-
- @Column(value = "last_updated")
- public long lastUpdatedTime;
-
- @Column("_data")
- public String path;
-
- @Override
- public String toString() {
- // Note: THIS IS REQUIRED. We used all the fields here. Otherwise,
- // ProGuard will remove these UNUSED fields. However, these
- // fields are needed to generate database.
- return new StringBuilder()
- .append("hash_code: ").append(hashCode).append(", ")
- .append("content_url").append(contentUrl).append(", ")
- .append("_size").append(contentSize).append(", ")
- .append("etag").append(eTag).append(", ")
- .append("last_access").append(lastAccessTime).append(", ")
- .append("last_updated").append(lastUpdatedTime).append(",")
- .append("_data").append(path)
- .toString();
- }
-}
diff --git a/src/com/android/gallery3d/data/DownloadUtils.java b/src/com/android/gallery3d/data/DownloadUtils.java
deleted file mode 100644
index 137898e91..000000000
--- a/src/com/android/gallery3d/data/DownloadUtils.java
+++ /dev/null
@@ -1,79 +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.data;
-
-import com.android.gallery3d.common.Utils;
-import com.android.gallery3d.util.ThreadPool.CancelListener;
-import com.android.gallery3d.util.ThreadPool.JobContext;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InterruptedIOException;
-import java.io.OutputStream;
-import java.net.URL;
-
-public class DownloadUtils {
- private static final String TAG = "DownloadService";
-
- public static boolean requestDownload(JobContext jc, URL url, File file) {
- FileOutputStream fos = null;
- try {
- fos = new FileOutputStream(file);
- return download(jc, url, fos);
- } catch (Throwable t) {
- return false;
- } finally {
- Utils.closeSilently(fos);
- }
- }
-
- public static void dump(JobContext jc, InputStream is, OutputStream os)
- throws IOException {
- byte buffer[] = new byte[4096];
- int rc = is.read(buffer, 0, buffer.length);
- final Thread thread = Thread.currentThread();
- jc.setCancelListener(new CancelListener() {
- @Override
- public void onCancel() {
- thread.interrupt();
- }
- });
- while (rc > 0) {
- if (jc.isCancelled()) throw new InterruptedIOException();
- os.write(buffer, 0, rc);
- rc = is.read(buffer, 0, buffer.length);
- }
- jc.setCancelListener(null);
- Thread.interrupted(); // consume the interrupt signal
- }
-
- public static boolean download(JobContext jc, URL url, OutputStream output) {
- InputStream input = null;
- try {
- input = url.openStream();
- dump(jc, input, output);
- return true;
- } catch (Throwable t) {
- Log.w(TAG, "fail to download", t);
- return false;
- } finally {
- Utils.closeSilently(input);
- }
- }
-} \ No newline at end of file
diff --git a/src/com/android/gallery3d/data/EmptyAlbumImage.java b/src/com/android/gallery3d/data/EmptyAlbumImage.java
deleted file mode 100644
index 6f8c37c6b..000000000
--- a/src/com/android/gallery3d/data/EmptyAlbumImage.java
+++ /dev/null
@@ -1,34 +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.data;
-
-import com.android.gallery3d.R;
-import com.android.gallery3d.app.GalleryApp;
-
-public class EmptyAlbumImage extends ActionImage {
- @SuppressWarnings("unused")
- private static final String TAG = "EmptyAlbumImage";
-
- public EmptyAlbumImage(Path path, GalleryApp application) {
- super(path, application, R.drawable.placeholder_empty);
- }
-
- @Override
- public int getSupportedOperations() {
- return super.getSupportedOperations() | SUPPORT_BACK;
- }
-}
diff --git a/src/com/android/gallery3d/data/Exif.java b/src/com/android/gallery3d/data/Exif.java
deleted file mode 100644
index 950e7de18..000000000
--- a/src/com/android/gallery3d/data/Exif.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2011 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.data;
-
-import android.util.Log;
-
-import com.android.gallery3d.exif.ExifInterface;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-public class Exif {
- private static final String TAG = "CameraExif";
-
- // Returns the degrees in clockwise. Values are 0, 90, 180, or 270.
- public static int getOrientation(InputStream is) {
- if (is == null) {
- return 0;
- }
- ExifInterface exif = new ExifInterface();
- try {
- exif.readExif(is);
- Integer val = exif.getTagIntValue(ExifInterface.TAG_ORIENTATION);
- if (val == null) {
- return 0;
- } else {
- return ExifInterface.getRotationForOrientationValue(val.shortValue());
- }
- } catch (IOException e) {
- Log.w(TAG, "Failed to read EXIF orientation", e);
- return 0;
- }
- }
-}
diff --git a/src/com/android/gallery3d/data/Face.java b/src/com/android/gallery3d/data/Face.java
deleted file mode 100644
index d2dc22bfc..000000000
--- a/src/com/android/gallery3d/data/Face.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2011 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.data;
-
-import android.graphics.Rect;
-
-import com.android.gallery3d.common.Utils;
-
-import java.util.StringTokenizer;
-
-public class Face implements Comparable<Face> {
- private String mName;
- private String mPersonId;
- private Rect mPosition;
-
- public Face(String name, String personId, String rect) {
- mName = name;
- mPersonId = personId;
- Utils.assertTrue(mName != null && mPersonId != null && rect != null);
- StringTokenizer tokenizer = new StringTokenizer(rect);
- mPosition = new Rect();
- while (tokenizer.hasMoreElements()) {
- mPosition.left = Integer.parseInt(tokenizer.nextToken());
- mPosition.top = Integer.parseInt(tokenizer.nextToken());
- mPosition.right = Integer.parseInt(tokenizer.nextToken());
- mPosition.bottom = Integer.parseInt(tokenizer.nextToken());
- }
- }
-
- public Rect getPosition() {
- return mPosition;
- }
-
- public String getName() {
- return mName;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (obj instanceof Face) {
- Face face = (Face) obj;
- return mPersonId.equals(face.mPersonId);
- }
- return false;
- }
-
- @Override
- public int compareTo(Face another) {
- return mName.compareTo(another.mName);
- }
-}
diff --git a/src/com/android/gallery3d/data/FaceClustering.java b/src/com/android/gallery3d/data/FaceClustering.java
deleted file mode 100644
index 819915edb..000000000
--- a/src/com/android/gallery3d/data/FaceClustering.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright (C) 2011 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.data;
-
-import android.content.Context;
-import android.graphics.Rect;
-
-import com.android.gallery3d.R;
-import com.android.gallery3d.picasasource.PicasaSource;
-
-import java.util.ArrayList;
-import java.util.TreeMap;
-
-public class FaceClustering extends Clustering {
- @SuppressWarnings("unused")
- private static final String TAG = "FaceClustering";
-
- private FaceCluster[] mClusters;
- private String mUntaggedString;
- private Context mContext;
-
- private class FaceCluster {
- ArrayList<Path> mPaths = new ArrayList<Path>();
- String mName;
- MediaItem mCoverItem;
- Rect mCoverRegion;
- int mCoverFaceIndex;
-
- public FaceCluster(String name) {
- mName = name;
- }
-
- public void add(MediaItem item, int faceIndex) {
- Path path = item.getPath();
- mPaths.add(path);
- Face[] faces = item.getFaces();
- if (faces != null) {
- Face face = faces[faceIndex];
- if (mCoverItem == null) {
- mCoverItem = item;
- mCoverRegion = face.getPosition();
- mCoverFaceIndex = faceIndex;
- } else {
- Rect region = face.getPosition();
- if (mCoverRegion.width() < region.width() &&
- mCoverRegion.height() < region.height()) {
- mCoverItem = item;
- mCoverRegion = face.getPosition();
- mCoverFaceIndex = faceIndex;
- }
- }
- }
- }
-
- public int size() {
- return mPaths.size();
- }
-
- public MediaItem getCover() {
- if (mCoverItem != null) {
- if (PicasaSource.isPicasaImage(mCoverItem)) {
- return PicasaSource.getFaceItem(mContext, mCoverItem, mCoverFaceIndex);
- } else {
- return mCoverItem;
- }
- }
- return null;
- }
- }
-
- public FaceClustering(Context context) {
- mUntaggedString = context.getResources().getString(R.string.untagged);
- mContext = context;
- }
-
- @Override
- public void run(MediaSet baseSet) {
- final TreeMap<Face, FaceCluster> map =
- new TreeMap<Face, FaceCluster>();
- final FaceCluster untagged = new FaceCluster(mUntaggedString);
-
- baseSet.enumerateTotalMediaItems(new MediaSet.ItemConsumer() {
- @Override
- public void consume(int index, MediaItem item) {
- Face[] faces = item.getFaces();
- if (faces == null || faces.length == 0) {
- untagged.add(item, -1);
- return;
- }
- for (int j = 0; j < faces.length; j++) {
- Face face = faces[j];
- FaceCluster cluster = map.get(face);
- if (cluster == null) {
- cluster = new FaceCluster(face.getName());
- map.put(face, cluster);
- }
- cluster.add(item, j);
- }
- }
- });
-
- int m = map.size();
- mClusters = map.values().toArray(new FaceCluster[m + ((untagged.size() > 0) ? 1 : 0)]);
- if (untagged.size() > 0) {
- mClusters[m] = untagged;
- }
- }
-
- @Override
- public int getNumberOfClusters() {
- return mClusters.length;
- }
-
- @Override
- public ArrayList<Path> getCluster(int index) {
- return mClusters[index].mPaths;
- }
-
- @Override
- public String getClusterName(int index) {
- return mClusters[index].mName;
- }
-
- @Override
- public MediaItem getClusterCover(int index) {
- return mClusters[index].getCover();
- }
-}
diff --git a/src/com/android/gallery3d/data/FilterDeleteSet.java b/src/com/android/gallery3d/data/FilterDeleteSet.java
deleted file mode 100644
index c76412ff8..000000000
--- a/src/com/android/gallery3d/data/FilterDeleteSet.java
+++ /dev/null
@@ -1,256 +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.data;
-
-import java.util.ArrayList;
-
-// FilterDeleteSet filters a base MediaSet to remove some deletion items (we
-// expect the number to be small). The user can use the following methods to
-// add/remove deletion items:
-//
-// void addDeletion(Path path, int index);
-// void removeDelection(Path path);
-// void clearDeletion();
-// int getNumberOfDeletions();
-//
-public class FilterDeleteSet extends MediaSet implements ContentListener {
- @SuppressWarnings("unused")
- private static final String TAG = "FilterDeleteSet";
-
- private static final int REQUEST_ADD = 1;
- private static final int REQUEST_REMOVE = 2;
- private static final int REQUEST_CLEAR = 3;
-
- private static class Request {
- int type; // one of the REQUEST_* constants
- Path path;
- int indexHint;
- public Request(int type, Path path, int indexHint) {
- this.type = type;
- this.path = path;
- this.indexHint = indexHint;
- }
- }
-
- private static class Deletion {
- Path path;
- int index;
- public Deletion(Path path, int index) {
- this.path = path;
- this.index = index;
- }
- }
-
- // The underlying MediaSet
- private final MediaSet mBaseSet;
-
- // Pending Requests
- private ArrayList<Request> mRequests = new ArrayList<Request>();
-
- // Deletions currently in effect, ordered by index
- private ArrayList<Deletion> mCurrent = new ArrayList<Deletion>();
-
- public FilterDeleteSet(Path path, MediaSet baseSet) {
- super(path, INVALID_DATA_VERSION);
- mBaseSet = baseSet;
- mBaseSet.addContentListener(this);
- }
-
- @Override
- public boolean isCameraRoll() {
- return mBaseSet.isCameraRoll();
- }
-
- @Override
- public String getName() {
- return mBaseSet.getName();
- }
-
- @Override
- public int getMediaItemCount() {
- return mBaseSet.getMediaItemCount() - mCurrent.size();
- }
-
- // Gets the MediaItems whose (post-deletion) index are in the range [start,
- // start + count). Because we remove some of the MediaItems, the index need
- // to be adjusted.
- //
- // For example, if there are 12 items in total. The deleted items are 3, 5,
- // 10, and the the requested range is [3, 7]:
- //
- // The original index: 0 1 2 3 4 5 6 7 8 9 A B C
- // The deleted items: X X X
- // The new index: 0 1 2 3 4 5 6 7 8 9
- // Requested: * * * * *
- //
- // We need to figure out the [3, 7] actually maps to the original index 4,
- // 6, 7, 8, 9.
- //
- // We can break the MediaItems into segments, each segment other than the
- // last one ends in a deleted item. The difference between the new index and
- // the original index increases with each segment:
- //
- // 0 1 2 X (new index = old index)
- // 4 X (new index = old index - 1)
- // 6 7 8 9 X (new index = old index - 2)
- // B C (new index = old index - 3)
- //
- @Override
- public ArrayList<MediaItem> getMediaItem(int start, int count) {
- if (count <= 0) return new ArrayList<MediaItem>();
-
- int end = start + count - 1;
- int n = mCurrent.size();
- // Find the segment that "start" falls into. Count the number of items
- // not yet deleted until it reaches "start".
- int i = 0;
- for (i = 0; i < n; i++) {
- Deletion d = mCurrent.get(i);
- if (d.index - i > start) break;
- }
- // Find the segment that "end" falls into.
- int j = i;
- for (; j < n; j++) {
- Deletion d = mCurrent.get(j);
- if (d.index - j > end) break;
- }
-
- // Now get enough to cover deleted items in [start, end]
- ArrayList<MediaItem> base = mBaseSet.getMediaItem(start + i, count + (j - i));
-
- // Remove the deleted items.
- for (int m = j - 1; m >= i; m--) {
- Deletion d = mCurrent.get(m);
- int k = d.index - (start + i);
- base.remove(k);
- }
- return base;
- }
-
- // We apply the pending requests in the mRequests to construct mCurrent in reload().
- @Override
- public long reload() {
- boolean newData = mBaseSet.reload() > mDataVersion;
- synchronized (mRequests) {
- if (!newData && mRequests.isEmpty()) {
- return mDataVersion;
- }
- for (int i = 0; i < mRequests.size(); i++) {
- Request r = mRequests.get(i);
- switch (r.type) {
- case REQUEST_ADD: {
- // Add the path into mCurrent if there is no duplicate.
- int n = mCurrent.size();
- int j;
- for (j = 0; j < n; j++) {
- if (mCurrent.get(j).path == r.path) break;
- }
- if (j == n) {
- mCurrent.add(new Deletion(r.path, r.indexHint));
- }
- break;
- }
- case REQUEST_REMOVE: {
- // Remove the path from mCurrent.
- int n = mCurrent.size();
- for (int j = 0; j < n; j++) {
- if (mCurrent.get(j).path == r.path) {
- mCurrent.remove(j);
- break;
- }
- }
- break;
- }
- case REQUEST_CLEAR: {
- mCurrent.clear();
- break;
- }
- }
- }
- mRequests.clear();
- }
-
- if (!mCurrent.isEmpty()) {
- // See if the elements in mCurrent can be found in the MediaSet. We
- // don't want to search the whole mBaseSet, so we just search a
- // small window that contains the index hints (plus some margin).
- int minIndex = mCurrent.get(0).index;
- int maxIndex = minIndex;
- for (int i = 1; i < mCurrent.size(); i++) {
- Deletion d = mCurrent.get(i);
- minIndex = Math.min(d.index, minIndex);
- maxIndex = Math.max(d.index, maxIndex);
- }
-
- int n = mBaseSet.getMediaItemCount();
- int from = Math.max(minIndex - 5, 0);
- int to = Math.min(maxIndex + 5, n);
- ArrayList<MediaItem> items = mBaseSet.getMediaItem(from, to - from);
- ArrayList<Deletion> result = new ArrayList<Deletion>();
- for (int i = 0; i < items.size(); i++) {
- MediaItem item = items.get(i);
- if (item == null) continue;
- Path p = item.getPath();
- // Find the matching path in mCurrent, if found move it to result
- for (int j = 0; j < mCurrent.size(); j++) {
- Deletion d = mCurrent.get(j);
- if (d.path == p) {
- d.index = from + i;
- result.add(d);
- mCurrent.remove(j);
- break;
- }
- }
- }
- mCurrent = result;
- }
-
- mDataVersion = nextVersionNumber();
- return mDataVersion;
- }
-
- private void sendRequest(int type, Path path, int indexHint) {
- Request r = new Request(type, path, indexHint);
- synchronized (mRequests) {
- mRequests.add(r);
- }
- notifyContentChanged();
- }
-
- @Override
- public void onContentDirty() {
- notifyContentChanged();
- }
-
- public void addDeletion(Path path, int indexHint) {
- sendRequest(REQUEST_ADD, path, indexHint);
- }
-
- public void removeDeletion(Path path) {
- sendRequest(REQUEST_REMOVE, path, 0 /* unused */);
- }
-
- public void clearDeletion() {
- sendRequest(REQUEST_CLEAR, null /* unused */ , 0 /* unused */);
- }
-
- // Returns number of deletions _in effect_ (the number will only gets
- // updated after a reload()).
- public int getNumberOfDeletions() {
- return mCurrent.size();
- }
-}
diff --git a/src/com/android/gallery3d/data/FilterEmptyPromptSet.java b/src/com/android/gallery3d/data/FilterEmptyPromptSet.java
deleted file mode 100644
index b576e06d4..000000000
--- a/src/com/android/gallery3d/data/FilterEmptyPromptSet.java
+++ /dev/null
@@ -1,82 +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.data;
-
-import java.util.ArrayList;
-
-public class FilterEmptyPromptSet extends MediaSet implements ContentListener {
- @SuppressWarnings("unused")
- private static final String TAG = "FilterEmptyPromptSet";
-
- private ArrayList<MediaItem> mEmptyItem;
- private MediaSet mBaseSet;
-
- public FilterEmptyPromptSet(Path path, MediaSet baseSet, MediaItem emptyItem) {
- super(path, INVALID_DATA_VERSION);
- mEmptyItem = new ArrayList<MediaItem>(1);
- mEmptyItem.add(emptyItem);
- mBaseSet = baseSet;
- mBaseSet.addContentListener(this);
- }
-
- @Override
- public int getMediaItemCount() {
- int itemCount = mBaseSet.getMediaItemCount();
- if (itemCount > 0) {
- return itemCount;
- } else {
- return 1;
- }
- }
-
- @Override
- public ArrayList<MediaItem> getMediaItem(int start, int count) {
- int itemCount = mBaseSet.getMediaItemCount();
- if (itemCount > 0) {
- return mBaseSet.getMediaItem(start, count);
- } else if (start == 0 && count == 1) {
- return mEmptyItem;
- } else {
- throw new ArrayIndexOutOfBoundsException();
- }
- }
-
- @Override
- public void onContentDirty() {
- notifyContentChanged();
- }
-
- @Override
- public boolean isLeafAlbum() {
- return true;
- }
-
- @Override
- public boolean isCameraRoll() {
- return mBaseSet.isCameraRoll();
- }
-
- @Override
- public long reload() {
- return mBaseSet.reload();
- }
-
- @Override
- public String getName() {
- return mBaseSet.getName();
- }
-}
diff --git a/src/com/android/gallery3d/data/FilterSource.java b/src/com/android/gallery3d/data/FilterSource.java
deleted file mode 100644
index d689fe336..000000000
--- a/src/com/android/gallery3d/data/FilterSource.java
+++ /dev/null
@@ -1,94 +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.data;
-
-import com.android.gallery3d.app.GalleryApp;
-
-public class FilterSource extends MediaSource {
- @SuppressWarnings("unused")
- private static final String TAG = "FilterSource";
- private static final int FILTER_BY_MEDIATYPE = 0;
- private static final int FILTER_BY_DELETE = 1;
- private static final int FILTER_BY_EMPTY = 2;
- private static final int FILTER_BY_EMPTY_ITEM = 3;
- private static final int FILTER_BY_CAMERA_SHORTCUT = 4;
- private static final int FILTER_BY_CAMERA_SHORTCUT_ITEM = 5;
-
- public static final String FILTER_EMPTY_ITEM = "/filter/empty_prompt";
- public static final String FILTER_CAMERA_SHORTCUT = "/filter/camera_shortcut";
- private static final String FILTER_CAMERA_SHORTCUT_ITEM = "/filter/camera_shortcut_item";
-
- private GalleryApp mApplication;
- private PathMatcher mMatcher;
- private MediaItem mEmptyItem;
- private MediaItem mCameraShortcutItem;
-
- public FilterSource(GalleryApp application) {
- super("filter");
- mApplication = application;
- mMatcher = new PathMatcher();
- mMatcher.add("/filter/mediatype/*/*", FILTER_BY_MEDIATYPE);
- mMatcher.add("/filter/delete/*", FILTER_BY_DELETE);
- mMatcher.add("/filter/empty/*", FILTER_BY_EMPTY);
- mMatcher.add(FILTER_EMPTY_ITEM, FILTER_BY_EMPTY_ITEM);
- mMatcher.add(FILTER_CAMERA_SHORTCUT, FILTER_BY_CAMERA_SHORTCUT);
- mMatcher.add(FILTER_CAMERA_SHORTCUT_ITEM, FILTER_BY_CAMERA_SHORTCUT_ITEM);
-
- mEmptyItem = new EmptyAlbumImage(Path.fromString(FILTER_EMPTY_ITEM),
- mApplication);
- mCameraShortcutItem = new CameraShortcutImage(
- Path.fromString(FILTER_CAMERA_SHORTCUT_ITEM), mApplication);
- }
-
- // The name we accept are:
- // /filter/mediatype/k/{set} where k is the media type we want.
- // /filter/delete/{set}
- @Override
- public MediaObject createMediaObject(Path path) {
- int matchType = mMatcher.match(path);
- DataManager dataManager = mApplication.getDataManager();
- switch (matchType) {
- case FILTER_BY_MEDIATYPE: {
- int mediaType = mMatcher.getIntVar(0);
- String setsName = mMatcher.getVar(1);
- MediaSet[] sets = dataManager.getMediaSetsFromString(setsName);
- return new FilterTypeSet(path, dataManager, sets[0], mediaType);
- }
- case FILTER_BY_DELETE: {
- String setsName = mMatcher.getVar(0);
- MediaSet[] sets = dataManager.getMediaSetsFromString(setsName);
- return new FilterDeleteSet(path, sets[0]);
- }
- case FILTER_BY_EMPTY: {
- String setsName = mMatcher.getVar(0);
- MediaSet[] sets = dataManager.getMediaSetsFromString(setsName);
- return new FilterEmptyPromptSet(path, sets[0], mEmptyItem);
- }
- case FILTER_BY_EMPTY_ITEM: {
- return mEmptyItem;
- }
- case FILTER_BY_CAMERA_SHORTCUT: {
- return new SingleItemAlbum(path, mCameraShortcutItem);
- }
- case FILTER_BY_CAMERA_SHORTCUT_ITEM: {
- return mCameraShortcutItem;
- }
- default:
- throw new RuntimeException("bad path: " + path);
- }
- }
-}
diff --git a/src/com/android/gallery3d/data/FilterTypeSet.java b/src/com/android/gallery3d/data/FilterTypeSet.java
deleted file mode 100644
index 477ef73ad..000000000
--- a/src/com/android/gallery3d/data/FilterTypeSet.java
+++ /dev/null
@@ -1,137 +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.data;
-
-import java.util.ArrayList;
-
-// FilterTypeSet filters a base MediaSet according to a matching media type.
-public class FilterTypeSet extends MediaSet implements ContentListener {
- @SuppressWarnings("unused")
- private static final String TAG = "FilterTypeSet";
-
- private final DataManager mDataManager;
- private final MediaSet mBaseSet;
- private final int mMediaType;
- private final ArrayList<Path> mPaths = new ArrayList<Path>();
- private final ArrayList<MediaSet> mAlbums = new ArrayList<MediaSet>();
-
- public FilterTypeSet(Path path, DataManager dataManager, MediaSet baseSet,
- int mediaType) {
- super(path, INVALID_DATA_VERSION);
- mDataManager = dataManager;
- mBaseSet = baseSet;
- mMediaType = mediaType;
- mBaseSet.addContentListener(this);
- }
-
- @Override
- public String getName() {
- return mBaseSet.getName();
- }
-
- @Override
- public MediaSet getSubMediaSet(int index) {
- return mAlbums.get(index);
- }
-
- @Override
- public int getSubMediaSetCount() {
- return mAlbums.size();
- }
-
- @Override
- public int getMediaItemCount() {
- return mPaths.size();
- }
-
- @Override
- public ArrayList<MediaItem> getMediaItem(int start, int count) {
- return ClusterAlbum.getMediaItemFromPath(
- mPaths, start, count, mDataManager);
- }
-
- @Override
- public long reload() {
- if (mBaseSet.reload() > mDataVersion) {
- updateData();
- mDataVersion = nextVersionNumber();
- }
- return mDataVersion;
- }
-
- @Override
- public void onContentDirty() {
- notifyContentChanged();
- }
-
- private void updateData() {
- // Albums
- mAlbums.clear();
- String basePath = "/filter/mediatype/" + mMediaType;
-
- for (int i = 0, n = mBaseSet.getSubMediaSetCount(); i < n; i++) {
- MediaSet set = mBaseSet.getSubMediaSet(i);
- String filteredPath = basePath + "/{" + set.getPath().toString() + "}";
- MediaSet filteredSet = mDataManager.getMediaSet(filteredPath);
- filteredSet.reload();
- if (filteredSet.getMediaItemCount() > 0
- || filteredSet.getSubMediaSetCount() > 0) {
- mAlbums.add(filteredSet);
- }
- }
-
- // Items
- mPaths.clear();
- final int total = mBaseSet.getMediaItemCount();
- final Path[] buf = new Path[total];
-
- mBaseSet.enumerateMediaItems(new MediaSet.ItemConsumer() {
- @Override
- public void consume(int index, MediaItem item) {
- if (item.getMediaType() == mMediaType) {
- if (index < 0 || index >= total) return;
- Path path = item.getPath();
- buf[index] = path;
- }
- }
- });
-
- for (int i = 0; i < total; i++) {
- if (buf[i] != null) {
- mPaths.add(buf[i]);
- }
- }
- }
-
- @Override
- public int getSupportedOperations() {
- return SUPPORT_SHARE | SUPPORT_DELETE;
- }
-
- @Override
- public void delete() {
- ItemConsumer consumer = new ItemConsumer() {
- @Override
- public void consume(int index, MediaItem item) {
- if ((item.getSupportedOperations() & SUPPORT_DELETE) != 0) {
- item.delete();
- }
- }
- };
- mDataManager.mapMediaItems(mPaths, consumer, 0);
- }
-}
diff --git a/src/com/android/gallery3d/data/ImageCacheRequest.java b/src/com/android/gallery3d/data/ImageCacheRequest.java
deleted file mode 100644
index 6cbc5c5ea..000000000
--- a/src/com/android/gallery3d/data/ImageCacheRequest.java
+++ /dev/null
@@ -1,102 +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.data;
-
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-
-import com.android.gallery3d.app.GalleryApp;
-import com.android.gallery3d.common.BitmapUtils;
-import com.android.gallery3d.data.BytesBufferPool.BytesBuffer;
-import com.android.gallery3d.util.ThreadPool.Job;
-import com.android.gallery3d.util.ThreadPool.JobContext;
-
-abstract class ImageCacheRequest implements Job<Bitmap> {
- private static final String TAG = "ImageCacheRequest";
-
- protected GalleryApp mApplication;
- private Path mPath;
- private int mType;
- private int mTargetSize;
- private long mTimeModified;
-
- public ImageCacheRequest(GalleryApp application,
- Path path, long timeModified, int type, int targetSize) {
- mApplication = application;
- mPath = path;
- mType = type;
- mTargetSize = targetSize;
- mTimeModified = timeModified;
- }
-
- private String debugTag() {
- return mPath + "," + mTimeModified + "," +
- ((mType == MediaItem.TYPE_THUMBNAIL) ? "THUMB" :
- (mType == MediaItem.TYPE_MICROTHUMBNAIL) ? "MICROTHUMB" : "?");
- }
-
- @Override
- public Bitmap run(JobContext jc) {
- ImageCacheService cacheService = mApplication.getImageCacheService();
-
- BytesBuffer buffer = MediaItem.getBytesBufferPool().get();
- try {
- boolean found = cacheService.getImageData(mPath, mTimeModified, mType, buffer);
- if (jc.isCancelled()) return null;
- if (found) {
- BitmapFactory.Options options = new BitmapFactory.Options();
- options.inPreferredConfig = Bitmap.Config.ARGB_8888;
- Bitmap bitmap;
- if (mType == MediaItem.TYPE_MICROTHUMBNAIL) {
- bitmap = DecodeUtils.decodeUsingPool(jc,
- buffer.data, buffer.offset, buffer.length, options);
- } else {
- bitmap = DecodeUtils.decodeUsingPool(jc,
- buffer.data, buffer.offset, buffer.length, options);
- }
- if (bitmap == null && !jc.isCancelled()) {
- Log.w(TAG, "decode cached failed " + debugTag());
- }
- return bitmap;
- }
- } finally {
- MediaItem.getBytesBufferPool().recycle(buffer);
- }
- Bitmap bitmap = onDecodeOriginal(jc, mType);
- if (jc.isCancelled()) return null;
-
- if (bitmap == null) {
- Log.w(TAG, "decode orig failed " + debugTag());
- return null;
- }
-
- if (mType == MediaItem.TYPE_MICROTHUMBNAIL) {
- bitmap = BitmapUtils.resizeAndCropCenter(bitmap, mTargetSize, true);
- } else {
- bitmap = BitmapUtils.resizeDownBySideLength(bitmap, mTargetSize, true);
- }
- if (jc.isCancelled()) return null;
-
- byte[] array = BitmapUtils.compressToBytes(bitmap);
- if (jc.isCancelled()) return null;
-
- cacheService.putImageData(mPath, mTimeModified, mType, array);
- return bitmap;
- }
-
- public abstract Bitmap onDecodeOriginal(JobContext jc, int targetSize);
-}
diff --git a/src/com/android/gallery3d/data/ImageCacheService.java b/src/com/android/gallery3d/data/ImageCacheService.java
deleted file mode 100644
index 1c7cb8c5e..000000000
--- a/src/com/android/gallery3d/data/ImageCacheService.java
+++ /dev/null
@@ -1,123 +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.data;
-
-import android.content.Context;
-
-import com.android.gallery3d.common.BlobCache;
-import com.android.gallery3d.common.BlobCache.LookupRequest;
-import com.android.gallery3d.common.Utils;
-import com.android.gallery3d.data.BytesBufferPool.BytesBuffer;
-import com.android.gallery3d.util.CacheManager;
-import com.android.gallery3d.util.GalleryUtils;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-
-public class ImageCacheService {
- @SuppressWarnings("unused")
- private static final String TAG = "ImageCacheService";
-
- private static final String IMAGE_CACHE_FILE = "imgcache";
- private static final int IMAGE_CACHE_MAX_ENTRIES = 5000;
- private static final int IMAGE_CACHE_MAX_BYTES = 200 * 1024 * 1024;
- private static final int IMAGE_CACHE_VERSION = 7;
-
- private BlobCache mCache;
-
- public ImageCacheService(Context context) {
- mCache = CacheManager.getCache(context, IMAGE_CACHE_FILE,
- IMAGE_CACHE_MAX_ENTRIES, IMAGE_CACHE_MAX_BYTES,
- IMAGE_CACHE_VERSION);
- }
-
- /**
- * Gets the cached image data for the given <code>path</code>,
- * <code>timeModified</code> and <code>type</code>.
- *
- * The image data will be stored in <code>buffer.data</code>, started from
- * <code>buffer.offset</code> for <code>buffer.length</code> bytes. If the
- * buffer.data is not big enough, a new byte array will be allocated and returned.
- *
- * @return true if the image data is found; false if not found.
- */
- public boolean getImageData(Path path, long timeModified, int type, BytesBuffer buffer) {
- byte[] key = makeKey(path, timeModified, type);
- long cacheKey = Utils.crc64Long(key);
- try {
- LookupRequest request = new LookupRequest();
- request.key = cacheKey;
- request.buffer = buffer.data;
- synchronized (mCache) {
- if (!mCache.lookup(request)) return false;
- }
- if (isSameKey(key, request.buffer)) {
- buffer.data = request.buffer;
- buffer.offset = key.length;
- buffer.length = request.length - buffer.offset;
- return true;
- }
- } catch (IOException ex) {
- // ignore.
- }
- return false;
- }
-
- public void putImageData(Path path, long timeModified, int type, byte[] value) {
- byte[] key = makeKey(path, timeModified, type);
- long cacheKey = Utils.crc64Long(key);
- ByteBuffer buffer = ByteBuffer.allocate(key.length + value.length);
- buffer.put(key);
- buffer.put(value);
- synchronized (mCache) {
- try {
- mCache.insert(cacheKey, buffer.array());
- } catch (IOException ex) {
- // ignore.
- }
- }
- }
-
- public void clearImageData(Path path, long timeModified, int type) {
- byte[] key = makeKey(path, timeModified, type);
- long cacheKey = Utils.crc64Long(key);
- synchronized (mCache) {
- try {
- mCache.clearEntry(cacheKey);
- } catch (IOException ex) {
- // ignore.
- }
- }
- }
-
- private static byte[] makeKey(Path path, long timeModified, int type) {
- return GalleryUtils.getBytes(path.toString() + "+" + timeModified + "+" + type);
- }
-
- private static boolean isSameKey(byte[] key, byte[] buffer) {
- int n = key.length;
- if (buffer.length < n) {
- return false;
- }
- for (int i = 0; i < n; ++i) {
- if (key[i] != buffer[i]) {
- return false;
- }
- }
- return true;
- }
-}
diff --git a/src/com/android/gallery3d/data/LocalAlbum.java b/src/com/android/gallery3d/data/LocalAlbum.java
deleted file mode 100644
index 7b7015af6..000000000
--- a/src/com/android/gallery3d/data/LocalAlbum.java
+++ /dev/null
@@ -1,325 +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.data;
-
-import android.content.ContentResolver;
-import android.content.res.Resources;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Environment;
-import android.provider.MediaStore;
-import android.provider.MediaStore.Images;
-import android.provider.MediaStore.Images.ImageColumns;
-import android.provider.MediaStore.Video;
-import android.provider.MediaStore.Video.VideoColumns;
-
-import com.android.gallery3d.R;
-import com.android.gallery3d.app.GalleryApp;
-import com.android.gallery3d.common.Utils;
-import com.android.gallery3d.util.BucketNames;
-import com.android.gallery3d.util.GalleryUtils;
-import com.android.gallery3d.util.MediaSetUtils;
-
-import java.io.File;
-import java.util.ArrayList;
-
-// LocalAlbumSet lists all media items in one bucket on local storage.
-// The media items need to be all images or all videos, but not both.
-public class LocalAlbum extends MediaSet {
- private static final String TAG = "LocalAlbum";
- private static final String[] COUNT_PROJECTION = { "count(*)" };
-
- private static final int INVALID_COUNT = -1;
- private final String mWhereClause;
- private final String mOrderClause;
- private final Uri mBaseUri;
- private final String[] mProjection;
-
- private final GalleryApp mApplication;
- private final ContentResolver mResolver;
- private final int mBucketId;
- private final String mName;
- private final boolean mIsImage;
- private final ChangeNotifier mNotifier;
- private final Path mItemPath;
- private int mCachedCount = INVALID_COUNT;
-
- public LocalAlbum(Path path, GalleryApp application, int bucketId,
- boolean isImage, String name) {
- super(path, nextVersionNumber());
- mApplication = application;
- mResolver = application.getContentResolver();
- mBucketId = bucketId;
- mName = name;
- mIsImage = isImage;
-
- if (isImage) {
- mWhereClause = ImageColumns.BUCKET_ID + " = ?";
- mOrderClause = ImageColumns.DATE_TAKEN + " DESC, "
- + ImageColumns._ID + " DESC";
- mBaseUri = Images.Media.EXTERNAL_CONTENT_URI;
- mProjection = LocalImage.PROJECTION;
- mItemPath = LocalImage.ITEM_PATH;
- } else {
- mWhereClause = VideoColumns.BUCKET_ID + " = ?";
- mOrderClause = VideoColumns.DATE_TAKEN + " DESC, "
- + VideoColumns._ID + " DESC";
- mBaseUri = Video.Media.EXTERNAL_CONTENT_URI;
- mProjection = LocalVideo.PROJECTION;
- mItemPath = LocalVideo.ITEM_PATH;
- }
-
- mNotifier = new ChangeNotifier(this, mBaseUri, application);
- }
-
- public LocalAlbum(Path path, GalleryApp application, int bucketId,
- boolean isImage) {
- this(path, application, bucketId, isImage,
- BucketHelper.getBucketName(
- application.getContentResolver(), bucketId));
- }
-
- @Override
- public boolean isCameraRoll() {
- return mBucketId == MediaSetUtils.CAMERA_BUCKET_ID;
- }
-
- @Override
- public Uri getContentUri() {
- if (mIsImage) {
- return MediaStore.Images.Media.EXTERNAL_CONTENT_URI.buildUpon()
- .appendQueryParameter(LocalSource.KEY_BUCKET_ID,
- String.valueOf(mBucketId)).build();
- } else {
- return MediaStore.Video.Media.EXTERNAL_CONTENT_URI.buildUpon()
- .appendQueryParameter(LocalSource.KEY_BUCKET_ID,
- String.valueOf(mBucketId)).build();
- }
- }
-
- @Override
- public ArrayList<MediaItem> getMediaItem(int start, int count) {
- DataManager dataManager = mApplication.getDataManager();
- Uri uri = mBaseUri.buildUpon()
- .appendQueryParameter("limit", start + "," + count).build();
- ArrayList<MediaItem> list = new ArrayList<MediaItem>();
- GalleryUtils.assertNotInRenderThread();
- Cursor cursor = mResolver.query(
- uri, mProjection, mWhereClause,
- new String[]{String.valueOf(mBucketId)},
- mOrderClause);
- if (cursor == null) {
- Log.w(TAG, "query fail: " + uri);
- return list;
- }
-
- try {
- while (cursor.moveToNext()) {
- int id = cursor.getInt(0); // _id must be in the first column
- Path childPath = mItemPath.getChild(id);
- MediaItem item = loadOrUpdateItem(childPath, cursor,
- dataManager, mApplication, mIsImage);
- list.add(item);
- }
- } finally {
- cursor.close();
- }
- return list;
- }
-
- private static MediaItem loadOrUpdateItem(Path path, Cursor cursor,
- DataManager dataManager, GalleryApp app, boolean isImage) {
- synchronized (DataManager.LOCK) {
- LocalMediaItem item = (LocalMediaItem) dataManager.peekMediaObject(path);
- if (item == null) {
- if (isImage) {
- item = new LocalImage(path, app, cursor);
- } else {
- item = new LocalVideo(path, app, cursor);
- }
- } else {
- item.updateContent(cursor);
- }
- return item;
- }
- }
-
- // The pids array are sorted by the (path) id.
- public static MediaItem[] getMediaItemById(
- GalleryApp application, boolean isImage, ArrayList<Integer> ids) {
- // get the lower and upper bound of (path) id
- MediaItem[] result = new MediaItem[ids.size()];
- if (ids.isEmpty()) return result;
- int idLow = ids.get(0);
- int idHigh = ids.get(ids.size() - 1);
-
- // prepare the query parameters
- Uri baseUri;
- String[] projection;
- Path itemPath;
- if (isImage) {
- baseUri = Images.Media.EXTERNAL_CONTENT_URI;
- projection = LocalImage.PROJECTION;
- itemPath = LocalImage.ITEM_PATH;
- } else {
- baseUri = Video.Media.EXTERNAL_CONTENT_URI;
- projection = LocalVideo.PROJECTION;
- itemPath = LocalVideo.ITEM_PATH;
- }
-
- ContentResolver resolver = application.getContentResolver();
- DataManager dataManager = application.getDataManager();
- Cursor cursor = resolver.query(baseUri, projection, "_id BETWEEN ? AND ?",
- new String[]{String.valueOf(idLow), String.valueOf(idHigh)},
- "_id");
- if (cursor == null) {
- Log.w(TAG, "query fail" + baseUri);
- return result;
- }
- try {
- int n = ids.size();
- int i = 0;
-
- while (i < n && cursor.moveToNext()) {
- int id = cursor.getInt(0); // _id must be in the first column
-
- // Match id with the one on the ids list.
- if (ids.get(i) > id) {
- continue;
- }
-
- while (ids.get(i) < id) {
- if (++i >= n) {
- return result;
- }
- }
-
- Path childPath = itemPath.getChild(id);
- MediaItem item = loadOrUpdateItem(childPath, cursor, dataManager,
- application, isImage);
- result[i] = item;
- ++i;
- }
- return result;
- } finally {
- cursor.close();
- }
- }
-
- public static Cursor getItemCursor(ContentResolver resolver, Uri uri,
- String[] projection, int id) {
- return resolver.query(uri, projection, "_id=?",
- new String[]{String.valueOf(id)}, null);
- }
-
- @Override
- public int getMediaItemCount() {
- if (mCachedCount == INVALID_COUNT) {
- Cursor cursor = mResolver.query(
- mBaseUri, COUNT_PROJECTION, mWhereClause,
- new String[]{String.valueOf(mBucketId)}, null);
- if (cursor == null) {
- Log.w(TAG, "query fail");
- return 0;
- }
- try {
- Utils.assertTrue(cursor.moveToNext());
- mCachedCount = cursor.getInt(0);
- } finally {
- cursor.close();
- }
- }
- return mCachedCount;
- }
-
- @Override
- public String getName() {
- return getLocalizedName(mApplication.getResources(), mBucketId, mName);
- }
-
- @Override
- public long reload() {
- if (mNotifier.isDirty()) {
- mDataVersion = nextVersionNumber();
- mCachedCount = INVALID_COUNT;
- }
- return mDataVersion;
- }
-
- @Override
- public int getSupportedOperations() {
- return SUPPORT_DELETE | SUPPORT_SHARE | SUPPORT_INFO;
- }
-
- @Override
- public void delete() {
- GalleryUtils.assertNotInRenderThread();
- mResolver.delete(mBaseUri, mWhereClause,
- new String[]{String.valueOf(mBucketId)});
- }
-
- @Override
- public boolean isLeafAlbum() {
- return true;
- }
-
- public static String getLocalizedName(Resources res, int bucketId,
- String name) {
- if (bucketId == MediaSetUtils.CAMERA_BUCKET_ID) {
- return res.getString(R.string.folder_camera);
- } else if (bucketId == MediaSetUtils.DOWNLOAD_BUCKET_ID) {
- return res.getString(R.string.folder_download);
- } else if (bucketId == MediaSetUtils.IMPORTED_BUCKET_ID) {
- return res.getString(R.string.folder_imported);
- } else if (bucketId == MediaSetUtils.SNAPSHOT_BUCKET_ID) {
- return res.getString(R.string.folder_screenshot);
- } else if (bucketId == MediaSetUtils.EDITED_ONLINE_PHOTOS_BUCKET_ID) {
- return res.getString(R.string.folder_edited_online_photos);
- } else {
- return name;
- }
- }
-
- // Relative path is the absolute path minus external storage path
- public static String getRelativePath(int bucketId) {
- String relativePath = "/";
- if (bucketId == MediaSetUtils.CAMERA_BUCKET_ID) {
- relativePath += BucketNames.CAMERA;
- } else if (bucketId == MediaSetUtils.DOWNLOAD_BUCKET_ID) {
- relativePath += BucketNames.DOWNLOAD;
- } else if (bucketId == MediaSetUtils.IMPORTED_BUCKET_ID) {
- relativePath += BucketNames.IMPORTED;
- } else if (bucketId == MediaSetUtils.SNAPSHOT_BUCKET_ID) {
- relativePath += BucketNames.SCREENSHOTS;
- } else if (bucketId == MediaSetUtils.EDITED_ONLINE_PHOTOS_BUCKET_ID) {
- relativePath += BucketNames.EDITED_ONLINE_PHOTOS;
- } else {
- // If the first few cases didn't hit the matching path, do a
- // thorough search in the local directories.
- File extStorage = Environment.getExternalStorageDirectory();
- String path = GalleryUtils.searchDirForPath(extStorage, bucketId);
- if (path == null) {
- Log.w(TAG, "Relative path for bucket id: " + bucketId + " is not found.");
- relativePath = null;
- } else {
- relativePath = path.substring(extStorage.getAbsolutePath().length());
- }
- }
- return relativePath;
- }
-
-}
diff --git a/src/com/android/gallery3d/data/LocalAlbumSet.java b/src/com/android/gallery3d/data/LocalAlbumSet.java
deleted file mode 100644
index b2b4b8c5d..000000000
--- a/src/com/android/gallery3d/data/LocalAlbumSet.java
+++ /dev/null
@@ -1,211 +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.data;
-
-import android.net.Uri;
-import android.os.Handler;
-import android.provider.MediaStore.Images;
-import android.provider.MediaStore.Video;
-
-import com.android.gallery3d.R;
-import com.android.gallery3d.app.GalleryApp;
-import com.android.gallery3d.data.BucketHelper.BucketEntry;
-import com.android.gallery3d.util.Future;
-import com.android.gallery3d.util.FutureListener;
-import com.android.gallery3d.util.MediaSetUtils;
-import com.android.gallery3d.util.ThreadPool;
-import com.android.gallery3d.util.ThreadPool.JobContext;
-
-import java.util.ArrayList;
-import java.util.Comparator;
-
-// LocalAlbumSet lists all image or video albums in the local storage.
-// The path should be "/local/image", "local/video" or "/local/all"
-public class LocalAlbumSet extends MediaSet
- implements FutureListener<ArrayList<MediaSet>> {
- @SuppressWarnings("unused")
- private static final String TAG = "LocalAlbumSet";
-
- public static final Path PATH_ALL = Path.fromString("/local/all");
- public static final Path PATH_IMAGE = Path.fromString("/local/image");
- public static final Path PATH_VIDEO = Path.fromString("/local/video");
-
- private static final Uri[] mWatchUris =
- {Images.Media.EXTERNAL_CONTENT_URI, Video.Media.EXTERNAL_CONTENT_URI};
-
- private final GalleryApp mApplication;
- private final int mType;
- private ArrayList<MediaSet> mAlbums = new ArrayList<MediaSet>();
- private final ChangeNotifier mNotifier;
- private final String mName;
- private final Handler mHandler;
- private boolean mIsLoading;
-
- private Future<ArrayList<MediaSet>> mLoadTask;
- private ArrayList<MediaSet> mLoadBuffer;
-
- public LocalAlbumSet(Path path, GalleryApp application) {
- super(path, nextVersionNumber());
- mApplication = application;
- mHandler = new Handler(application.getMainLooper());
- mType = getTypeFromPath(path);
- mNotifier = new ChangeNotifier(this, mWatchUris, application);
- mName = application.getResources().getString(
- R.string.set_label_local_albums);
- }
-
- private static int getTypeFromPath(Path path) {
- String name[] = path.split();
- if (name.length < 2) {
- throw new IllegalArgumentException(path.toString());
- }
- return getTypeFromString(name[1]);
- }
-
- @Override
- public MediaSet getSubMediaSet(int index) {
- return mAlbums.get(index);
- }
-
- @Override
- public int getSubMediaSetCount() {
- return mAlbums.size();
- }
-
- @Override
- public String getName() {
- return mName;
- }
-
- private static int findBucket(BucketEntry entries[], int bucketId) {
- for (int i = 0, n = entries.length; i < n; ++i) {
- if (entries[i].bucketId == bucketId) return i;
- }
- return -1;
- }
-
- private class AlbumsLoader implements ThreadPool.Job<ArrayList<MediaSet>> {
-
- @Override
- @SuppressWarnings("unchecked")
- public ArrayList<MediaSet> run(JobContext jc) {
- // Note: it will be faster if we only select media_type and bucket_id.
- // need to test the performance if that is worth
- BucketEntry[] entries = BucketHelper.loadBucketEntries(
- jc, mApplication.getContentResolver(), mType);
-
- if (jc.isCancelled()) return null;
-
- int offset = 0;
- // Move camera and download bucket to the front, while keeping the
- // order of others.
- int index = findBucket(entries, MediaSetUtils.CAMERA_BUCKET_ID);
- if (index != -1) {
- circularShiftRight(entries, offset++, index);
- }
- index = findBucket(entries, MediaSetUtils.DOWNLOAD_BUCKET_ID);
- if (index != -1) {
- circularShiftRight(entries, offset++, index);
- }
-
- ArrayList<MediaSet> albums = new ArrayList<MediaSet>();
- DataManager dataManager = mApplication.getDataManager();
- for (BucketEntry entry : entries) {
- MediaSet album = getLocalAlbum(dataManager,
- mType, mPath, entry.bucketId, entry.bucketName);
- albums.add(album);
- }
- return albums;
- }
- }
-
- private MediaSet getLocalAlbum(
- DataManager manager, int type, Path parent, int id, String name) {
- synchronized (DataManager.LOCK) {
- Path path = parent.getChild(id);
- MediaObject object = manager.peekMediaObject(path);
- if (object != null) return (MediaSet) object;
- switch (type) {
- case MEDIA_TYPE_IMAGE:
- return new LocalAlbum(path, mApplication, id, true, name);
- case MEDIA_TYPE_VIDEO:
- return new LocalAlbum(path, mApplication, id, false, name);
- case MEDIA_TYPE_ALL:
- Comparator<MediaItem> comp = DataManager.sDateTakenComparator;
- return new LocalMergeAlbum(path, comp, new MediaSet[] {
- getLocalAlbum(manager, MEDIA_TYPE_IMAGE, PATH_IMAGE, id, name),
- getLocalAlbum(manager, MEDIA_TYPE_VIDEO, PATH_VIDEO, id, name)}, id);
- }
- throw new IllegalArgumentException(String.valueOf(type));
- }
- }
-
- @Override
- public synchronized boolean isLoading() {
- return mIsLoading;
- }
-
- @Override
- // synchronized on this function for
- // 1. Prevent calling reload() concurrently.
- // 2. Prevent calling onFutureDone() and reload() concurrently
- public synchronized long reload() {
- if (mNotifier.isDirty()) {
- if (mLoadTask != null) mLoadTask.cancel();
- mIsLoading = true;
- mLoadTask = mApplication.getThreadPool().submit(new AlbumsLoader(), this);
- }
- if (mLoadBuffer != null) {
- mAlbums = mLoadBuffer;
- mLoadBuffer = null;
- for (MediaSet album : mAlbums) {
- album.reload();
- }
- mDataVersion = nextVersionNumber();
- }
- return mDataVersion;
- }
-
- @Override
- public synchronized void onFutureDone(Future<ArrayList<MediaSet>> future) {
- if (mLoadTask != future) return; // ignore, wait for the latest task
- mLoadBuffer = future.get();
- mIsLoading = false;
- if (mLoadBuffer == null) mLoadBuffer = new ArrayList<MediaSet>();
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- notifyContentChanged();
- }
- });
- }
-
- // For debug only. Fake there is a ContentObserver.onChange() event.
- void fakeChange() {
- mNotifier.fakeChange();
- }
-
- // Circular shift the array range from a[i] to a[j] (inclusive). That is,
- // a[i] -> a[i+1] -> a[i+2] -> ... -> a[j], and a[j] -> a[i]
- private static <T> void circularShiftRight(T[] array, int i, int j) {
- T temp = array[j];
- for (int k = j; k > i; k--) {
- array[k] = array[k - 1];
- }
- array[i] = temp;
- }
-}
diff --git a/src/com/android/gallery3d/data/LocalImage.java b/src/com/android/gallery3d/data/LocalImage.java
deleted file mode 100644
index cc70dd457..000000000
--- a/src/com/android/gallery3d/data/LocalImage.java
+++ /dev/null
@@ -1,355 +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.data;
-
-import android.annotation.TargetApi;
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.database.Cursor;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.BitmapRegionDecoder;
-import android.net.Uri;
-import android.os.Build;
-import android.provider.MediaStore.Images;
-import android.provider.MediaStore.Images.ImageColumns;
-import android.provider.MediaStore.MediaColumns;
-import android.util.Log;
-
-import com.android.gallery3d.app.GalleryApp;
-import com.android.gallery3d.app.PanoramaMetadataSupport;
-import com.android.gallery3d.app.StitchingProgressManager;
-import com.android.gallery3d.common.ApiHelper;
-import com.android.gallery3d.common.BitmapUtils;
-import com.android.gallery3d.exif.ExifInterface;
-import com.android.gallery3d.exif.ExifTag;
-import com.android.gallery3d.filtershow.tools.SaveImage;
-import com.android.gallery3d.util.GalleryUtils;
-import com.android.gallery3d.util.ThreadPool.Job;
-import com.android.gallery3d.util.ThreadPool.JobContext;
-import com.android.gallery3d.util.UpdateHelper;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-
-// LocalImage represents an image in the local storage.
-public class LocalImage extends LocalMediaItem {
- private static final String TAG = "LocalImage";
-
- static final Path ITEM_PATH = Path.fromString("/local/image/item");
-
- // Must preserve order between these indices and the order of the terms in
- // the following PROJECTION array.
- private static final int INDEX_ID = 0;
- private static final int INDEX_CAPTION = 1;
- private static final int INDEX_MIME_TYPE = 2;
- private static final int INDEX_LATITUDE = 3;
- private static final int INDEX_LONGITUDE = 4;
- private static final int INDEX_DATE_TAKEN = 5;
- private static final int INDEX_DATE_ADDED = 6;
- private static final int INDEX_DATE_MODIFIED = 7;
- private static final int INDEX_DATA = 8;
- private static final int INDEX_ORIENTATION = 9;
- private static final int INDEX_BUCKET_ID = 10;
- private static final int INDEX_SIZE = 11;
- private static final int INDEX_WIDTH = 12;
- private static final int INDEX_HEIGHT = 13;
-
- static final String[] PROJECTION = {
- ImageColumns._ID, // 0
- ImageColumns.TITLE, // 1
- ImageColumns.MIME_TYPE, // 2
- ImageColumns.LATITUDE, // 3
- ImageColumns.LONGITUDE, // 4
- ImageColumns.DATE_TAKEN, // 5
- ImageColumns.DATE_ADDED, // 6
- ImageColumns.DATE_MODIFIED, // 7
- ImageColumns.DATA, // 8
- ImageColumns.ORIENTATION, // 9
- ImageColumns.BUCKET_ID, // 10
- ImageColumns.SIZE, // 11
- "0", // 12
- "0" // 13
- };
-
- static {
- updateWidthAndHeightProjection();
- }
-
- @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
- private static void updateWidthAndHeightProjection() {
- if (ApiHelper.HAS_MEDIA_COLUMNS_WIDTH_AND_HEIGHT) {
- PROJECTION[INDEX_WIDTH] = MediaColumns.WIDTH;
- PROJECTION[INDEX_HEIGHT] = MediaColumns.HEIGHT;
- }
- }
-
- private final GalleryApp mApplication;
-
- public int rotation;
-
- private PanoramaMetadataSupport mPanoramaMetadata = new PanoramaMetadataSupport(this);
-
- public LocalImage(Path path, GalleryApp application, Cursor cursor) {
- super(path, nextVersionNumber());
- mApplication = application;
- loadFromCursor(cursor);
- }
-
- public LocalImage(Path path, GalleryApp application, int id) {
- super(path, nextVersionNumber());
- mApplication = application;
- ContentResolver resolver = mApplication.getContentResolver();
- Uri uri = Images.Media.EXTERNAL_CONTENT_URI;
- Cursor cursor = LocalAlbum.getItemCursor(resolver, uri, PROJECTION, id);
- if (cursor == null) {
- throw new RuntimeException("cannot get cursor for: " + path);
- }
- try {
- if (cursor.moveToNext()) {
- loadFromCursor(cursor);
- } else {
- throw new RuntimeException("cannot find data for: " + path);
- }
- } finally {
- cursor.close();
- }
- }
-
- private void loadFromCursor(Cursor cursor) {
- id = cursor.getInt(INDEX_ID);
- caption = cursor.getString(INDEX_CAPTION);
- mimeType = cursor.getString(INDEX_MIME_TYPE);
- latitude = cursor.getDouble(INDEX_LATITUDE);
- longitude = cursor.getDouble(INDEX_LONGITUDE);
- dateTakenInMs = cursor.getLong(INDEX_DATE_TAKEN);
- dateAddedInSec = cursor.getLong(INDEX_DATE_ADDED);
- dateModifiedInSec = cursor.getLong(INDEX_DATE_MODIFIED);
- filePath = cursor.getString(INDEX_DATA);
- rotation = cursor.getInt(INDEX_ORIENTATION);
- bucketId = cursor.getInt(INDEX_BUCKET_ID);
- fileSize = cursor.getLong(INDEX_SIZE);
- width = cursor.getInt(INDEX_WIDTH);
- height = cursor.getInt(INDEX_HEIGHT);
- }
-
- @Override
- protected boolean updateFromCursor(Cursor cursor) {
- UpdateHelper uh = new UpdateHelper();
- id = uh.update(id, cursor.getInt(INDEX_ID));
- caption = uh.update(caption, cursor.getString(INDEX_CAPTION));
- mimeType = uh.update(mimeType, cursor.getString(INDEX_MIME_TYPE));
- latitude = uh.update(latitude, cursor.getDouble(INDEX_LATITUDE));
- longitude = uh.update(longitude, cursor.getDouble(INDEX_LONGITUDE));
- dateTakenInMs = uh.update(
- dateTakenInMs, cursor.getLong(INDEX_DATE_TAKEN));
- dateAddedInSec = uh.update(
- dateAddedInSec, cursor.getLong(INDEX_DATE_ADDED));
- dateModifiedInSec = uh.update(
- dateModifiedInSec, cursor.getLong(INDEX_DATE_MODIFIED));
- filePath = uh.update(filePath, cursor.getString(INDEX_DATA));
- rotation = uh.update(rotation, cursor.getInt(INDEX_ORIENTATION));
- bucketId = uh.update(bucketId, cursor.getInt(INDEX_BUCKET_ID));
- fileSize = uh.update(fileSize, cursor.getLong(INDEX_SIZE));
- width = uh.update(width, cursor.getInt(INDEX_WIDTH));
- height = uh.update(height, cursor.getInt(INDEX_HEIGHT));
- return uh.isUpdated();
- }
-
- @Override
- public Job<Bitmap> requestImage(int type) {
- return new LocalImageRequest(mApplication, mPath, dateModifiedInSec,
- type, filePath);
- }
-
- public static class LocalImageRequest extends ImageCacheRequest {
- private String mLocalFilePath;
-
- LocalImageRequest(GalleryApp application, Path path, long timeModified,
- int type, String localFilePath) {
- super(application, path, timeModified, type,
- MediaItem.getTargetSize(type));
- mLocalFilePath = localFilePath;
- }
-
- @Override
- public Bitmap onDecodeOriginal(JobContext jc, final int type) {
- BitmapFactory.Options options = new BitmapFactory.Options();
- options.inPreferredConfig = Bitmap.Config.ARGB_8888;
- int targetSize = MediaItem.getTargetSize(type);
-
- // try to decode from JPEG EXIF
- if (type == MediaItem.TYPE_MICROTHUMBNAIL) {
- ExifInterface exif = new ExifInterface();
- byte[] thumbData = null;
- try {
- exif.readExif(mLocalFilePath);
- thumbData = exif.getThumbnail();
- } catch (FileNotFoundException e) {
- Log.w(TAG, "failed to find file to read thumbnail: " + mLocalFilePath);
- } catch (IOException e) {
- Log.w(TAG, "failed to get thumbnail from: " + mLocalFilePath);
- }
- if (thumbData != null) {
- Bitmap bitmap = DecodeUtils.decodeIfBigEnough(
- jc, thumbData, options, targetSize);
- if (bitmap != null) return bitmap;
- }
- }
-
- return DecodeUtils.decodeThumbnail(jc, mLocalFilePath, options, targetSize, type);
- }
- }
-
- @Override
- public Job<BitmapRegionDecoder> requestLargeImage() {
- return new LocalLargeImageRequest(filePath);
- }
-
- public static class LocalLargeImageRequest
- implements Job<BitmapRegionDecoder> {
- String mLocalFilePath;
-
- public LocalLargeImageRequest(String localFilePath) {
- mLocalFilePath = localFilePath;
- }
-
- @Override
- public BitmapRegionDecoder run(JobContext jc) {
- return DecodeUtils.createBitmapRegionDecoder(jc, mLocalFilePath, false);
- }
- }
-
- @Override
- public int getSupportedOperations() {
- StitchingProgressManager progressManager = mApplication.getStitchingProgressManager();
- if (progressManager != null && progressManager.getProgress(getContentUri()) != null) {
- return 0; // doesn't support anything while stitching!
- }
- int operation = SUPPORT_DELETE | SUPPORT_SHARE | SUPPORT_CROP
- | SUPPORT_SETAS | SUPPORT_EDIT | SUPPORT_INFO;
- if (BitmapUtils.isSupportedByRegionDecoder(mimeType)) {
- operation |= SUPPORT_FULL_IMAGE;
- }
-
- if (BitmapUtils.isRotationSupported(mimeType)) {
- operation |= SUPPORT_ROTATE;
- }
-
- if (GalleryUtils.isValidLocation(latitude, longitude)) {
- operation |= SUPPORT_SHOW_ON_MAP;
- }
- return operation;
- }
-
- @Override
- public void getPanoramaSupport(PanoramaSupportCallback callback) {
- mPanoramaMetadata.getPanoramaSupport(mApplication, callback);
- }
-
- @Override
- public void clearCachedPanoramaSupport() {
- mPanoramaMetadata.clearCachedValues();
- }
-
- @Override
- public void delete() {
- GalleryUtils.assertNotInRenderThread();
- Uri baseUri = Images.Media.EXTERNAL_CONTENT_URI;
- ContentResolver contentResolver = mApplication.getContentResolver();
- SaveImage.deleteAuxFiles(contentResolver, getContentUri());
- contentResolver.delete(baseUri, "_id=?",
- new String[]{String.valueOf(id)});
- }
-
- @Override
- public void rotate(int degrees) {
- GalleryUtils.assertNotInRenderThread();
- Uri baseUri = Images.Media.EXTERNAL_CONTENT_URI;
- ContentValues values = new ContentValues();
- int rotation = (this.rotation + degrees) % 360;
- if (rotation < 0) rotation += 360;
-
- if (mimeType.equalsIgnoreCase("image/jpeg")) {
- ExifInterface exifInterface = new ExifInterface();
- ExifTag tag = exifInterface.buildTag(ExifInterface.TAG_ORIENTATION,
- ExifInterface.getOrientationValueForRotation(rotation));
- if(tag != null) {
- exifInterface.setTag(tag);
- try {
- exifInterface.forceRewriteExif(filePath);
- fileSize = new File(filePath).length();
- values.put(Images.Media.SIZE, fileSize);
- } catch (FileNotFoundException e) {
- Log.w(TAG, "cannot find file to set exif: " + filePath);
- } catch (IOException e) {
- Log.w(TAG, "cannot set exif data: " + filePath);
- }
- } else {
- Log.w(TAG, "Could not build tag: " + ExifInterface.TAG_ORIENTATION);
- }
- }
-
- values.put(Images.Media.ORIENTATION, rotation);
- mApplication.getContentResolver().update(baseUri, values, "_id=?",
- new String[]{String.valueOf(id)});
- }
-
- @Override
- public Uri getContentUri() {
- Uri baseUri = Images.Media.EXTERNAL_CONTENT_URI;
- return baseUri.buildUpon().appendPath(String.valueOf(id)).build();
- }
-
- @Override
- public int getMediaType() {
- return MEDIA_TYPE_IMAGE;
- }
-
- @Override
- public MediaDetails getDetails() {
- MediaDetails details = super.getDetails();
- details.addDetail(MediaDetails.INDEX_ORIENTATION, Integer.valueOf(rotation));
- if (MIME_TYPE_JPEG.equals(mimeType)) {
- // ExifInterface returns incorrect values for photos in other format.
- // For example, the width and height of an webp images is always '0'.
- MediaDetails.extractExifInfo(details, filePath);
- }
- return details;
- }
-
- @Override
- public int getRotation() {
- return rotation;
- }
-
- @Override
- public int getWidth() {
- return width;
- }
-
- @Override
- public int getHeight() {
- return height;
- }
-
- @Override
- public String getFilePath() {
- return filePath;
- }
-}
diff --git a/src/com/android/gallery3d/data/LocalMediaItem.java b/src/com/android/gallery3d/data/LocalMediaItem.java
deleted file mode 100644
index 7e003cd3a..000000000
--- a/src/com/android/gallery3d/data/LocalMediaItem.java
+++ /dev/null
@@ -1,109 +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.data;
-
-import android.database.Cursor;
-
-import com.android.gallery3d.util.GalleryUtils;
-
-import java.text.DateFormat;
-import java.util.Date;
-
-//
-// LocalMediaItem is an abstract class captures those common fields
-// in LocalImage and LocalVideo.
-//
-public abstract class LocalMediaItem extends MediaItem {
-
- @SuppressWarnings("unused")
- private static final String TAG = "LocalMediaItem";
-
- // database fields
- public int id;
- public String caption;
- public String mimeType;
- public long fileSize;
- public double latitude = INVALID_LATLNG;
- public double longitude = INVALID_LATLNG;
- public long dateTakenInMs;
- public long dateAddedInSec;
- public long dateModifiedInSec;
- public String filePath;
- public int bucketId;
- public int width;
- public int height;
-
- public LocalMediaItem(Path path, long version) {
- super(path, version);
- }
-
- @Override
- public long getDateInMs() {
- return dateTakenInMs;
- }
-
- @Override
- public String getName() {
- return caption;
- }
-
- @Override
- public void getLatLong(double[] latLong) {
- latLong[0] = latitude;
- latLong[1] = longitude;
- }
-
- abstract protected boolean updateFromCursor(Cursor cursor);
-
- public int getBucketId() {
- return bucketId;
- }
-
- protected void updateContent(Cursor cursor) {
- if (updateFromCursor(cursor)) {
- mDataVersion = nextVersionNumber();
- }
- }
-
- @Override
- public MediaDetails getDetails() {
- MediaDetails details = super.getDetails();
- details.addDetail(MediaDetails.INDEX_PATH, filePath);
- details.addDetail(MediaDetails.INDEX_TITLE, caption);
- DateFormat formater = DateFormat.getDateTimeInstance();
- details.addDetail(MediaDetails.INDEX_DATETIME,
- formater.format(new Date(dateModifiedInSec * 1000)));
- details.addDetail(MediaDetails.INDEX_WIDTH, width);
- details.addDetail(MediaDetails.INDEX_HEIGHT, height);
-
- if (GalleryUtils.isValidLocation(latitude, longitude)) {
- details.addDetail(MediaDetails.INDEX_LOCATION, new double[] {latitude, longitude});
- }
- if (fileSize > 0) details.addDetail(MediaDetails.INDEX_SIZE, fileSize);
- return details;
- }
-
- @Override
- public String getMimeType() {
- return mimeType;
- }
-
- @Override
- public long getSize() {
- return fileSize;
- }
-}
diff --git a/src/com/android/gallery3d/data/LocalMergeAlbum.java b/src/com/android/gallery3d/data/LocalMergeAlbum.java
deleted file mode 100644
index f0b5e5726..000000000
--- a/src/com/android/gallery3d/data/LocalMergeAlbum.java
+++ /dev/null
@@ -1,257 +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.data;
-
-import android.net.Uri;
-import android.provider.MediaStore;
-
-import com.android.gallery3d.common.ApiHelper;
-
-import java.lang.ref.SoftReference;
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.NoSuchElementException;
-import java.util.SortedMap;
-import java.util.TreeMap;
-
-// MergeAlbum merges items from two or more MediaSets. It uses a Comparator to
-// determine the order of items. The items are assumed to be sorted in the input
-// media sets (with the same order that the Comparator uses).
-//
-// This only handles MediaItems, not SubMediaSets.
-public class LocalMergeAlbum extends MediaSet implements ContentListener {
- @SuppressWarnings("unused")
- private static final String TAG = "LocalMergeAlbum";
- private static final int PAGE_SIZE = 64;
-
- private final Comparator<MediaItem> mComparator;
- private final MediaSet[] mSources;
-
- private FetchCache[] mFetcher;
- private int mSupportedOperation;
- private int mBucketId;
-
- // mIndex maps global position to the position of each underlying media sets.
- private TreeMap<Integer, int[]> mIndex = new TreeMap<Integer, int[]>();
-
- public LocalMergeAlbum(
- Path path, Comparator<MediaItem> comparator, MediaSet[] sources, int bucketId) {
- super(path, INVALID_DATA_VERSION);
- mComparator = comparator;
- mSources = sources;
- mBucketId = bucketId;
- for (MediaSet set : mSources) {
- set.addContentListener(this);
- }
- reload();
- }
-
- @Override
- public boolean isCameraRoll() {
- if (mSources.length == 0) return false;
- for(MediaSet set : mSources) {
- if (!set.isCameraRoll()) return false;
- }
- return true;
- }
-
- private void updateData() {
- ArrayList<MediaSet> matches = new ArrayList<MediaSet>();
- int supported = mSources.length == 0 ? 0 : MediaItem.SUPPORT_ALL;
- mFetcher = new FetchCache[mSources.length];
- for (int i = 0, n = mSources.length; i < n; ++i) {
- mFetcher[i] = new FetchCache(mSources[i]);
- supported &= mSources[i].getSupportedOperations();
- }
- mSupportedOperation = supported;
- mIndex.clear();
- mIndex.put(0, new int[mSources.length]);
- }
-
- private void invalidateCache() {
- for (int i = 0, n = mSources.length; i < n; i++) {
- mFetcher[i].invalidate();
- }
- mIndex.clear();
- mIndex.put(0, new int[mSources.length]);
- }
-
- @Override
- public Uri getContentUri() {
- String bucketId = String.valueOf(mBucketId);
- if (ApiHelper.HAS_MEDIA_PROVIDER_FILES_TABLE) {
- return MediaStore.Files.getContentUri("external").buildUpon()
- .appendQueryParameter(LocalSource.KEY_BUCKET_ID, bucketId)
- .build();
- } else {
- // We don't have a single URL for a merged image before ICS
- // So we used the image's URL as a substitute.
- return MediaStore.Images.Media.EXTERNAL_CONTENT_URI.buildUpon()
- .appendQueryParameter(LocalSource.KEY_BUCKET_ID, bucketId)
- .build();
- }
- }
-
- @Override
- public String getName() {
- return mSources.length == 0 ? "" : mSources[0].getName();
- }
-
- @Override
- public int getMediaItemCount() {
- return getTotalMediaItemCount();
- }
-
- @Override
- public ArrayList<MediaItem> getMediaItem(int start, int count) {
-
- // First find the nearest mark position <= start.
- SortedMap<Integer, int[]> head = mIndex.headMap(start + 1);
- int markPos = head.lastKey();
- int[] subPos = head.get(markPos).clone();
- MediaItem[] slot = new MediaItem[mSources.length];
-
- int size = mSources.length;
-
- // fill all slots
- for (int i = 0; i < size; i++) {
- slot[i] = mFetcher[i].getItem(subPos[i]);
- }
-
- ArrayList<MediaItem> result = new ArrayList<MediaItem>();
-
- for (int i = markPos; i < start + count; i++) {
- int k = -1; // k points to the best slot up to now.
- for (int j = 0; j < size; j++) {
- if (slot[j] != null) {
- if (k == -1 || mComparator.compare(slot[j], slot[k]) < 0) {
- k = j;
- }
- }
- }
-
- // If we don't have anything, all streams are exhausted.
- if (k == -1) break;
-
- // Pick the best slot and refill it.
- subPos[k]++;
- if (i >= start) {
- result.add(slot[k]);
- }
- slot[k] = mFetcher[k].getItem(subPos[k]);
-
- // Periodically leave a mark in the index, so we can come back later.
- if ((i + 1) % PAGE_SIZE == 0) {
- mIndex.put(i + 1, subPos.clone());
- }
- }
-
- return result;
- }
-
- @Override
- public int getTotalMediaItemCount() {
- int count = 0;
- for (MediaSet set : mSources) {
- count += set.getTotalMediaItemCount();
- }
- return count;
- }
-
- @Override
- public long reload() {
- boolean changed = false;
- for (int i = 0, n = mSources.length; i < n; ++i) {
- if (mSources[i].reload() > mDataVersion) changed = true;
- }
- if (changed) {
- mDataVersion = nextVersionNumber();
- updateData();
- invalidateCache();
- }
- return mDataVersion;
- }
-
- @Override
- public void onContentDirty() {
- notifyContentChanged();
- }
-
- @Override
- public int getSupportedOperations() {
- return mSupportedOperation;
- }
-
- @Override
- public void delete() {
- for (MediaSet set : mSources) {
- set.delete();
- }
- }
-
- @Override
- public void rotate(int degrees) {
- for (MediaSet set : mSources) {
- set.rotate(degrees);
- }
- }
-
- private static class FetchCache {
- private MediaSet mBaseSet;
- private SoftReference<ArrayList<MediaItem>> mCacheRef;
- private int mStartPos;
-
- public FetchCache(MediaSet baseSet) {
- mBaseSet = baseSet;
- }
-
- public void invalidate() {
- mCacheRef = null;
- }
-
- public MediaItem getItem(int index) {
- boolean needLoading = false;
- ArrayList<MediaItem> cache = null;
- if (mCacheRef == null
- || index < mStartPos || index >= mStartPos + PAGE_SIZE) {
- needLoading = true;
- } else {
- cache = mCacheRef.get();
- if (cache == null) {
- needLoading = true;
- }
- }
-
- if (needLoading) {
- cache = mBaseSet.getMediaItem(index, PAGE_SIZE);
- mCacheRef = new SoftReference<ArrayList<MediaItem>>(cache);
- mStartPos = index;
- }
-
- if (index < mStartPos || index >= mStartPos + cache.size()) {
- return null;
- }
-
- return cache.get(index - mStartPos);
- }
- }
-
- @Override
- public boolean isLeafAlbum() {
- return true;
- }
-}
diff --git a/src/com/android/gallery3d/data/LocalSource.java b/src/com/android/gallery3d/data/LocalSource.java
deleted file mode 100644
index a2e3d1443..000000000
--- a/src/com/android/gallery3d/data/LocalSource.java
+++ /dev/null
@@ -1,275 +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.data;
-
-import android.content.ContentProviderClient;
-import android.content.ContentUris;
-import android.content.UriMatcher;
-import android.net.Uri;
-import android.provider.MediaStore;
-
-import com.android.gallery3d.app.Gallery;
-import com.android.gallery3d.app.GalleryApp;
-import com.android.gallery3d.data.MediaSet.ItemConsumer;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-
-class LocalSource extends MediaSource {
-
- public static final String KEY_BUCKET_ID = "bucketId";
-
- private GalleryApp mApplication;
- private PathMatcher mMatcher;
- private static final int NO_MATCH = -1;
- private final UriMatcher mUriMatcher = new UriMatcher(NO_MATCH);
- public static final Comparator<PathId> sIdComparator = new IdComparator();
-
- private static final int LOCAL_IMAGE_ALBUMSET = 0;
- private static final int LOCAL_VIDEO_ALBUMSET = 1;
- private static final int LOCAL_IMAGE_ALBUM = 2;
- private static final int LOCAL_VIDEO_ALBUM = 3;
- private static final int LOCAL_IMAGE_ITEM = 4;
- private static final int LOCAL_VIDEO_ITEM = 5;
- private static final int LOCAL_ALL_ALBUMSET = 6;
- private static final int LOCAL_ALL_ALBUM = 7;
-
- private static final String TAG = "LocalSource";
-
- private ContentProviderClient mClient;
-
- public LocalSource(GalleryApp context) {
- super("local");
- mApplication = context;
- mMatcher = new PathMatcher();
- mMatcher.add("/local/image", LOCAL_IMAGE_ALBUMSET);
- mMatcher.add("/local/video", LOCAL_VIDEO_ALBUMSET);
- mMatcher.add("/local/all", LOCAL_ALL_ALBUMSET);
-
- mMatcher.add("/local/image/*", LOCAL_IMAGE_ALBUM);
- mMatcher.add("/local/video/*", LOCAL_VIDEO_ALBUM);
- mMatcher.add("/local/all/*", LOCAL_ALL_ALBUM);
- mMatcher.add("/local/image/item/*", LOCAL_IMAGE_ITEM);
- mMatcher.add("/local/video/item/*", LOCAL_VIDEO_ITEM);
-
- mUriMatcher.addURI(MediaStore.AUTHORITY,
- "external/images/media/#", LOCAL_IMAGE_ITEM);
- mUriMatcher.addURI(MediaStore.AUTHORITY,
- "external/video/media/#", LOCAL_VIDEO_ITEM);
- mUriMatcher.addURI(MediaStore.AUTHORITY,
- "external/images/media", LOCAL_IMAGE_ALBUM);
- mUriMatcher.addURI(MediaStore.AUTHORITY,
- "external/video/media", LOCAL_VIDEO_ALBUM);
- mUriMatcher.addURI(MediaStore.AUTHORITY,
- "external/file", LOCAL_ALL_ALBUM);
- }
-
- @Override
- public MediaObject createMediaObject(Path path) {
- GalleryApp app = mApplication;
- switch (mMatcher.match(path)) {
- case LOCAL_ALL_ALBUMSET:
- case LOCAL_IMAGE_ALBUMSET:
- case LOCAL_VIDEO_ALBUMSET:
- return new LocalAlbumSet(path, mApplication);
- case LOCAL_IMAGE_ALBUM:
- return new LocalAlbum(path, app, mMatcher.getIntVar(0), true);
- case LOCAL_VIDEO_ALBUM:
- return new LocalAlbum(path, app, mMatcher.getIntVar(0), false);
- case LOCAL_ALL_ALBUM: {
- int bucketId = mMatcher.getIntVar(0);
- DataManager dataManager = app.getDataManager();
- MediaSet imageSet = (MediaSet) dataManager.getMediaObject(
- LocalAlbumSet.PATH_IMAGE.getChild(bucketId));
- MediaSet videoSet = (MediaSet) dataManager.getMediaObject(
- LocalAlbumSet.PATH_VIDEO.getChild(bucketId));
- Comparator<MediaItem> comp = DataManager.sDateTakenComparator;
- return new LocalMergeAlbum(
- path, comp, new MediaSet[] {imageSet, videoSet}, bucketId);
- }
- case LOCAL_IMAGE_ITEM:
- return new LocalImage(path, mApplication, mMatcher.getIntVar(0));
- case LOCAL_VIDEO_ITEM:
- return new LocalVideo(path, mApplication, mMatcher.getIntVar(0));
- default:
- throw new RuntimeException("bad path: " + path);
- }
- }
-
- private static int getMediaType(String type, int defaultType) {
- if (type == null) return defaultType;
- try {
- int value = Integer.parseInt(type);
- if ((value & (MEDIA_TYPE_IMAGE
- | MEDIA_TYPE_VIDEO)) != 0) return value;
- } catch (NumberFormatException e) {
- Log.w(TAG, "invalid type: " + type, e);
- }
- return defaultType;
- }
-
- // The media type bit passed by the intent
- private static final int MEDIA_TYPE_ALL = 0;
- private static final int MEDIA_TYPE_IMAGE = 1;
- private static final int MEDIA_TYPE_VIDEO = 4;
-
- private Path getAlbumPath(Uri uri, int defaultType) {
- int mediaType = getMediaType(
- uri.getQueryParameter(Gallery.KEY_MEDIA_TYPES),
- defaultType);
- String bucketId = uri.getQueryParameter(KEY_BUCKET_ID);
- int id = 0;
- try {
- id = Integer.parseInt(bucketId);
- } catch (NumberFormatException e) {
- Log.w(TAG, "invalid bucket id: " + bucketId, e);
- return null;
- }
- switch (mediaType) {
- case MEDIA_TYPE_IMAGE:
- return Path.fromString("/local/image").getChild(id);
- case MEDIA_TYPE_VIDEO:
- return Path.fromString("/local/video").getChild(id);
- default:
- return Path.fromString("/local/all").getChild(id);
- }
- }
-
- @Override
- public Path findPathByUri(Uri uri, String type) {
- try {
- switch (mUriMatcher.match(uri)) {
- case LOCAL_IMAGE_ITEM: {
- long id = ContentUris.parseId(uri);
- return id >= 0 ? LocalImage.ITEM_PATH.getChild(id) : null;
- }
- case LOCAL_VIDEO_ITEM: {
- long id = ContentUris.parseId(uri);
- return id >= 0 ? LocalVideo.ITEM_PATH.getChild(id) : null;
- }
- case LOCAL_IMAGE_ALBUM: {
- return getAlbumPath(uri, MEDIA_TYPE_IMAGE);
- }
- case LOCAL_VIDEO_ALBUM: {
- return getAlbumPath(uri, MEDIA_TYPE_VIDEO);
- }
- case LOCAL_ALL_ALBUM: {
- return getAlbumPath(uri, MEDIA_TYPE_ALL);
- }
- }
- } catch (NumberFormatException e) {
- Log.w(TAG, "uri: " + uri.toString(), e);
- }
- return null;
- }
-
- @Override
- public Path getDefaultSetOf(Path item) {
- MediaObject object = mApplication.getDataManager().getMediaObject(item);
- if (object instanceof LocalMediaItem) {
- return Path.fromString("/local/all").getChild(
- String.valueOf(((LocalMediaItem) object).getBucketId()));
- }
- return null;
- }
-
- @Override
- public void mapMediaItems(ArrayList<PathId> list, ItemConsumer consumer) {
- ArrayList<PathId> imageList = new ArrayList<PathId>();
- ArrayList<PathId> videoList = new ArrayList<PathId>();
- int n = list.size();
- for (int i = 0; i < n; i++) {
- PathId pid = list.get(i);
- // We assume the form is: "/local/{image,video}/item/#"
- // We don't use mMatcher for efficiency's reason.
- Path parent = pid.path.getParent();
- if (parent == LocalImage.ITEM_PATH) {
- imageList.add(pid);
- } else if (parent == LocalVideo.ITEM_PATH) {
- videoList.add(pid);
- }
- }
- // TODO: use "files" table so we can merge the two cases.
- processMapMediaItems(imageList, consumer, true);
- processMapMediaItems(videoList, consumer, false);
- }
-
- private void processMapMediaItems(ArrayList<PathId> list,
- ItemConsumer consumer, boolean isImage) {
- // Sort path by path id
- Collections.sort(list, sIdComparator);
- int n = list.size();
- for (int i = 0; i < n; ) {
- PathId pid = list.get(i);
-
- // Find a range of items.
- ArrayList<Integer> ids = new ArrayList<Integer>();
- int startId = Integer.parseInt(pid.path.getSuffix());
- ids.add(startId);
-
- int j;
- for (j = i + 1; j < n; j++) {
- PathId pid2 = list.get(j);
- int curId = Integer.parseInt(pid2.path.getSuffix());
- if (curId - startId >= MediaSet.MEDIAITEM_BATCH_FETCH_COUNT) {
- break;
- }
- ids.add(curId);
- }
-
- MediaItem[] items = LocalAlbum.getMediaItemById(
- mApplication, isImage, ids);
- for(int k = i ; k < j; k++) {
- PathId pid2 = list.get(k);
- consumer.consume(pid2.id, items[k - i]);
- }
-
- i = j;
- }
- }
-
- // This is a comparator which compares the suffix number in two Paths.
- private static class IdComparator implements Comparator<PathId> {
- @Override
- public int compare(PathId p1, PathId p2) {
- String s1 = p1.path.getSuffix();
- String s2 = p2.path.getSuffix();
- int len1 = s1.length();
- int len2 = s2.length();
- if (len1 < len2) {
- return -1;
- } else if (len1 > len2) {
- return 1;
- } else {
- return s1.compareTo(s2);
- }
- }
- }
-
- @Override
- public void resume() {
- mClient = mApplication.getContentResolver()
- .acquireContentProviderClient(MediaStore.AUTHORITY);
- }
-
- @Override
- public void pause() {
- mClient.release();
- mClient = null;
- }
-}
diff --git a/src/com/android/gallery3d/data/LocalVideo.java b/src/com/android/gallery3d/data/LocalVideo.java
deleted file mode 100644
index 4b8774ca4..000000000
--- a/src/com/android/gallery3d/data/LocalVideo.java
+++ /dev/null
@@ -1,242 +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.data;
-
-import android.content.ContentResolver;
-import android.database.Cursor;
-import android.graphics.Bitmap;
-import android.graphics.BitmapRegionDecoder;
-import android.net.Uri;
-import android.provider.MediaStore.Video;
-import android.provider.MediaStore.Video.VideoColumns;
-
-import com.android.gallery3d.app.GalleryApp;
-import com.android.gallery3d.common.BitmapUtils;
-import com.android.gallery3d.util.GalleryUtils;
-import com.android.gallery3d.util.ThreadPool.Job;
-import com.android.gallery3d.util.ThreadPool.JobContext;
-import com.android.gallery3d.util.UpdateHelper;
-
-// LocalVideo represents a video in the local storage.
-public class LocalVideo extends LocalMediaItem {
- private static final String TAG = "LocalVideo";
- static final Path ITEM_PATH = Path.fromString("/local/video/item");
-
- // Must preserve order between these indices and the order of the terms in
- // the following PROJECTION array.
- private static final int INDEX_ID = 0;
- private static final int INDEX_CAPTION = 1;
- private static final int INDEX_MIME_TYPE = 2;
- private static final int INDEX_LATITUDE = 3;
- private static final int INDEX_LONGITUDE = 4;
- private static final int INDEX_DATE_TAKEN = 5;
- private static final int INDEX_DATE_ADDED = 6;
- private static final int INDEX_DATE_MODIFIED = 7;
- private static final int INDEX_DATA = 8;
- private static final int INDEX_DURATION = 9;
- private static final int INDEX_BUCKET_ID = 10;
- private static final int INDEX_SIZE = 11;
- private static final int INDEX_RESOLUTION = 12;
-
- static final String[] PROJECTION = new String[] {
- VideoColumns._ID,
- VideoColumns.TITLE,
- VideoColumns.MIME_TYPE,
- VideoColumns.LATITUDE,
- VideoColumns.LONGITUDE,
- VideoColumns.DATE_TAKEN,
- VideoColumns.DATE_ADDED,
- VideoColumns.DATE_MODIFIED,
- VideoColumns.DATA,
- VideoColumns.DURATION,
- VideoColumns.BUCKET_ID,
- VideoColumns.SIZE,
- VideoColumns.RESOLUTION,
- };
-
- private final GalleryApp mApplication;
-
- public int durationInSec;
-
- public LocalVideo(Path path, GalleryApp application, Cursor cursor) {
- super(path, nextVersionNumber());
- mApplication = application;
- loadFromCursor(cursor);
- }
-
- public LocalVideo(Path path, GalleryApp context, int id) {
- super(path, nextVersionNumber());
- mApplication = context;
- ContentResolver resolver = mApplication.getContentResolver();
- Uri uri = Video.Media.EXTERNAL_CONTENT_URI;
- Cursor cursor = LocalAlbum.getItemCursor(resolver, uri, PROJECTION, id);
- if (cursor == null) {
- throw new RuntimeException("cannot get cursor for: " + path);
- }
- try {
- if (cursor.moveToNext()) {
- loadFromCursor(cursor);
- } else {
- throw new RuntimeException("cannot find data for: " + path);
- }
- } finally {
- cursor.close();
- }
- }
-
- private void loadFromCursor(Cursor cursor) {
- id = cursor.getInt(INDEX_ID);
- caption = cursor.getString(INDEX_CAPTION);
- mimeType = cursor.getString(INDEX_MIME_TYPE);
- latitude = cursor.getDouble(INDEX_LATITUDE);
- longitude = cursor.getDouble(INDEX_LONGITUDE);
- dateTakenInMs = cursor.getLong(INDEX_DATE_TAKEN);
- dateAddedInSec = cursor.getLong(INDEX_DATE_ADDED);
- dateModifiedInSec = cursor.getLong(INDEX_DATE_MODIFIED);
- filePath = cursor.getString(INDEX_DATA);
- durationInSec = cursor.getInt(INDEX_DURATION) / 1000;
- bucketId = cursor.getInt(INDEX_BUCKET_ID);
- fileSize = cursor.getLong(INDEX_SIZE);
- parseResolution(cursor.getString(INDEX_RESOLUTION));
- }
-
- private void parseResolution(String resolution) {
- if (resolution == null) return;
- int m = resolution.indexOf('x');
- if (m == -1) return;
- try {
- int w = Integer.parseInt(resolution.substring(0, m));
- int h = Integer.parseInt(resolution.substring(m + 1));
- width = w;
- height = h;
- } catch (Throwable t) {
- Log.w(TAG, t);
- }
- }
-
- @Override
- protected boolean updateFromCursor(Cursor cursor) {
- UpdateHelper uh = new UpdateHelper();
- id = uh.update(id, cursor.getInt(INDEX_ID));
- caption = uh.update(caption, cursor.getString(INDEX_CAPTION));
- mimeType = uh.update(mimeType, cursor.getString(INDEX_MIME_TYPE));
- latitude = uh.update(latitude, cursor.getDouble(INDEX_LATITUDE));
- longitude = uh.update(longitude, cursor.getDouble(INDEX_LONGITUDE));
- dateTakenInMs = uh.update(
- dateTakenInMs, cursor.getLong(INDEX_DATE_TAKEN));
- dateAddedInSec = uh.update(
- dateAddedInSec, cursor.getLong(INDEX_DATE_ADDED));
- dateModifiedInSec = uh.update(
- dateModifiedInSec, cursor.getLong(INDEX_DATE_MODIFIED));
- filePath = uh.update(filePath, cursor.getString(INDEX_DATA));
- durationInSec = uh.update(
- durationInSec, cursor.getInt(INDEX_DURATION) / 1000);
- bucketId = uh.update(bucketId, cursor.getInt(INDEX_BUCKET_ID));
- fileSize = uh.update(fileSize, cursor.getLong(INDEX_SIZE));
- return uh.isUpdated();
- }
-
- @Override
- public Job<Bitmap> requestImage(int type) {
- return new LocalVideoRequest(mApplication, getPath(), dateModifiedInSec,
- type, filePath);
- }
-
- public static class LocalVideoRequest extends ImageCacheRequest {
- private String mLocalFilePath;
-
- LocalVideoRequest(GalleryApp application, Path path, long timeModified,
- int type, String localFilePath) {
- super(application, path, timeModified, type,
- MediaItem.getTargetSize(type));
- mLocalFilePath = localFilePath;
- }
-
- @Override
- public Bitmap onDecodeOriginal(JobContext jc, int type) {
- Bitmap bitmap = BitmapUtils.createVideoThumbnail(mLocalFilePath);
- if (bitmap == null || jc.isCancelled()) return null;
- return bitmap;
- }
- }
-
- @Override
- public Job<BitmapRegionDecoder> requestLargeImage() {
- throw new UnsupportedOperationException("Cannot regquest a large image"
- + " to a local video!");
- }
-
- @Override
- public int getSupportedOperations() {
- return SUPPORT_DELETE | SUPPORT_SHARE | SUPPORT_PLAY | SUPPORT_INFO | SUPPORT_TRIM | SUPPORT_MUTE;
- }
-
- @Override
- public void delete() {
- GalleryUtils.assertNotInRenderThread();
- Uri baseUri = Video.Media.EXTERNAL_CONTENT_URI;
- mApplication.getContentResolver().delete(baseUri, "_id=?",
- new String[]{String.valueOf(id)});
- }
-
- @Override
- public void rotate(int degrees) {
- // TODO
- }
-
- @Override
- public Uri getContentUri() {
- Uri baseUri = Video.Media.EXTERNAL_CONTENT_URI;
- return baseUri.buildUpon().appendPath(String.valueOf(id)).build();
- }
-
- @Override
- public Uri getPlayUri() {
- return getContentUri();
- }
-
- @Override
- public int getMediaType() {
- return MEDIA_TYPE_VIDEO;
- }
-
- @Override
- public MediaDetails getDetails() {
- MediaDetails details = super.getDetails();
- int s = durationInSec;
- if (s > 0) {
- details.addDetail(MediaDetails.INDEX_DURATION, GalleryUtils.formatDuration(
- mApplication.getAndroidContext(), durationInSec));
- }
- return details;
- }
-
- @Override
- public int getWidth() {
- return width;
- }
-
- @Override
- public int getHeight() {
- return height;
- }
-
- @Override
- public String getFilePath() {
- return filePath;
- }
-}
diff --git a/src/com/android/gallery3d/data/LocationClustering.java b/src/com/android/gallery3d/data/LocationClustering.java
deleted file mode 100644
index 540322a33..000000000
--- a/src/com/android/gallery3d/data/LocationClustering.java
+++ /dev/null
@@ -1,316 +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.data;
-
-import android.content.Context;
-import android.os.Handler;
-import android.os.Looper;
-import android.util.FloatMath;
-import android.widget.Toast;
-
-import com.android.gallery3d.R;
-import com.android.gallery3d.util.GalleryUtils;
-import com.android.gallery3d.util.ReverseGeocoder;
-
-import java.util.ArrayList;
-
-class LocationClustering extends Clustering {
- @SuppressWarnings("unused")
- private static final String TAG = "LocationClustering";
-
- private static final int MIN_GROUPS = 1;
- private static final int MAX_GROUPS = 20;
- private static final int MAX_ITERATIONS = 30;
-
- // If the total distance change is less than this ratio, stop iterating.
- private static final float STOP_CHANGE_RATIO = 0.01f;
- private Context mContext;
- private ArrayList<ArrayList<SmallItem>> mClusters;
- private ArrayList<String> mNames;
- private String mNoLocationString;
- private Handler mHandler;
-
- private static class Point {
- public Point(double lat, double lng) {
- latRad = Math.toRadians(lat);
- lngRad = Math.toRadians(lng);
- }
- public Point() {}
- public double latRad, lngRad;
- }
-
- private static class SmallItem {
- Path path;
- double lat, lng;
- }
-
- public LocationClustering(Context context) {
- mContext = context;
- mNoLocationString = mContext.getResources().getString(R.string.no_location);
- mHandler = new Handler(Looper.getMainLooper());
- }
-
- @Override
- public void run(MediaSet baseSet) {
- final int total = baseSet.getTotalMediaItemCount();
- final SmallItem[] buf = new SmallItem[total];
- // Separate items to two sets: with or without lat-long.
- final double[] latLong = new double[2];
- baseSet.enumerateTotalMediaItems(new MediaSet.ItemConsumer() {
- @Override
- public void consume(int index, MediaItem item) {
- if (index < 0 || index >= total) return;
- SmallItem s = new SmallItem();
- s.path = item.getPath();
- item.getLatLong(latLong);
- s.lat = latLong[0];
- s.lng = latLong[1];
- buf[index] = s;
- }
- });
-
- final ArrayList<SmallItem> withLatLong = new ArrayList<SmallItem>();
- final ArrayList<SmallItem> withoutLatLong = new ArrayList<SmallItem>();
- final ArrayList<Point> points = new ArrayList<Point>();
- for (int i = 0; i < total; i++) {
- SmallItem s = buf[i];
- if (s == null) continue;
- if (GalleryUtils.isValidLocation(s.lat, s.lng)) {
- withLatLong.add(s);
- points.add(new Point(s.lat, s.lng));
- } else {
- withoutLatLong.add(s);
- }
- }
-
- ArrayList<ArrayList<SmallItem>> clusters = new ArrayList<ArrayList<SmallItem>>();
-
- int m = withLatLong.size();
- if (m > 0) {
- // cluster the items with lat-long
- Point[] pointsArray = new Point[m];
- pointsArray = points.toArray(pointsArray);
- int[] bestK = new int[1];
- int[] index = kMeans(pointsArray, bestK);
-
- for (int i = 0; i < bestK[0]; i++) {
- clusters.add(new ArrayList<SmallItem>());
- }
-
- for (int i = 0; i < m; i++) {
- clusters.get(index[i]).add(withLatLong.get(i));
- }
- }
-
- ReverseGeocoder geocoder = new ReverseGeocoder(mContext);
- mNames = new ArrayList<String>();
- boolean hasUnresolvedAddress = false;
- mClusters = new ArrayList<ArrayList<SmallItem>>();
- for (ArrayList<SmallItem> cluster : clusters) {
- String name = generateName(cluster, geocoder);
- if (name != null) {
- mNames.add(name);
- mClusters.add(cluster);
- } else {
- // move cluster-i to no location cluster
- withoutLatLong.addAll(cluster);
- hasUnresolvedAddress = true;
- }
- }
-
- if (withoutLatLong.size() > 0) {
- mNames.add(mNoLocationString);
- mClusters.add(withoutLatLong);
- }
-
- if (hasUnresolvedAddress) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- Toast.makeText(mContext, R.string.no_connectivity,
- Toast.LENGTH_LONG).show();
- }
- });
- }
- }
-
- private static String generateName(ArrayList<SmallItem> items,
- ReverseGeocoder geocoder) {
- ReverseGeocoder.SetLatLong set = new ReverseGeocoder.SetLatLong();
-
- int n = items.size();
- for (int i = 0; i < n; i++) {
- SmallItem item = items.get(i);
- double itemLatitude = item.lat;
- double itemLongitude = item.lng;
-
- if (set.mMinLatLatitude > itemLatitude) {
- set.mMinLatLatitude = itemLatitude;
- set.mMinLatLongitude = itemLongitude;
- }
- if (set.mMaxLatLatitude < itemLatitude) {
- set.mMaxLatLatitude = itemLatitude;
- set.mMaxLatLongitude = itemLongitude;
- }
- if (set.mMinLonLongitude > itemLongitude) {
- set.mMinLonLatitude = itemLatitude;
- set.mMinLonLongitude = itemLongitude;
- }
- if (set.mMaxLonLongitude < itemLongitude) {
- set.mMaxLonLatitude = itemLatitude;
- set.mMaxLonLongitude = itemLongitude;
- }
- }
-
- return geocoder.computeAddress(set);
- }
-
- @Override
- public int getNumberOfClusters() {
- return mClusters.size();
- }
-
- @Override
- public ArrayList<Path> getCluster(int index) {
- ArrayList<SmallItem> items = mClusters.get(index);
- ArrayList<Path> result = new ArrayList<Path>(items.size());
- for (int i = 0, n = items.size(); i < n; i++) {
- result.add(items.get(i).path);
- }
- return result;
- }
-
- @Override
- public String getClusterName(int index) {
- return mNames.get(index);
- }
-
- // Input: n points
- // Output: the best k is stored in bestK[0], and the return value is the
- // an array which specifies the group that each point belongs (0 to k - 1).
- private static int[] kMeans(Point points[], int[] bestK) {
- int n = points.length;
-
- // min and max number of groups wanted
- int minK = Math.min(n, MIN_GROUPS);
- int maxK = Math.min(n, MAX_GROUPS);
-
- Point[] center = new Point[maxK]; // center of each group.
- Point[] groupSum = new Point[maxK]; // sum of points in each group.
- int[] groupCount = new int[maxK]; // number of points in each group.
- int[] grouping = new int[n]; // The group assignment for each point.
-
- for (int i = 0; i < maxK; i++) {
- center[i] = new Point();
- groupSum[i] = new Point();
- }
-
- // The score we want to minimize is:
- // (sum of distance from each point to its group center) * sqrt(k).
- float bestScore = Float.MAX_VALUE;
- // The best group assignment up to now.
- int[] bestGrouping = new int[n];
- // The best K up to now.
- bestK[0] = 1;
-
- float lastDistance = 0;
- float totalDistance = 0;
-
- for (int k = minK; k <= maxK; k++) {
- // step 1: (arbitrarily) pick k points as the initial centers.
- int delta = n / k;
- for (int i = 0; i < k; i++) {
- Point p = points[i * delta];
- center[i].latRad = p.latRad;
- center[i].lngRad = p.lngRad;
- }
-
- for (int iter = 0; iter < MAX_ITERATIONS; iter++) {
- // step 2: assign each point to the nearest center.
- for (int i = 0; i < k; i++) {
- groupSum[i].latRad = 0;
- groupSum[i].lngRad = 0;
- groupCount[i] = 0;
- }
- totalDistance = 0;
-
- for (int i = 0; i < n; i++) {
- Point p = points[i];
- float bestDistance = Float.MAX_VALUE;
- int bestIndex = 0;
- for (int j = 0; j < k; j++) {
- float distance = (float) GalleryUtils.fastDistanceMeters(
- p.latRad, p.lngRad, center[j].latRad, center[j].lngRad);
- // We may have small non-zero distance introduced by
- // floating point calculation, so zero out small
- // distances less than 1 meter.
- if (distance < 1) {
- distance = 0;
- }
- if (distance < bestDistance) {
- bestDistance = distance;
- bestIndex = j;
- }
- }
- grouping[i] = bestIndex;
- groupCount[bestIndex]++;
- groupSum[bestIndex].latRad += p.latRad;
- groupSum[bestIndex].lngRad += p.lngRad;
- totalDistance += bestDistance;
- }
-
- // step 3: calculate new centers
- for (int i = 0; i < k; i++) {
- if (groupCount[i] > 0) {
- center[i].latRad = groupSum[i].latRad / groupCount[i];
- center[i].lngRad = groupSum[i].lngRad / groupCount[i];
- }
- }
-
- if (totalDistance == 0 || (Math.abs(lastDistance - totalDistance)
- / totalDistance) < STOP_CHANGE_RATIO) {
- break;
- }
- lastDistance = totalDistance;
- }
-
- // step 4: remove empty groups and reassign group number
- int reassign[] = new int[k];
- int realK = 0;
- for (int i = 0; i < k; i++) {
- if (groupCount[i] > 0) {
- reassign[i] = realK++;
- }
- }
-
- // step 5: calculate the final score
- float score = totalDistance * FloatMath.sqrt(realK);
-
- if (score < bestScore) {
- bestScore = score;
- bestK[0] = realK;
- for (int i = 0; i < n; i++) {
- bestGrouping[i] = reassign[grouping[i]];
- }
- if (score == 0) {
- break;
- }
- }
- }
- return bestGrouping;
- }
-}
diff --git a/src/com/android/gallery3d/data/Log.java b/src/com/android/gallery3d/data/Log.java
deleted file mode 100644
index 3384eb66c..000000000
--- a/src/com/android/gallery3d/data/Log.java
+++ /dev/null
@@ -1,53 +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.data;
-
-public class Log {
- public static int v(String tag, String msg) {
- return android.util.Log.v(tag, msg);
- }
- public static int v(String tag, String msg, Throwable tr) {
- return android.util.Log.v(tag, msg, tr);
- }
- public static int d(String tag, String msg) {
- return android.util.Log.d(tag, msg);
- }
- public static int d(String tag, String msg, Throwable tr) {
- return android.util.Log.d(tag, msg, tr);
- }
- public static int i(String tag, String msg) {
- return android.util.Log.i(tag, msg);
- }
- public static int i(String tag, String msg, Throwable tr) {
- return android.util.Log.i(tag, msg, tr);
- }
- public static int w(String tag, String msg) {
- return android.util.Log.w(tag, msg);
- }
- public static int w(String tag, String msg, Throwable tr) {
- return android.util.Log.w(tag, msg, tr);
- }
- public static int w(String tag, Throwable tr) {
- return android.util.Log.w(tag, tr);
- }
- public static int e(String tag, String msg) {
- return android.util.Log.e(tag, msg);
- }
- public static int e(String tag, String msg, Throwable tr) {
- return android.util.Log.e(tag, msg, tr);
- }
-}
diff --git a/src/com/android/gallery3d/data/MediaDetails.java b/src/com/android/gallery3d/data/MediaDetails.java
deleted file mode 100644
index cac524b88..000000000
--- a/src/com/android/gallery3d/data/MediaDetails.java
+++ /dev/null
@@ -1,170 +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.data;
-
-import com.android.gallery3d.R;
-import com.android.gallery3d.common.Utils;
-import com.android.gallery3d.exif.ExifInterface;
-import com.android.gallery3d.exif.ExifTag;
-import com.android.gallery3d.exif.Rational;
-
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map.Entry;
-import java.util.TreeMap;
-
-public class MediaDetails implements Iterable<Entry<Integer, Object>> {
- @SuppressWarnings("unused")
- private static final String TAG = "MediaDetails";
-
- private TreeMap<Integer, Object> mDetails = new TreeMap<Integer, Object>();
- private HashMap<Integer, Integer> mUnits = new HashMap<Integer, Integer>();
-
- public static final int INDEX_TITLE = 1;
- public static final int INDEX_DESCRIPTION = 2;
- public static final int INDEX_DATETIME = 3;
- public static final int INDEX_LOCATION = 4;
- public static final int INDEX_WIDTH = 5;
- public static final int INDEX_HEIGHT = 6;
- public static final int INDEX_ORIENTATION = 7;
- public static final int INDEX_DURATION = 8;
- public static final int INDEX_MIMETYPE = 9;
- public static final int INDEX_SIZE = 10;
-
- // for EXIF
- public static final int INDEX_MAKE = 100;
- public static final int INDEX_MODEL = 101;
- public static final int INDEX_FLASH = 102;
- public static final int INDEX_FOCAL_LENGTH = 103;
- public static final int INDEX_WHITE_BALANCE = 104;
- public static final int INDEX_APERTURE = 105;
- public static final int INDEX_SHUTTER_SPEED = 106;
- public static final int INDEX_EXPOSURE_TIME = 107;
- public static final int INDEX_ISO = 108;
-
- // Put this last because it may be long.
- public static final int INDEX_PATH = 200;
-
- public static class FlashState {
- private static int FLASH_FIRED_MASK = 1;
- private static int FLASH_RETURN_MASK = 2 | 4;
- private static int FLASH_MODE_MASK = 8 | 16;
- private static int FLASH_FUNCTION_MASK = 32;
- private static int FLASH_RED_EYE_MASK = 64;
- private int mState;
-
- public FlashState(int state) {
- mState = state;
- }
-
- public boolean isFlashFired() {
- return (mState & FLASH_FIRED_MASK) != 0;
- }
- }
-
- public void addDetail(int index, Object value) {
- mDetails.put(index, value);
- }
-
- public Object getDetail(int index) {
- return mDetails.get(index);
- }
-
- public int size() {
- return mDetails.size();
- }
-
- @Override
- public Iterator<Entry<Integer, Object>> iterator() {
- return mDetails.entrySet().iterator();
- }
-
- public void setUnit(int index, int unit) {
- mUnits.put(index, unit);
- }
-
- public boolean hasUnit(int index) {
- return mUnits.containsKey(index);
- }
-
- public int getUnit(int index) {
- return mUnits.get(index);
- }
-
- private static void setExifData(MediaDetails details, ExifTag tag,
- int key) {
- if (tag != null) {
- String value = null;
- int type = tag.getDataType();
- if (type == ExifTag.TYPE_UNSIGNED_RATIONAL || type == ExifTag.TYPE_RATIONAL) {
- value = String.valueOf(tag.getValueAsRational(0).toDouble());
- } else if (type == ExifTag.TYPE_ASCII) {
- value = tag.getValueAsString();
- } else {
- value = String.valueOf(tag.forceGetValueAsLong(0));
- }
- if (key == MediaDetails.INDEX_FLASH) {
- MediaDetails.FlashState state = new MediaDetails.FlashState(
- Integer.valueOf(value.toString()));
- details.addDetail(key, state);
- } else {
- details.addDetail(key, value);
- }
- }
- }
-
- public static void extractExifInfo(MediaDetails details, String filePath) {
-
- ExifInterface exif = new ExifInterface();
- try {
- exif.readExif(filePath);
- } catch (FileNotFoundException e) {
- Log.w(TAG, "Could not find file to read exif: " + filePath, e);
- } catch (IOException e) {
- Log.w(TAG, "Could not read exif from file: " + filePath, e);
- }
-
- setExifData(details, exif.getTag(ExifInterface.TAG_FLASH),
- MediaDetails.INDEX_FLASH);
- setExifData(details, exif.getTag(ExifInterface.TAG_IMAGE_WIDTH),
- MediaDetails.INDEX_WIDTH);
- setExifData(details, exif.getTag(ExifInterface.TAG_IMAGE_LENGTH),
- MediaDetails.INDEX_HEIGHT);
- setExifData(details, exif.getTag(ExifInterface.TAG_MAKE),
- MediaDetails.INDEX_MAKE);
- setExifData(details, exif.getTag(ExifInterface.TAG_MODEL),
- MediaDetails.INDEX_MODEL);
- setExifData(details, exif.getTag(ExifInterface.TAG_APERTURE_VALUE),
- MediaDetails.INDEX_APERTURE);
- setExifData(details, exif.getTag(ExifInterface.TAG_ISO_SPEED_RATINGS),
- MediaDetails.INDEX_ISO);
- setExifData(details, exif.getTag(ExifInterface.TAG_WHITE_BALANCE),
- MediaDetails.INDEX_WHITE_BALANCE);
- setExifData(details, exif.getTag(ExifInterface.TAG_EXPOSURE_TIME),
- MediaDetails.INDEX_EXPOSURE_TIME);
- ExifTag focalTag = exif.getTag(ExifInterface.TAG_FOCAL_LENGTH);
- if (focalTag != null) {
- details.addDetail(MediaDetails.INDEX_FOCAL_LENGTH,
- focalTag.getValueAsRational(0).toDouble());
- details.setUnit(MediaDetails.INDEX_FOCAL_LENGTH, R.string.unit_mm);
- }
- }
-}
diff --git a/src/com/android/gallery3d/data/MediaItem.java b/src/com/android/gallery3d/data/MediaItem.java
deleted file mode 100644
index 59ea86551..000000000
--- a/src/com/android/gallery3d/data/MediaItem.java
+++ /dev/null
@@ -1,134 +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.data;
-
-import android.graphics.Bitmap;
-import android.graphics.BitmapRegionDecoder;
-
-import com.android.gallery3d.common.ApiHelper;
-import com.android.gallery3d.ui.ScreenNail;
-import com.android.gallery3d.util.ThreadPool.Job;
-
-// MediaItem represents an image or a video item.
-public abstract class MediaItem extends MediaObject {
- // NOTE: These type numbers are stored in the image cache, so it should not
- // not be changed without resetting the cache.
- public static final int TYPE_THUMBNAIL = 1;
- public static final int TYPE_MICROTHUMBNAIL = 2;
-
- public static final int CACHED_IMAGE_QUALITY = 95;
-
- public static final int IMAGE_READY = 0;
- public static final int IMAGE_WAIT = 1;
- public static final int IMAGE_ERROR = -1;
-
- public static final String MIME_TYPE_JPEG = "image/jpeg";
-
- private static final int BYTESBUFFE_POOL_SIZE = 4;
- private static final int BYTESBUFFER_SIZE = 200 * 1024;
-
- private static int sMicrothumbnailTargetSize = 200;
- private static final BytesBufferPool sMicroThumbBufferPool =
- new BytesBufferPool(BYTESBUFFE_POOL_SIZE, BYTESBUFFER_SIZE);
-
- private static int sThumbnailTargetSize = 640;
-
- // TODO: fix default value for latlng and change this.
- public static final double INVALID_LATLNG = 0f;
-
- public abstract Job<Bitmap> requestImage(int type);
- public abstract Job<BitmapRegionDecoder> requestLargeImage();
-
- public MediaItem(Path path, long version) {
- super(path, version);
- }
-
- public long getDateInMs() {
- return 0;
- }
-
- public String getName() {
- return null;
- }
-
- public void getLatLong(double[] latLong) {
- latLong[0] = INVALID_LATLNG;
- latLong[1] = INVALID_LATLNG;
- }
-
- public String[] getTags() {
- return null;
- }
-
- public Face[] getFaces() {
- return null;
- }
-
- // The rotation of the full-resolution image. By default, it returns the value of
- // getRotation().
- public int getFullImageRotation() {
- return getRotation();
- }
-
- public int getRotation() {
- return 0;
- }
-
- public long getSize() {
- return 0;
- }
-
- public abstract String getMimeType();
-
- public String getFilePath() {
- return "";
- }
-
- // Returns width and height of the media item.
- // Returns 0, 0 if the information is not available.
- public abstract int getWidth();
- public abstract int getHeight();
-
- // This is an alternative for requestImage() in PhotoPage. If this
- // is implemented, you don't need to implement requestImage().
- public ScreenNail getScreenNail() {
- return null;
- }
-
- public static int getTargetSize(int type) {
- switch (type) {
- case TYPE_THUMBNAIL:
- return sThumbnailTargetSize;
- case TYPE_MICROTHUMBNAIL:
- return sMicrothumbnailTargetSize;
- default:
- throw new RuntimeException(
- "should only request thumb/microthumb from cache");
- }
- }
-
- public static BytesBufferPool getBytesBufferPool() {
- return sMicroThumbBufferPool;
- }
-
- public static void setThumbnailSizes(int size, int microSize) {
- sThumbnailTargetSize = size;
- if (sMicrothumbnailTargetSize != microSize) {
- sMicrothumbnailTargetSize = microSize;
- }
- }
-}
diff --git a/src/com/android/gallery3d/data/MediaObject.java b/src/com/android/gallery3d/data/MediaObject.java
deleted file mode 100644
index 270d4cf0b..000000000
--- a/src/com/android/gallery3d/data/MediaObject.java
+++ /dev/null
@@ -1,166 +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.data;
-
-import android.net.Uri;
-
-public abstract class MediaObject {
- @SuppressWarnings("unused")
- private static final String TAG = "MediaObject";
- public static final long INVALID_DATA_VERSION = -1;
-
- // These are the bits returned from getSupportedOperations():
- public static final int SUPPORT_DELETE = 1 << 0;
- public static final int SUPPORT_ROTATE = 1 << 1;
- public static final int SUPPORT_SHARE = 1 << 2;
- public static final int SUPPORT_CROP = 1 << 3;
- public static final int SUPPORT_SHOW_ON_MAP = 1 << 4;
- public static final int SUPPORT_SETAS = 1 << 5;
- public static final int SUPPORT_FULL_IMAGE = 1 << 6;
- public static final int SUPPORT_PLAY = 1 << 7;
- public static final int SUPPORT_CACHE = 1 << 8;
- public static final int SUPPORT_EDIT = 1 << 9;
- public static final int SUPPORT_INFO = 1 << 10;
- public static final int SUPPORT_TRIM = 1 << 11;
- public static final int SUPPORT_UNLOCK = 1 << 12;
- public static final int SUPPORT_BACK = 1 << 13;
- public static final int SUPPORT_ACTION = 1 << 14;
- public static final int SUPPORT_CAMERA_SHORTCUT = 1 << 15;
- public static final int SUPPORT_MUTE = 1 << 16;
- public static final int SUPPORT_ALL = 0xffffffff;
-
- // These are the bits returned from getMediaType():
- public static final int MEDIA_TYPE_UNKNOWN = 1;
- public static final int MEDIA_TYPE_IMAGE = 2;
- public static final int MEDIA_TYPE_VIDEO = 4;
- public static final int MEDIA_TYPE_ALL = MEDIA_TYPE_IMAGE | MEDIA_TYPE_VIDEO;
-
- public static final String MEDIA_TYPE_IMAGE_STRING = "image";
- public static final String MEDIA_TYPE_VIDEO_STRING = "video";
- public static final String MEDIA_TYPE_ALL_STRING = "all";
-
- // These are flags for cache() and return values for getCacheFlag():
- public static final int CACHE_FLAG_NO = 0;
- public static final int CACHE_FLAG_SCREENNAIL = 1;
- public static final int CACHE_FLAG_FULL = 2;
-
- // These are return values for getCacheStatus():
- public static final int CACHE_STATUS_NOT_CACHED = 0;
- public static final int CACHE_STATUS_CACHING = 1;
- public static final int CACHE_STATUS_CACHED_SCREENNAIL = 2;
- public static final int CACHE_STATUS_CACHED_FULL = 3;
-
- private static long sVersionSerial = 0;
-
- protected long mDataVersion;
-
- protected final Path mPath;
-
- public interface PanoramaSupportCallback {
- void panoramaInfoAvailable(MediaObject mediaObject, boolean isPanorama,
- boolean isPanorama360);
- }
-
- public MediaObject(Path path, long version) {
- path.setObject(this);
- mPath = path;
- mDataVersion = version;
- }
-
- public Path getPath() {
- return mPath;
- }
-
- public int getSupportedOperations() {
- return 0;
- }
-
- public void getPanoramaSupport(PanoramaSupportCallback callback) {
- callback.panoramaInfoAvailable(this, false, false);
- }
-
- public void clearCachedPanoramaSupport() {
- }
-
- public void delete() {
- throw new UnsupportedOperationException();
- }
-
- public void rotate(int degrees) {
- throw new UnsupportedOperationException();
- }
-
- public Uri getContentUri() {
- String className = getClass().getName();
- Log.e(TAG, "Class " + className + "should implement getContentUri.");
- Log.e(TAG, "The object was created from path: " + getPath());
- throw new UnsupportedOperationException();
- }
-
- public Uri getPlayUri() {
- throw new UnsupportedOperationException();
- }
-
- public int getMediaType() {
- return MEDIA_TYPE_UNKNOWN;
- }
-
- public MediaDetails getDetails() {
- MediaDetails details = new MediaDetails();
- return details;
- }
-
- public long getDataVersion() {
- return mDataVersion;
- }
-
- public int getCacheFlag() {
- return CACHE_FLAG_NO;
- }
-
- public int getCacheStatus() {
- throw new UnsupportedOperationException();
- }
-
- public long getCacheSize() {
- throw new UnsupportedOperationException();
- }
-
- public void cache(int flag) {
- throw new UnsupportedOperationException();
- }
-
- public static synchronized long nextVersionNumber() {
- return ++MediaObject.sVersionSerial;
- }
-
- public static int getTypeFromString(String s) {
- if (MEDIA_TYPE_ALL_STRING.equals(s)) return MediaObject.MEDIA_TYPE_ALL;
- if (MEDIA_TYPE_IMAGE_STRING.equals(s)) return MediaObject.MEDIA_TYPE_IMAGE;
- if (MEDIA_TYPE_VIDEO_STRING.equals(s)) return MediaObject.MEDIA_TYPE_VIDEO;
- throw new IllegalArgumentException(s);
- }
-
- public static String getTypeString(int type) {
- switch (type) {
- case MEDIA_TYPE_IMAGE: return MEDIA_TYPE_IMAGE_STRING;
- case MEDIA_TYPE_VIDEO: return MEDIA_TYPE_VIDEO_STRING;
- case MEDIA_TYPE_ALL: return MEDIA_TYPE_ALL_STRING;
- }
- throw new IllegalArgumentException();
- }
-}
diff --git a/src/com/android/gallery3d/data/MediaSet.java b/src/com/android/gallery3d/data/MediaSet.java
deleted file mode 100644
index 683aa6b32..000000000
--- a/src/com/android/gallery3d/data/MediaSet.java
+++ /dev/null
@@ -1,348 +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.data;
-
-import com.android.gallery3d.common.Utils;
-import com.android.gallery3d.util.Future;
-
-import java.util.ArrayList;
-import java.util.WeakHashMap;
-
-// MediaSet is a directory-like data structure.
-// It contains MediaItems and sub-MediaSets.
-//
-// The primary interface are:
-// getMediaItemCount(), getMediaItem() and
-// getSubMediaSetCount(), getSubMediaSet().
-//
-// getTotalMediaItemCount() returns the number of all MediaItems, including
-// those in sub-MediaSets.
-public abstract class MediaSet extends MediaObject {
- @SuppressWarnings("unused")
- private static final String TAG = "MediaSet";
-
- public static final int MEDIAITEM_BATCH_FETCH_COUNT = 500;
- public static final int INDEX_NOT_FOUND = -1;
-
- public static final int SYNC_RESULT_SUCCESS = 0;
- public static final int SYNC_RESULT_CANCELLED = 1;
- public static final int SYNC_RESULT_ERROR = 2;
-
- /** Listener to be used with requestSync(SyncListener). */
- public static interface SyncListener {
- /**
- * Called when the sync task completed. Completion may be due to normal termination,
- * an exception, or cancellation.
- *
- * @param mediaSet the MediaSet that's done with sync
- * @param resultCode one of the SYNC_RESULT_* constants
- */
- void onSyncDone(MediaSet mediaSet, int resultCode);
- }
-
- public MediaSet(Path path, long version) {
- super(path, version);
- }
-
- public int getMediaItemCount() {
- return 0;
- }
-
- // Returns the media items in the range [start, start + count).
- //
- // The number of media items returned may be less than the specified count
- // if there are not enough media items available. The number of
- // media items available may not be consistent with the return value of
- // getMediaItemCount() because the contents of database may have already
- // changed.
- public ArrayList<MediaItem> getMediaItem(int start, int count) {
- return new ArrayList<MediaItem>();
- }
-
- public MediaItem getCoverMediaItem() {
- ArrayList<MediaItem> items = getMediaItem(0, 1);
- if (items.size() > 0) return items.get(0);
- for (int i = 0, n = getSubMediaSetCount(); i < n; i++) {
- MediaItem cover = getSubMediaSet(i).getCoverMediaItem();
- if (cover != null) return cover;
- }
- return null;
- }
-
- public int getSubMediaSetCount() {
- return 0;
- }
-
- public MediaSet getSubMediaSet(int index) {
- throw new IndexOutOfBoundsException();
- }
-
- public boolean isLeafAlbum() {
- return false;
- }
-
- public boolean isCameraRoll() {
- return false;
- }
-
- /**
- * Method {@link #reload()} may process the loading task in background, this method tells
- * its client whether the loading is still in process or not.
- */
- public boolean isLoading() {
- return false;
- }
-
- public int getTotalMediaItemCount() {
- int total = getMediaItemCount();
- for (int i = 0, n = getSubMediaSetCount(); i < n; i++) {
- total += getSubMediaSet(i).getTotalMediaItemCount();
- }
- return total;
- }
-
- // TODO: we should have better implementation of sub classes
- public int getIndexOfItem(Path path, int hint) {
- // hint < 0 is handled below
- // first, try to find it around the hint
- int start = Math.max(0,
- hint - MEDIAITEM_BATCH_FETCH_COUNT / 2);
- ArrayList<MediaItem> list = getMediaItem(
- start, MEDIAITEM_BATCH_FETCH_COUNT);
- int index = getIndexOf(path, list);
- if (index != INDEX_NOT_FOUND) return start + index;
-
- // try to find it globally
- start = start == 0 ? MEDIAITEM_BATCH_FETCH_COUNT : 0;
- list = getMediaItem(start, MEDIAITEM_BATCH_FETCH_COUNT);
- while (true) {
- index = getIndexOf(path, list);
- if (index != INDEX_NOT_FOUND) return start + index;
- if (list.size() < MEDIAITEM_BATCH_FETCH_COUNT) return INDEX_NOT_FOUND;
- start += MEDIAITEM_BATCH_FETCH_COUNT;
- list = getMediaItem(start, MEDIAITEM_BATCH_FETCH_COUNT);
- }
- }
-
- protected int getIndexOf(Path path, ArrayList<MediaItem> list) {
- for (int i = 0, n = list.size(); i < n; ++i) {
- // item could be null only in ClusterAlbum
- MediaObject item = list.get(i);
- if (item != null && item.mPath == path) return i;
- }
- return INDEX_NOT_FOUND;
- }
-
- public abstract String getName();
-
- private WeakHashMap<ContentListener, Object> mListeners =
- new WeakHashMap<ContentListener, Object>();
-
- // NOTE: The MediaSet only keeps a weak reference to the listener. The
- // listener is automatically removed when there is no other reference to
- // the listener.
- public void addContentListener(ContentListener listener) {
- mListeners.put(listener, null);
- }
-
- public void removeContentListener(ContentListener listener) {
- mListeners.remove(listener);
- }
-
- // This should be called by subclasses when the content is changed.
- public void notifyContentChanged() {
- for (ContentListener listener : mListeners.keySet()) {
- listener.onContentDirty();
- }
- }
-
- // Reload the content. Return the current data version. reload() should be called
- // in the same thread as getMediaItem(int, int) and getSubMediaSet(int).
- public abstract long reload();
-
- @Override
- public MediaDetails getDetails() {
- MediaDetails details = super.getDetails();
- details.addDetail(MediaDetails.INDEX_TITLE, getName());
- return details;
- }
-
- // Enumerate all media items in this media set (including the ones in sub
- // media sets), in an efficient order. ItemConsumer.consumer() will be
- // called for each media item with its index.
- public void enumerateMediaItems(ItemConsumer consumer) {
- enumerateMediaItems(consumer, 0);
- }
-
- public void enumerateTotalMediaItems(ItemConsumer consumer) {
- enumerateTotalMediaItems(consumer, 0);
- }
-
- public static interface ItemConsumer {
- void consume(int index, MediaItem item);
- }
-
- // The default implementation uses getMediaItem() for enumerateMediaItems().
- // Subclasses may override this and use more efficient implementations.
- // Returns the number of items enumerated.
- protected int enumerateMediaItems(ItemConsumer consumer, int startIndex) {
- int total = getMediaItemCount();
- int start = 0;
- while (start < total) {
- int count = Math.min(MEDIAITEM_BATCH_FETCH_COUNT, total - start);
- ArrayList<MediaItem> items = getMediaItem(start, count);
- for (int i = 0, n = items.size(); i < n; i++) {
- MediaItem item = items.get(i);
- consumer.consume(startIndex + start + i, item);
- }
- start += count;
- }
- return total;
- }
-
- // Recursively enumerate all media items under this set.
- // Returns the number of items enumerated.
- protected int enumerateTotalMediaItems(
- ItemConsumer consumer, int startIndex) {
- int start = 0;
- start += enumerateMediaItems(consumer, startIndex);
- int m = getSubMediaSetCount();
- for (int i = 0; i < m; i++) {
- start += getSubMediaSet(i).enumerateTotalMediaItems(
- consumer, startIndex + start);
- }
- return start;
- }
-
- /**
- * Requests sync on this MediaSet. It returns a Future object that can be used by the caller
- * to query the status of the sync. The sync result code is one of the SYNC_RESULT_* constants
- * defined in this class and can be obtained by Future.get().
- *
- * Subclasses should perform sync on a different thread.
- *
- * The default implementation here returns a Future stub that does nothing and returns
- * SYNC_RESULT_SUCCESS by get().
- */
- public Future<Integer> requestSync(SyncListener listener) {
- listener.onSyncDone(this, SYNC_RESULT_SUCCESS);
- return FUTURE_STUB;
- }
-
- private static final Future<Integer> FUTURE_STUB = new Future<Integer>() {
- @Override
- public void cancel() {}
-
- @Override
- public boolean isCancelled() {
- return false;
- }
-
- @Override
- public boolean isDone() {
- return true;
- }
-
- @Override
- public Integer get() {
- return SYNC_RESULT_SUCCESS;
- }
-
- @Override
- public void waitDone() {}
- };
-
- protected Future<Integer> requestSyncOnMultipleSets(MediaSet[] sets, SyncListener listener) {
- return new MultiSetSyncFuture(sets, listener);
- }
-
- private class MultiSetSyncFuture implements Future<Integer>, SyncListener {
- @SuppressWarnings("hiding")
- private static final String TAG = "Gallery.MultiSetSync";
-
- private final SyncListener mListener;
- private final Future<Integer> mFutures[];
-
- private boolean mIsCancelled = false;
- private int mResult = -1;
- private int mPendingCount;
-
- @SuppressWarnings("unchecked")
- MultiSetSyncFuture(MediaSet[] sets, SyncListener listener) {
- mListener = listener;
- mPendingCount = sets.length;
- mFutures = new Future[sets.length];
-
- synchronized (this) {
- for (int i = 0, n = sets.length; i < n; ++i) {
- mFutures[i] = sets[i].requestSync(this);
- Log.d(TAG, " request sync: " + Utils.maskDebugInfo(sets[i].getName()));
- }
- }
- }
-
- @Override
- public synchronized void cancel() {
- if (mIsCancelled) return;
- mIsCancelled = true;
- for (Future<Integer> future : mFutures) future.cancel();
- if (mResult < 0) mResult = SYNC_RESULT_CANCELLED;
- }
-
- @Override
- public synchronized boolean isCancelled() {
- return mIsCancelled;
- }
-
- @Override
- public synchronized boolean isDone() {
- return mPendingCount == 0;
- }
-
- @Override
- public synchronized Integer get() {
- waitDone();
- return mResult;
- }
-
- @Override
- public synchronized void waitDone() {
- try {
- while (!isDone()) wait();
- } catch (InterruptedException e) {
- Log.d(TAG, "waitDone() interrupted");
- }
- }
-
- // SyncListener callback
- @Override
- public void onSyncDone(MediaSet mediaSet, int resultCode) {
- SyncListener listener = null;
- synchronized (this) {
- if (resultCode == SYNC_RESULT_ERROR) mResult = SYNC_RESULT_ERROR;
- --mPendingCount;
- if (mPendingCount == 0) {
- listener = mListener;
- notifyAll();
- }
- Log.d(TAG, "onSyncDone: " + Utils.maskDebugInfo(mediaSet.getName())
- + " #pending=" + mPendingCount);
- }
- if (listener != null) listener.onSyncDone(MediaSet.this, mResult);
- }
- }
-}
diff --git a/src/com/android/gallery3d/data/MediaSource.java b/src/com/android/gallery3d/data/MediaSource.java
deleted file mode 100644
index 95901283b..000000000
--- a/src/com/android/gallery3d/data/MediaSource.java
+++ /dev/null
@@ -1,96 +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.data;
-
-import android.net.Uri;
-
-import com.android.gallery3d.data.MediaSet.ItemConsumer;
-
-import java.util.ArrayList;
-
-public abstract class MediaSource {
- private static final String TAG = "MediaSource";
- private String mPrefix;
-
- protected MediaSource(String prefix) {
- mPrefix = prefix;
- }
-
- public String getPrefix() {
- return mPrefix;
- }
-
- public Path findPathByUri(Uri uri, String type) {
- return null;
- }
-
- public abstract MediaObject createMediaObject(Path path);
-
- public void pause() {
- }
-
- public void resume() {
- }
-
- public Path getDefaultSetOf(Path item) {
- return null;
- }
-
- public long getTotalUsedCacheSize() {
- return 0;
- }
-
- public long getTotalTargetCacheSize() {
- return 0;
- }
-
- public static class PathId {
- public PathId(Path path, int id) {
- this.path = path;
- this.id = id;
- }
- public Path path;
- public int id;
- }
-
- // Maps a list of Paths (all belong to this MediaSource) to MediaItems,
- // and invoke consumer.consume() for each MediaItem with the given id.
- //
- // This default implementation uses getMediaObject for each Path. Subclasses
- // may override this and provide more efficient implementation (like
- // batching the database query).
- public void mapMediaItems(ArrayList<PathId> list, ItemConsumer consumer) {
- int n = list.size();
- for (int i = 0; i < n; i++) {
- PathId pid = list.get(i);
- MediaObject obj;
- synchronized (DataManager.LOCK) {
- obj = pid.path.getObject();
- if (obj == null) {
- try {
- obj = createMediaObject(pid.path);
- } catch (Throwable th) {
- Log.w(TAG, "cannot create media object: " + pid.path, th);
- }
- }
- }
- if (obj != null) {
- consumer.consume(pid.id, (MediaItem) obj);
- }
- }
- }
-}
diff --git a/src/com/android/gallery3d/data/MtpClient.java b/src/com/android/gallery3d/data/MtpClient.java
deleted file mode 100644
index 737b5b60d..000000000
--- a/src/com/android/gallery3d/data/MtpClient.java
+++ /dev/null
@@ -1,443 +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.data;
-
-import android.annotation.TargetApi;
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.hardware.usb.UsbConstants;
-import android.hardware.usb.UsbDevice;
-import android.hardware.usb.UsbDeviceConnection;
-import android.hardware.usb.UsbInterface;
-import android.hardware.usb.UsbManager;
-import android.mtp.MtpDevice;
-import android.mtp.MtpObjectInfo;
-import android.mtp.MtpStorageInfo;
-import android.util.Log;
-
-import com.android.gallery3d.common.ApiHelper;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-
-/**
- * This class helps an application manage a list of connected MTP or PTP devices.
- * It listens for MTP devices being attached and removed from the USB host bus
- * and notifies the application when the MTP device list changes.
- */
-@TargetApi(ApiHelper.VERSION_CODES.HONEYCOMB_MR1)
-public class MtpClient {
-
- private static final String TAG = "MtpClient";
-
- private static final String ACTION_USB_PERMISSION =
- "android.mtp.MtpClient.action.USB_PERMISSION";
-
- private final Context mContext;
- private final UsbManager mUsbManager;
- private final ArrayList<Listener> mListeners = new ArrayList<Listener>();
- // mDevices contains all MtpDevices that have been seen by our client,
- // so we can inform when the device has been detached.
- // mDevices is also used for synchronization in this class.
- private final HashMap<String, MtpDevice> mDevices = new HashMap<String, MtpDevice>();
- // List of MTP devices we should not try to open for which we are currently
- // asking for permission to open.
- private final ArrayList<String> mRequestPermissionDevices = new ArrayList<String>();
- // List of MTP devices we should not try to open.
- // We add devices to this list if the user canceled a permission request or we were
- // unable to open the device.
- private final ArrayList<String> mIgnoredDevices = new ArrayList<String>();
-
- private final PendingIntent mPermissionIntent;
-
- private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- UsbDevice usbDevice = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
- String deviceName = usbDevice.getDeviceName();
-
- synchronized (mDevices) {
- MtpDevice mtpDevice = mDevices.get(deviceName);
-
- if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) {
- if (mtpDevice == null) {
- mtpDevice = openDeviceLocked(usbDevice);
- }
- if (mtpDevice != null) {
- for (Listener listener : mListeners) {
- listener.deviceAdded(mtpDevice);
- }
- }
- } else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {
- if (mtpDevice != null) {
- mDevices.remove(deviceName);
- mRequestPermissionDevices.remove(deviceName);
- mIgnoredDevices.remove(deviceName);
- for (Listener listener : mListeners) {
- listener.deviceRemoved(mtpDevice);
- }
- }
- } else if (ACTION_USB_PERMISSION.equals(action)) {
- mRequestPermissionDevices.remove(deviceName);
- boolean permission = intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED,
- false);
- Log.d(TAG, "ACTION_USB_PERMISSION: " + permission);
- if (permission) {
- if (mtpDevice == null) {
- mtpDevice = openDeviceLocked(usbDevice);
- }
- if (mtpDevice != null) {
- for (Listener listener : mListeners) {
- listener.deviceAdded(mtpDevice);
- }
- }
- } else {
- // so we don't ask for permission again
- mIgnoredDevices.add(deviceName);
- }
- }
- }
- }
- };
-
- /**
- * An interface for being notified when MTP or PTP devices are attached
- * or removed. In the current implementation, only PTP devices are supported.
- */
- public interface Listener {
- /**
- * Called when a new device has been added
- *
- * @param device the new device that was added
- */
- public void deviceAdded(MtpDevice device);
-
- /**
- * Called when a new device has been removed
- *
- * @param device the device that was removed
- */
- public void deviceRemoved(MtpDevice device);
- }
-
- /**
- * Tests to see if a {@link android.hardware.usb.UsbDevice}
- * supports the PTP protocol (typically used by digital cameras)
- *
- * @param device the device to test
- * @return true if the device is a PTP device.
- */
- static public boolean isCamera(UsbDevice device) {
- int count = device.getInterfaceCount();
- for (int i = 0; i < count; i++) {
- UsbInterface intf = device.getInterface(i);
- if (intf.getInterfaceClass() == UsbConstants.USB_CLASS_STILL_IMAGE &&
- intf.getInterfaceSubclass() == 1 &&
- intf.getInterfaceProtocol() == 1) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * MtpClient constructor
- *
- * @param context the {@link android.content.Context} to use for the MtpClient
- */
- public MtpClient(Context context) {
- mContext = context;
- mUsbManager = (UsbManager)context.getSystemService(Context.USB_SERVICE);
- mPermissionIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ACTION_USB_PERMISSION), 0);
- IntentFilter filter = new IntentFilter();
- filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
- filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
- filter.addAction(ACTION_USB_PERMISSION);
- context.registerReceiver(mUsbReceiver, filter);
- }
-
- /**
- * Opens the {@link android.hardware.usb.UsbDevice} for an MTP or PTP
- * device and return an {@link android.mtp.MtpDevice} for it.
- *
- * @param usbDevice the device to open
- * @return an MtpDevice for the device.
- */
- private MtpDevice openDeviceLocked(UsbDevice usbDevice) {
- String deviceName = usbDevice.getDeviceName();
-
- // don't try to open devices that we have decided to ignore
- // or are currently asking permission for
- if (isCamera(usbDevice) && !mIgnoredDevices.contains(deviceName)
- && !mRequestPermissionDevices.contains(deviceName)) {
- if (!mUsbManager.hasPermission(usbDevice)) {
- mUsbManager.requestPermission(usbDevice, mPermissionIntent);
- mRequestPermissionDevices.add(deviceName);
- } else {
- UsbDeviceConnection connection = mUsbManager.openDevice(usbDevice);
- if (connection != null) {
- MtpDevice mtpDevice = new MtpDevice(usbDevice);
- if (mtpDevice.open(connection)) {
- mDevices.put(usbDevice.getDeviceName(), mtpDevice);
- return mtpDevice;
- } else {
- // so we don't try to open it again
- mIgnoredDevices.add(deviceName);
- }
- } else {
- // so we don't try to open it again
- mIgnoredDevices.add(deviceName);
- }
- }
- }
- return null;
- }
-
- /**
- * Closes all resources related to the MtpClient object
- */
- public void close() {
- mContext.unregisterReceiver(mUsbReceiver);
- }
-
- /**
- * Registers a {@link com.android.gallery3d.data.MtpClient.Listener} interface to receive
- * notifications when MTP or PTP devices are added or removed.
- *
- * @param listener the listener to register
- */
- public void addListener(Listener listener) {
- synchronized (mDevices) {
- if (!mListeners.contains(listener)) {
- mListeners.add(listener);
- }
- }
- }
-
- /**
- * Unregisters a {@link com.android.gallery3d.data.MtpClient.Listener} interface.
- *
- * @param listener the listener to unregister
- */
- public void removeListener(Listener listener) {
- synchronized (mDevices) {
- mListeners.remove(listener);
- }
- }
-
- /**
- * Retrieves an {@link android.mtp.MtpDevice} object for the USB device
- * with the given name.
- *
- * @param deviceName the name of the USB device
- * @return the MtpDevice, or null if it does not exist
- */
- public MtpDevice getDevice(String deviceName) {
- synchronized (mDevices) {
- return mDevices.get(deviceName);
- }
- }
-
- /**
- * Retrieves an {@link android.mtp.MtpDevice} object for the USB device
- * with the given ID.
- *
- * @param id the ID of the USB device
- * @return the MtpDevice, or null if it does not exist
- */
- public MtpDevice getDevice(int id) {
- synchronized (mDevices) {
- return mDevices.get(UsbDevice.getDeviceName(id));
- }
- }
-
- /**
- * Retrieves a list of all currently connected {@link android.mtp.MtpDevice}.
- *
- * @return the list of MtpDevices
- */
- public List<MtpDevice> getDeviceList() {
- synchronized (mDevices) {
- // Query the USB manager since devices might have attached
- // before we added our listener.
- for (UsbDevice usbDevice : mUsbManager.getDeviceList().values()) {
- if (mDevices.get(usbDevice.getDeviceName()) == null) {
- openDeviceLocked(usbDevice);
- }
- }
-
- return new ArrayList<MtpDevice>(mDevices.values());
- }
- }
-
- /**
- * Retrieves a list of all {@link android.mtp.MtpStorageInfo}
- * for the MTP or PTP device with the given USB device name
- *
- * @param deviceName the name of the USB device
- * @return the list of MtpStorageInfo
- */
- public List<MtpStorageInfo> getStorageList(String deviceName) {
- MtpDevice device = getDevice(deviceName);
- if (device == null) {
- return null;
- }
- int[] storageIds = device.getStorageIds();
- if (storageIds == null) {
- return null;
- }
-
- int length = storageIds.length;
- ArrayList<MtpStorageInfo> storageList = new ArrayList<MtpStorageInfo>(length);
- for (int i = 0; i < length; i++) {
- MtpStorageInfo info = device.getStorageInfo(storageIds[i]);
- if (info == null) {
- Log.w(TAG, "getStorageInfo failed");
- } else {
- storageList.add(info);
- }
- }
- return storageList;
- }
-
- /**
- * Retrieves the {@link android.mtp.MtpObjectInfo} for an object on
- * the MTP or PTP device with the given USB device name with the given
- * object handle
- *
- * @param deviceName the name of the USB device
- * @param objectHandle handle of the object to query
- * @return the MtpObjectInfo
- */
- public MtpObjectInfo getObjectInfo(String deviceName, int objectHandle) {
- MtpDevice device = getDevice(deviceName);
- if (device == null) {
- return null;
- }
- return device.getObjectInfo(objectHandle);
- }
-
- /**
- * Deletes an object on the MTP or PTP device with the given USB device name.
- *
- * @param deviceName the name of the USB device
- * @param objectHandle handle of the object to delete
- * @return true if the deletion succeeds
- */
- public boolean deleteObject(String deviceName, int objectHandle) {
- MtpDevice device = getDevice(deviceName);
- if (device == null) {
- return false;
- }
- return device.deleteObject(objectHandle);
- }
-
- /**
- * Retrieves a list of {@link android.mtp.MtpObjectInfo} for all objects
- * on the MTP or PTP device with the given USB device name and given storage ID
- * and/or object handle.
- * If the object handle is zero, then all objects in the root of the storage unit
- * will be returned. Otherwise, all immediate children of the object will be returned.
- * If the storage ID is also zero, then all objects on all storage units will be returned.
- *
- * @param deviceName the name of the USB device
- * @param storageId the ID of the storage unit to query, or zero for all
- * @param objectHandle the handle of the parent object to query, or zero for the storage root
- * @return the list of MtpObjectInfo
- */
- public List<MtpObjectInfo> getObjectList(String deviceName, int storageId, int objectHandle) {
- MtpDevice device = getDevice(deviceName);
- if (device == null) {
- return null;
- }
- if (objectHandle == 0) {
- // all objects in root of storage
- objectHandle = 0xFFFFFFFF;
- }
- int[] handles = device.getObjectHandles(storageId, 0, objectHandle);
- if (handles == null) {
- return null;
- }
-
- int length = handles.length;
- ArrayList<MtpObjectInfo> objectList = new ArrayList<MtpObjectInfo>(length);
- for (int i = 0; i < length; i++) {
- MtpObjectInfo info = device.getObjectInfo(handles[i]);
- if (info == null) {
- Log.w(TAG, "getObjectInfo failed");
- } else {
- objectList.add(info);
- }
- }
- return objectList;
- }
-
- /**
- * Returns the data for an object as a byte array.
- *
- * @param deviceName the name of the USB device containing the object
- * @param objectHandle handle of the object to read
- * @param objectSize the size of the object (this should match
- * {@link android.mtp.MtpObjectInfo#getCompressedSize}
- * @return the object's data, or null if reading fails
- */
- public byte[] getObject(String deviceName, int objectHandle, int objectSize) {
- MtpDevice device = getDevice(deviceName);
- if (device == null) {
- return null;
- }
- return device.getObject(objectHandle, objectSize);
- }
-
- /**
- * Returns the thumbnail data for an object as a byte array.
- *
- * @param deviceName the name of the USB device containing the object
- * @param objectHandle handle of the object to read
- * @return the object's thumbnail, or null if reading fails
- */
- public byte[] getThumbnail(String deviceName, int objectHandle) {
- MtpDevice device = getDevice(deviceName);
- if (device == null) {
- return null;
- }
- return device.getThumbnail(objectHandle);
- }
-
- /**
- * Copies the data for an object to a file in external storage.
- *
- * @param deviceName the name of the USB device containing the object
- * @param objectHandle handle of the object to read
- * @param destPath path to destination for the file transfer.
- * This path should be in the external storage as defined by
- * {@link android.os.Environment#getExternalStorageDirectory}
- * @return true if the file transfer succeeds
- */
- public boolean importFile(String deviceName, int objectHandle, String destPath) {
- MtpDevice device = getDevice(deviceName);
- if (device == null) {
- return false;
- }
- return device.importFile(objectHandle, destPath);
- }
-}
diff --git a/src/com/android/gallery3d/data/PanoramaMetadataJob.java b/src/com/android/gallery3d/data/PanoramaMetadataJob.java
deleted file mode 100644
index ab99d6a81..000000000
--- a/src/com/android/gallery3d/data/PanoramaMetadataJob.java
+++ /dev/null
@@ -1,40 +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.data;
-
-import android.content.Context;
-import android.net.Uri;
-
-import com.android.gallery3d.util.LightCycleHelper;
-import com.android.gallery3d.util.LightCycleHelper.PanoramaMetadata;
-import com.android.gallery3d.util.ThreadPool.Job;
-import com.android.gallery3d.util.ThreadPool.JobContext;
-
-public class PanoramaMetadataJob implements Job<PanoramaMetadata> {
- Context mContext;
- Uri mUri;
-
- public PanoramaMetadataJob(Context context, Uri uri) {
- mContext = context;
- mUri = uri;
- }
-
- @Override
- public PanoramaMetadata run(JobContext jc) {
- return LightCycleHelper.getPanoramaMetadata(mContext, mUri);
- }
-}
diff --git a/src/com/android/gallery3d/data/Path.java b/src/com/android/gallery3d/data/Path.java
deleted file mode 100644
index fcae65e66..000000000
--- a/src/com/android/gallery3d/data/Path.java
+++ /dev/null
@@ -1,241 +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.data;
-
-import com.android.gallery3d.common.Utils;
-import com.android.gallery3d.util.IdentityCache;
-
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-
-public class Path {
- private static final String TAG = "Path";
- private static Path sRoot = new Path(null, "ROOT");
-
- private final Path mParent;
- private final String mSegment;
- private WeakReference<MediaObject> mObject;
- private IdentityCache<String, Path> mChildren;
-
- private Path(Path parent, String segment) {
- mParent = parent;
- mSegment = segment;
- }
-
- public Path getChild(String segment) {
- synchronized (Path.class) {
- if (mChildren == null) {
- mChildren = new IdentityCache<String, Path>();
- } else {
- Path p = mChildren.get(segment);
- if (p != null) return p;
- }
-
- Path p = new Path(this, segment);
- mChildren.put(segment, p);
- return p;
- }
- }
-
- public Path getParent() {
- synchronized (Path.class) {
- return mParent;
- }
- }
-
- public Path getChild(int segment) {
- return getChild(String.valueOf(segment));
- }
-
- public Path getChild(long segment) {
- return getChild(String.valueOf(segment));
- }
-
- public void setObject(MediaObject object) {
- synchronized (Path.class) {
- Utils.assertTrue(mObject == null || mObject.get() == null);
- mObject = new WeakReference<MediaObject>(object);
- }
- }
-
- MediaObject getObject() {
- synchronized (Path.class) {
- return (mObject == null) ? null : mObject.get();
- }
- }
-
- @Override
- // TODO: toString() should be more efficient, will fix it later
- public String toString() {
- synchronized (Path.class) {
- StringBuilder sb = new StringBuilder();
- String[] segments = split();
- for (int i = 0; i < segments.length; i++) {
- sb.append("/");
- sb.append(segments[i]);
- }
- return sb.toString();
- }
- }
-
- public boolean equalsIgnoreCase (String p) {
- String path = toString();
- return path.equalsIgnoreCase(p);
- }
-
- public static Path fromString(String s) {
- synchronized (Path.class) {
- String[] segments = split(s);
- Path current = sRoot;
- for (int i = 0; i < segments.length; i++) {
- current = current.getChild(segments[i]);
- }
- return current;
- }
- }
-
- public String[] split() {
- synchronized (Path.class) {
- int n = 0;
- for (Path p = this; p != sRoot; p = p.mParent) {
- n++;
- }
- String[] segments = new String[n];
- int i = n - 1;
- for (Path p = this; p != sRoot; p = p.mParent) {
- segments[i--] = p.mSegment;
- }
- return segments;
- }
- }
-
- public static String[] split(String s) {
- int n = s.length();
- if (n == 0) return new String[0];
- if (s.charAt(0) != '/') {
- throw new RuntimeException("malformed path:" + s);
- }
- ArrayList<String> segments = new ArrayList<String>();
- int i = 1;
- while (i < n) {
- int brace = 0;
- int j;
- for (j = i; j < n; j++) {
- char c = s.charAt(j);
- if (c == '{') ++brace;
- else if (c == '}') --brace;
- else if (brace == 0 && c == '/') break;
- }
- if (brace != 0) {
- throw new RuntimeException("unbalanced brace in path:" + s);
- }
- segments.add(s.substring(i, j));
- i = j + 1;
- }
- String[] result = new String[segments.size()];
- segments.toArray(result);
- return result;
- }
-
- // Splits a string to an array of strings.
- // For example, "{foo,bar,baz}" -> {"foo","bar","baz"}.
- public static String[] splitSequence(String s) {
- int n = s.length();
- if (s.charAt(0) != '{' || s.charAt(n-1) != '}') {
- throw new RuntimeException("bad sequence: " + s);
- }
- ArrayList<String> segments = new ArrayList<String>();
- int i = 1;
- while (i < n - 1) {
- int brace = 0;
- int j;
- for (j = i; j < n - 1; j++) {
- char c = s.charAt(j);
- if (c == '{') ++brace;
- else if (c == '}') --brace;
- else if (brace == 0 && c == ',') break;
- }
- if (brace != 0) {
- throw new RuntimeException("unbalanced brace in path:" + s);
- }
- segments.add(s.substring(i, j));
- i = j + 1;
- }
- String[] result = new String[segments.size()];
- segments.toArray(result);
- return result;
- }
-
- public String getPrefix() {
- if (this == sRoot) return "";
- return getPrefixPath().mSegment;
- }
-
- public Path getPrefixPath() {
- synchronized (Path.class) {
- Path current = this;
- if (current == sRoot) {
- throw new IllegalStateException();
- }
- while (current.mParent != sRoot) {
- current = current.mParent;
- }
- return current;
- }
- }
-
- public String getSuffix() {
- // We don't need lock because mSegment is final.
- return mSegment;
- }
-
- // Below are for testing/debugging only
- static void clearAll() {
- synchronized (Path.class) {
- sRoot = new Path(null, "");
- }
- }
-
- static void dumpAll() {
- dumpAll(sRoot, "", "");
- }
-
- static void dumpAll(Path p, String prefix1, String prefix2) {
- synchronized (Path.class) {
- MediaObject obj = p.getObject();
- Log.d(TAG, prefix1 + p.mSegment + ":"
- + (obj == null ? "null" : obj.getClass().getSimpleName()));
- if (p.mChildren != null) {
- ArrayList<String> childrenKeys = p.mChildren.keys();
- int i = 0, n = childrenKeys.size();
- for (String key : childrenKeys) {
- Path child = p.mChildren.get(key);
- if (child == null) {
- ++i;
- continue;
- }
- Log.d(TAG, prefix2 + "|");
- if (++i < n) {
- dumpAll(child, prefix2 + "+-- ", prefix2 + "| ");
- } else {
- dumpAll(child, prefix2 + "+-- ", prefix2 + " ");
- }
- }
- }
- }
- }
-}
diff --git a/src/com/android/gallery3d/data/PathMatcher.java b/src/com/android/gallery3d/data/PathMatcher.java
deleted file mode 100644
index 9c6b840d5..000000000
--- a/src/com/android/gallery3d/data/PathMatcher.java
+++ /dev/null
@@ -1,102 +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.data;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-
-public class PathMatcher {
- public static final int NOT_FOUND = -1;
-
- private ArrayList<String> mVariables = new ArrayList<String>();
- private Node mRoot = new Node();
-
- public PathMatcher() {
- mRoot = new Node();
- }
-
- public void add(String pattern, int kind) {
- String[] segments = Path.split(pattern);
- Node current = mRoot;
- for (int i = 0; i < segments.length; i++) {
- current = current.addChild(segments[i]);
- }
- current.setKind(kind);
- }
-
- public int match(Path path) {
- String[] segments = path.split();
- mVariables.clear();
- Node current = mRoot;
- for (int i = 0; i < segments.length; i++) {
- Node next = current.getChild(segments[i]);
- if (next == null) {
- next = current.getChild("*");
- if (next != null) {
- mVariables.add(segments[i]);
- } else {
- return NOT_FOUND;
- }
- }
- current = next;
- }
- return current.getKind();
- }
-
- public String getVar(int index) {
- return mVariables.get(index);
- }
-
- public int getIntVar(int index) {
- return Integer.parseInt(mVariables.get(index));
- }
-
- public long getLongVar(int index) {
- return Long.parseLong(mVariables.get(index));
- }
-
- private static class Node {
- private HashMap<String, Node> mMap;
- private int mKind = NOT_FOUND;
-
- Node addChild(String segment) {
- if (mMap == null) {
- mMap = new HashMap<String, Node>();
- } else {
- Node node = mMap.get(segment);
- if (node != null) return node;
- }
-
- Node n = new Node();
- mMap.put(segment, n);
- return n;
- }
-
- Node getChild(String segment) {
- if (mMap == null) return null;
- return mMap.get(segment);
- }
-
- void setKind(int kind) {
- mKind = kind;
- }
-
- int getKind() {
- return mKind;
- }
- }
-}
diff --git a/src/com/android/gallery3d/data/SecureAlbum.java b/src/com/android/gallery3d/data/SecureAlbum.java
deleted file mode 100644
index 204f848f8..000000000
--- a/src/com/android/gallery3d/data/SecureAlbum.java
+++ /dev/null
@@ -1,206 +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.data;
-
-import android.content.Context;
-import android.database.Cursor;
-import android.net.Uri;
-import android.provider.MediaStore.Images;
-import android.provider.MediaStore.MediaColumns;
-import android.provider.MediaStore.Video;
-
-import com.android.gallery3d.app.GalleryApp;
-import com.android.gallery3d.app.StitchingChangeListener;
-import com.android.gallery3d.util.MediaSetUtils;
-
-import java.util.ArrayList;
-
-// This class lists all media items added by the client.
-public class SecureAlbum extends MediaSet implements StitchingChangeListener {
- @SuppressWarnings("unused")
- private static final String TAG = "SecureAlbum";
- private static final String[] PROJECTION = {MediaColumns._ID};
- private int mMinImageId = Integer.MAX_VALUE; // the smallest id of images
- private int mMaxImageId = Integer.MIN_VALUE; // the biggest id in images
- private int mMinVideoId = Integer.MAX_VALUE; // the smallest id of videos
- private int mMaxVideoId = Integer.MIN_VALUE; // the biggest id of videos
- // All the media items added by the client.
- private ArrayList<Path> mAllItems = new ArrayList<Path>();
- // The types of items in mAllItems. True is video and false is image.
- private ArrayList<Boolean> mAllItemTypes = new ArrayList<Boolean>();
- private ArrayList<Path> mExistingItems = new ArrayList<Path>();
- private Context mContext;
- private DataManager mDataManager;
- private static final Uri[] mWatchUris =
- {Images.Media.EXTERNAL_CONTENT_URI, Video.Media.EXTERNAL_CONTENT_URI};
- private final ChangeNotifier mNotifier;
- // A placeholder image in the end of secure album. When it is tapped, it
- // will take the user to the lock screen.
- private MediaItem mUnlockItem;
- private boolean mShowUnlockItem;
-
- public SecureAlbum(Path path, GalleryApp application, MediaItem unlock) {
- super(path, nextVersionNumber());
- mContext = application.getAndroidContext();
- mDataManager = application.getDataManager();
- mNotifier = new ChangeNotifier(this, mWatchUris, application);
- mUnlockItem = unlock;
- mShowUnlockItem = (!isCameraBucketEmpty(Images.Media.EXTERNAL_CONTENT_URI)
- || !isCameraBucketEmpty(Video.Media.EXTERNAL_CONTENT_URI));
- }
-
- public void addMediaItem(boolean isVideo, int id) {
- Path pathBase;
- if (isVideo) {
- pathBase = LocalVideo.ITEM_PATH;
- mMinVideoId = Math.min(mMinVideoId, id);
- mMaxVideoId = Math.max(mMaxVideoId, id);
- } else {
- pathBase = LocalImage.ITEM_PATH;
- mMinImageId = Math.min(mMinImageId, id);
- mMaxImageId = Math.max(mMaxImageId, id);
- }
- Path path = pathBase.getChild(id);
- if (!mAllItems.contains(path)) {
- mAllItems.add(path);
- mAllItemTypes.add(isVideo);
- mNotifier.fakeChange();
- }
- }
-
- // The sequence is stitching items, local media items, and unlock image.
- @Override
- public ArrayList<MediaItem> getMediaItem(int start, int count) {
- int existingCount = mExistingItems.size();
- if (start >= existingCount + 1) {
- return new ArrayList<MediaItem>();
- }
-
- // Add paths of requested stitching items.
- int end = Math.min(start + count, existingCount);
- ArrayList<Path> subset = new ArrayList<Path>(mExistingItems.subList(start, end));
-
- // Convert paths to media items.
- final MediaItem[] buf = new MediaItem[end - start];
- ItemConsumer consumer = new ItemConsumer() {
- @Override
- public void consume(int index, MediaItem item) {
- buf[index] = item;
- }
- };
- mDataManager.mapMediaItems(subset, consumer, 0);
- ArrayList<MediaItem> result = new ArrayList<MediaItem>(end - start);
- for (int i = 0; i < buf.length; i++) {
- result.add(buf[i]);
- }
- if (mShowUnlockItem) result.add(mUnlockItem);
- return result;
- }
-
- @Override
- public int getMediaItemCount() {
- return (mExistingItems.size() + (mShowUnlockItem ? 1 : 0));
- }
-
- @Override
- public String getName() {
- return "secure";
- }
-
- @Override
- public long reload() {
- if (mNotifier.isDirty()) {
- mDataVersion = nextVersionNumber();
- updateExistingItems();
- }
- return mDataVersion;
- }
-
- private ArrayList<Integer> queryExistingIds(Uri uri, int minId, int maxId) {
- ArrayList<Integer> ids = new ArrayList<Integer>();
- if (minId == Integer.MAX_VALUE || maxId == Integer.MIN_VALUE) return ids;
-
- String[] selectionArgs = {String.valueOf(minId), String.valueOf(maxId)};
- Cursor cursor = mContext.getContentResolver().query(uri, PROJECTION,
- "_id BETWEEN ? AND ?", selectionArgs, null);
- if (cursor == null) return ids;
- try {
- while (cursor.moveToNext()) {
- ids.add(cursor.getInt(0));
- }
- } finally {
- cursor.close();
- }
- return ids;
- }
-
- private boolean isCameraBucketEmpty(Uri baseUri) {
- Uri uri = baseUri.buildUpon()
- .appendQueryParameter("limit", "1").build();
- String[] selection = {String.valueOf(MediaSetUtils.CAMERA_BUCKET_ID)};
- Cursor cursor = mContext.getContentResolver().query(uri, PROJECTION,
- "bucket_id = ?", selection, null);
- if (cursor == null) return true;
- try {
- return (cursor.getCount() == 0);
- } finally {
- cursor.close();
- }
- }
-
- private void updateExistingItems() {
- if (mAllItems.size() == 0) return;
-
- // Query existing ids.
- ArrayList<Integer> imageIds = queryExistingIds(
- Images.Media.EXTERNAL_CONTENT_URI, mMinImageId, mMaxImageId);
- ArrayList<Integer> videoIds = queryExistingIds(
- Video.Media.EXTERNAL_CONTENT_URI, mMinVideoId, mMaxVideoId);
-
- // Construct the existing items list.
- mExistingItems.clear();
- for (int i = mAllItems.size() - 1; i >= 0; i--) {
- Path path = mAllItems.get(i);
- boolean isVideo = mAllItemTypes.get(i);
- int id = Integer.parseInt(path.getSuffix());
- if (isVideo) {
- if (videoIds.contains(id)) mExistingItems.add(path);
- } else {
- if (imageIds.contains(id)) mExistingItems.add(path);
- }
- }
- }
-
- @Override
- public boolean isLeafAlbum() {
- return true;
- }
-
- @Override
- public void onStitchingQueued(Uri uri) {
- int id = Integer.parseInt(uri.getLastPathSegment());
- addMediaItem(false, id);
- }
-
- @Override
- public void onStitchingResult(Uri uri) {
- }
-
- @Override
- public void onStitchingProgress(Uri uri, final int progress) {
- }
-}
diff --git a/src/com/android/gallery3d/data/SecureSource.java b/src/com/android/gallery3d/data/SecureSource.java
deleted file mode 100644
index 6bc8cc295..000000000
--- a/src/com/android/gallery3d/data/SecureSource.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.data;
-
-import com.android.gallery3d.app.GalleryApp;
-
-public class SecureSource extends MediaSource {
- private GalleryApp mApplication;
- private static PathMatcher mMatcher = new PathMatcher();
- private static final int SECURE_ALBUM = 0;
- private static final int SECURE_UNLOCK = 1;
-
- static {
- mMatcher.add("/secure/all/*", SECURE_ALBUM);
- mMatcher.add("/secure/unlock", SECURE_UNLOCK);
- }
-
- public SecureSource(GalleryApp context) {
- super("secure");
- mApplication = context;
- }
-
- public static boolean isSecurePath(String path) {
- return (SECURE_ALBUM == mMatcher.match(Path.fromString(path)));
- }
-
- @Override
- public MediaObject createMediaObject(Path path) {
- switch (mMatcher.match(path)) {
- case SECURE_ALBUM: {
- DataManager dataManager = mApplication.getDataManager();
- MediaItem unlock = (MediaItem) dataManager.getMediaObject(
- "/secure/unlock");
- return new SecureAlbum(path, mApplication, unlock);
- }
- case SECURE_UNLOCK:
- return new UnlockImage(path, mApplication);
- default:
- throw new RuntimeException("bad path: " + path);
- }
- }
-}
diff --git a/src/com/android/gallery3d/data/SingleItemAlbum.java b/src/com/android/gallery3d/data/SingleItemAlbum.java
deleted file mode 100644
index a0093e0c3..000000000
--- a/src/com/android/gallery3d/data/SingleItemAlbum.java
+++ /dev/null
@@ -1,68 +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.data;
-
-import java.util.ArrayList;
-
-public class SingleItemAlbum extends MediaSet {
- @SuppressWarnings("unused")
- private static final String TAG = "SingleItemAlbum";
- private final MediaItem mItem;
- private final String mName;
-
- public SingleItemAlbum(Path path, MediaItem item) {
- super(path, nextVersionNumber());
- mItem = item;
- mName = "SingleItemAlbum("+mItem.getClass().getSimpleName()+")";
- }
-
- @Override
- public int getMediaItemCount() {
- return 1;
- }
-
- @Override
- public ArrayList<MediaItem> getMediaItem(int start, int count) {
- ArrayList<MediaItem> result = new ArrayList<MediaItem>();
-
- // If [start, start+count) contains the index 0, return the item.
- if (start <= 0 && start + count > 0) {
- result.add(mItem);
- }
-
- return result;
- }
-
- public MediaItem getItem() {
- return mItem;
- }
-
- @Override
- public boolean isLeafAlbum() {
- return true;
- }
-
- @Override
- public String getName() {
- return mName;
- }
-
- @Override
- public long reload() {
- return mDataVersion;
- }
-}
diff --git a/src/com/android/gallery3d/data/SizeClustering.java b/src/com/android/gallery3d/data/SizeClustering.java
deleted file mode 100644
index b809c841b..000000000
--- a/src/com/android/gallery3d/data/SizeClustering.java
+++ /dev/null
@@ -1,141 +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.data;
-
-import android.content.Context;
-import android.content.res.Resources;
-
-import com.android.gallery3d.R;
-
-import java.util.ArrayList;
-
-public class SizeClustering extends Clustering {
- @SuppressWarnings("unused")
- private static final String TAG = "SizeClustering";
-
- private Context mContext;
- private ArrayList<Path>[] mClusters;
- private String[] mNames;
- private long mMinSizes[];
-
- private static final long MEGA_BYTES = 1024L*1024;
- private static final long GIGA_BYTES = 1024L*1024*1024;
-
- private static final long[] SIZE_LEVELS = {
- 0,
- 1 * MEGA_BYTES,
- 10 * MEGA_BYTES,
- 100 * MEGA_BYTES,
- 1 * GIGA_BYTES,
- 2 * GIGA_BYTES,
- 4 * GIGA_BYTES,
- };
-
- public SizeClustering(Context context) {
- mContext = context;
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public void run(MediaSet baseSet) {
- @SuppressWarnings("unchecked")
- final ArrayList<Path>[] group = new ArrayList[SIZE_LEVELS.length];
- baseSet.enumerateTotalMediaItems(new MediaSet.ItemConsumer() {
- @Override
- public void consume(int index, MediaItem item) {
- // Find the cluster this item belongs to.
- long size = item.getSize();
- int i;
- for (i = 0; i < SIZE_LEVELS.length - 1; i++) {
- if (size < SIZE_LEVELS[i + 1]) {
- break;
- }
- }
-
- ArrayList<Path> list = group[i];
- if (list == null) {
- list = new ArrayList<Path>();
- group[i] = list;
- }
- list.add(item.getPath());
- }
- });
-
- int count = 0;
- for (int i = 0; i < group.length; i++) {
- if (group[i] != null) {
- count++;
- }
- }
-
- mClusters = new ArrayList[count];
- mNames = new String[count];
- mMinSizes = new long[count];
-
- Resources res = mContext.getResources();
- int k = 0;
- // Go through group in the reverse order, so the group with the largest
- // size will show first.
- for (int i = group.length - 1; i >= 0; i--) {
- if (group[i] == null) continue;
-
- mClusters[k] = group[i];
- if (i == 0) {
- mNames[k] = String.format(
- res.getString(R.string.size_below), getSizeString(i + 1));
- } else if (i == group.length - 1) {
- mNames[k] = String.format(
- res.getString(R.string.size_above), getSizeString(i));
- } else {
- String minSize = getSizeString(i);
- String maxSize = getSizeString(i + 1);
- mNames[k] = String.format(
- res.getString(R.string.size_between), minSize, maxSize);
- }
- mMinSizes[k] = SIZE_LEVELS[i];
- k++;
- }
- }
-
- private String getSizeString(int index) {
- long bytes = SIZE_LEVELS[index];
- if (bytes >= GIGA_BYTES) {
- return (bytes / GIGA_BYTES) + "GB";
- } else {
- return (bytes / MEGA_BYTES) + "MB";
- }
- }
-
- @Override
- public int getNumberOfClusters() {
- return mClusters.length;
- }
-
- @Override
- public ArrayList<Path> getCluster(int index) {
- return mClusters[index];
- }
-
- @Override
- public String getClusterName(int index) {
- return mNames[index];
- }
-
- public long getMinSize(int index) {
- return mMinSizes[index];
- }
-}
diff --git a/src/com/android/gallery3d/data/SnailAlbum.java b/src/com/android/gallery3d/data/SnailAlbum.java
deleted file mode 100644
index 7bce7a695..000000000
--- a/src/com/android/gallery3d/data/SnailAlbum.java
+++ /dev/null
@@ -1,44 +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.data;
-
-import java.util.concurrent.atomic.AtomicBoolean;
-
-// This is a simple MediaSet which contains only one MediaItem -- a SnailItem.
-public class SnailAlbum extends SingleItemAlbum {
- @SuppressWarnings("unused")
- private static final String TAG = "SnailAlbum";
- private AtomicBoolean mDirty = new AtomicBoolean(false);
-
- public SnailAlbum(Path path, SnailItem item) {
- super(path, item);
- }
-
- @Override
- public long reload() {
- if (mDirty.compareAndSet(true, false)) {
- ((SnailItem) getItem()).updateVersion();
- mDataVersion = nextVersionNumber();
- }
- return mDataVersion;
- }
-
- public void notifyChange() {
- mDirty.set(true);
- notifyContentChanged();
- }
-}
diff --git a/src/com/android/gallery3d/data/SnailItem.java b/src/com/android/gallery3d/data/SnailItem.java
deleted file mode 100644
index 3586d2cab..000000000
--- a/src/com/android/gallery3d/data/SnailItem.java
+++ /dev/null
@@ -1,95 +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.data;
-
-import android.graphics.Bitmap;
-import android.graphics.BitmapRegionDecoder;
-
-import com.android.gallery3d.ui.ScreenNail;
-import com.android.gallery3d.util.ThreadPool.Job;
-import com.android.gallery3d.util.ThreadPool.JobContext;
-
-// SnailItem is a MediaItem which can provide a ScreenNail. This is
-// used so we can show an foreign component (like an
-// android.view.View) instead of a Bitmap.
-public class SnailItem extends MediaItem {
- @SuppressWarnings("unused")
- private static final String TAG = "SnailItem";
- private ScreenNail mScreenNail;
-
- public SnailItem(Path path) {
- super(path, nextVersionNumber());
- }
-
- @Override
- public Job<Bitmap> requestImage(int type) {
- // nothing to return
- return new Job<Bitmap>() {
- @Override
- public Bitmap run(JobContext jc) {
- return null;
- }
- };
- }
-
- @Override
- public Job<BitmapRegionDecoder> requestLargeImage() {
- // nothing to return
- return new Job<BitmapRegionDecoder>() {
- @Override
- public BitmapRegionDecoder run(JobContext jc) {
- return null;
- }
- };
- }
-
- // We do not provide requestImage or requestLargeImage, instead we
- // provide a ScreenNail.
- @Override
- public ScreenNail getScreenNail() {
- return mScreenNail;
- }
-
- @Override
- public String getMimeType() {
- return "";
- }
-
- // Returns width and height of the media item.
- // Returns 0, 0 if the information is not available.
- @Override
- public int getWidth() {
- return 0;
- }
-
- @Override
- public int getHeight() {
- return 0;
- }
-
- //////////////////////////////////////////////////////////////////////////
- // Extra methods for SnailItem
- //////////////////////////////////////////////////////////////////////////
-
- public void setScreenNail(ScreenNail screenNail) {
- mScreenNail = screenNail;
- }
-
- public void updateVersion() {
- mDataVersion = nextVersionNumber();
- }
-}
diff --git a/src/com/android/gallery3d/data/SnailSource.java b/src/com/android/gallery3d/data/SnailSource.java
deleted file mode 100644
index 5c690ccdb..000000000
--- a/src/com/android/gallery3d/data/SnailSource.java
+++ /dev/null
@@ -1,70 +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.data;
-
-import com.android.gallery3d.app.GalleryApp;
-
-public class SnailSource extends MediaSource {
- @SuppressWarnings("unused")
- private static final String TAG = "SnailSource";
- private static final int SNAIL_ALBUM = 0;
- private static final int SNAIL_ITEM = 1;
-
- private GalleryApp mApplication;
- private PathMatcher mMatcher;
- private static int sNextId;
-
- public SnailSource(GalleryApp application) {
- super("snail");
- mApplication = application;
- mMatcher = new PathMatcher();
- mMatcher.add("/snail/set/*", SNAIL_ALBUM);
- mMatcher.add("/snail/item/*", SNAIL_ITEM);
- }
-
- // The only path we accept is "/snail/set/id" and "/snail/item/id"
- @Override
- public MediaObject createMediaObject(Path path) {
- DataManager dataManager = mApplication.getDataManager();
- switch (mMatcher.match(path)) {
- case SNAIL_ALBUM:
- String itemPath = "/snail/item/" + mMatcher.getVar(0);
- SnailItem item =
- (SnailItem) dataManager.getMediaObject(itemPath);
- return new SnailAlbum(path, item);
- case SNAIL_ITEM: {
- int id = mMatcher.getIntVar(0);
- return new SnailItem(path);
- }
- }
- return null;
- }
-
- // Registers a new SnailAlbum containing a SnailItem and returns the id of
- // them. You can obtain the Path of the SnailAlbum and SnailItem associated
- // with the id by getSetPath and getItemPath().
- public static synchronized int newId() {
- return sNextId++;
- }
-
- public static Path getSetPath(int id) {
- return Path.fromString("/snail/set").getChild(id);
- }
-
- public static Path getItemPath(int id) {
- return Path.fromString("/snail/item").getChild(id);
- }
-}
diff --git a/src/com/android/gallery3d/data/TagClustering.java b/src/com/android/gallery3d/data/TagClustering.java
deleted file mode 100644
index 407ca84c4..000000000
--- a/src/com/android/gallery3d/data/TagClustering.java
+++ /dev/null
@@ -1,95 +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.data;
-
-import android.content.Context;
-
-import com.android.gallery3d.R;
-
-import java.util.ArrayList;
-import java.util.Map;
-import java.util.TreeMap;
-
-public class TagClustering extends Clustering {
- @SuppressWarnings("unused")
- private static final String TAG = "TagClustering";
-
- private ArrayList<ArrayList<Path>> mClusters;
- private String[] mNames;
- private String mUntaggedString;
-
- public TagClustering(Context context) {
- mUntaggedString = context.getResources().getString(R.string.untagged);
- }
-
- @Override
- public void run(MediaSet baseSet) {
- final TreeMap<String, ArrayList<Path>> map =
- new TreeMap<String, ArrayList<Path>>();
- final ArrayList<Path> untagged = new ArrayList<Path>();
-
- baseSet.enumerateTotalMediaItems(new MediaSet.ItemConsumer() {
- @Override
- public void consume(int index, MediaItem item) {
- Path path = item.getPath();
-
- String[] tags = item.getTags();
- if (tags == null || tags.length == 0) {
- untagged.add(path);
- return;
- }
- for (int j = 0; j < tags.length; j++) {
- String key = tags[j];
- ArrayList<Path> list = map.get(key);
- if (list == null) {
- list = new ArrayList<Path>();
- map.put(key, list);
- }
- list.add(path);
- }
- }
- });
-
- int m = map.size();
- mClusters = new ArrayList<ArrayList<Path>>();
- mNames = new String[m + ((untagged.size() > 0) ? 1 : 0)];
- int i = 0;
- for (Map.Entry<String, ArrayList<Path>> entry : map.entrySet()) {
- mNames[i++] = entry.getKey();
- mClusters.add(entry.getValue());
- }
- if (untagged.size() > 0) {
- mNames[i++] = mUntaggedString;
- mClusters.add(untagged);
- }
- }
-
- @Override
- public int getNumberOfClusters() {
- return mClusters.size();
- }
-
- @Override
- public ArrayList<Path> getCluster(int index) {
- return mClusters.get(index);
- }
-
- @Override
- public String getClusterName(int index) {
- return mNames[index];
- }
-}
diff --git a/src/com/android/gallery3d/data/TimeClustering.java b/src/com/android/gallery3d/data/TimeClustering.java
deleted file mode 100644
index 35cbab1ee..000000000
--- a/src/com/android/gallery3d/data/TimeClustering.java
+++ /dev/null
@@ -1,439 +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.data;
-
-import android.content.Context;
-import android.text.format.DateFormat;
-import android.text.format.DateUtils;
-
-import com.android.gallery3d.common.Utils;
-import com.android.gallery3d.util.GalleryUtils;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-
-public class TimeClustering extends Clustering {
- @SuppressWarnings("unused")
- private static final String TAG = "TimeClustering";
-
- // If 2 items are greater than 25 miles apart, they will be in different
- // clusters.
- private static final int GEOGRAPHIC_DISTANCE_CUTOFF_IN_MILES = 20;
-
- // Do not want to split based on anything under 1 min.
- private static final long MIN_CLUSTER_SPLIT_TIME_IN_MS = 60000L;
-
- // Disregard a cluster split time of anything over 2 hours.
- private static final long MAX_CLUSTER_SPLIT_TIME_IN_MS = 7200000L;
-
- // Try and get around 9 clusters (best-effort for the common case).
- private static final int NUM_CLUSTERS_TARGETED = 9;
-
- // Try and merge 2 clusters if they are both smaller than min cluster size.
- // The min cluster size can range from 8 to 15.
- private static final int MIN_MIN_CLUSTER_SIZE = 8;
- private static final int MAX_MIN_CLUSTER_SIZE = 15;
-
- // Try and split a cluster if it is bigger than max cluster size.
- // The max cluster size can range from 20 to 50.
- private static final int MIN_MAX_CLUSTER_SIZE = 20;
- private static final int MAX_MAX_CLUSTER_SIZE = 50;
-
- // Initially put 2 items in the same cluster as long as they are within
- // 3 cluster frequencies of each other.
- private static int CLUSTER_SPLIT_MULTIPLIER = 3;
-
- // The minimum change factor in the time between items to consider a
- // partition.
- // Example: (Item 3 - Item 2) / (Item 2 - Item 1).
- private static final int MIN_PARTITION_CHANGE_FACTOR = 2;
-
- // Make the cluster split time of a large cluster half that of a regular
- // cluster.
- private static final int PARTITION_CLUSTER_SPLIT_TIME_FACTOR = 2;
-
- private Context mContext;
- private ArrayList<Cluster> mClusters;
- private String[] mNames;
- private Cluster mCurrCluster;
-
- private long mClusterSplitTime =
- (MIN_CLUSTER_SPLIT_TIME_IN_MS + MAX_CLUSTER_SPLIT_TIME_IN_MS) / 2;
- private long mLargeClusterSplitTime =
- mClusterSplitTime / PARTITION_CLUSTER_SPLIT_TIME_FACTOR;
- private int mMinClusterSize = (MIN_MIN_CLUSTER_SIZE + MAX_MIN_CLUSTER_SIZE) / 2;
- private int mMaxClusterSize = (MIN_MAX_CLUSTER_SIZE + MAX_MAX_CLUSTER_SIZE) / 2;
-
-
- private static final Comparator<SmallItem> sDateComparator =
- new DateComparator();
-
- private static class DateComparator implements Comparator<SmallItem> {
- @Override
- public int compare(SmallItem item1, SmallItem item2) {
- return -Utils.compare(item1.dateInMs, item2.dateInMs);
- }
- }
-
- public TimeClustering(Context context) {
- mContext = context;
- mClusters = new ArrayList<Cluster>();
- mCurrCluster = new Cluster();
- }
-
- @Override
- public void run(MediaSet baseSet) {
- final int total = baseSet.getTotalMediaItemCount();
- final SmallItem[] buf = new SmallItem[total];
- final double[] latLng = new double[2];
-
- baseSet.enumerateTotalMediaItems(new MediaSet.ItemConsumer() {
- @Override
- public void consume(int index, MediaItem item) {
- if (index < 0 || index >= total) return;
- SmallItem s = new SmallItem();
- s.path = item.getPath();
- s.dateInMs = item.getDateInMs();
- item.getLatLong(latLng);
- s.lat = latLng[0];
- s.lng = latLng[1];
- buf[index] = s;
- }
- });
-
- ArrayList<SmallItem> items = new ArrayList<SmallItem>(total);
- for (int i = 0; i < total; i++) {
- if (buf[i] != null) {
- items.add(buf[i]);
- }
- }
-
- Collections.sort(items, sDateComparator);
-
- int n = items.size();
- long minTime = 0;
- long maxTime = 0;
- for (int i = 0; i < n; i++) {
- long t = items.get(i).dateInMs;
- if (t == 0) continue;
- if (minTime == 0) {
- minTime = maxTime = t;
- } else {
- minTime = Math.min(minTime, t);
- maxTime = Math.max(maxTime, t);
- }
- }
-
- setTimeRange(maxTime - minTime, n);
-
- for (int i = 0; i < n; i++) {
- compute(items.get(i));
- }
-
- compute(null);
-
- int m = mClusters.size();
- mNames = new String[m];
- for (int i = 0; i < m; i++) {
- mNames[i] = mClusters.get(i).generateCaption(mContext);
- }
- }
-
- @Override
- public int getNumberOfClusters() {
- return mClusters.size();
- }
-
- @Override
- public ArrayList<Path> getCluster(int index) {
- ArrayList<SmallItem> items = mClusters.get(index).getItems();
- ArrayList<Path> result = new ArrayList<Path>(items.size());
- for (int i = 0, n = items.size(); i < n; i++) {
- result.add(items.get(i).path);
- }
- return result;
- }
-
- @Override
- public String getClusterName(int index) {
- return mNames[index];
- }
-
- private void setTimeRange(long timeRange, int numItems) {
- if (numItems != 0) {
- int meanItemsPerCluster = numItems / NUM_CLUSTERS_TARGETED;
- // Heuristic to get min and max cluster size - half and double the
- // desired items per cluster.
- mMinClusterSize = meanItemsPerCluster / 2;
- mMaxClusterSize = meanItemsPerCluster * 2;
- mClusterSplitTime = timeRange / numItems * CLUSTER_SPLIT_MULTIPLIER;
- }
- mClusterSplitTime = Utils.clamp(mClusterSplitTime, MIN_CLUSTER_SPLIT_TIME_IN_MS, MAX_CLUSTER_SPLIT_TIME_IN_MS);
- mLargeClusterSplitTime = mClusterSplitTime / PARTITION_CLUSTER_SPLIT_TIME_FACTOR;
- mMinClusterSize = Utils.clamp(mMinClusterSize, MIN_MIN_CLUSTER_SIZE, MAX_MIN_CLUSTER_SIZE);
- mMaxClusterSize = Utils.clamp(mMaxClusterSize, MIN_MAX_CLUSTER_SIZE, MAX_MAX_CLUSTER_SIZE);
- }
-
- private void compute(SmallItem currentItem) {
- if (currentItem != null) {
- int numClusters = mClusters.size();
- int numCurrClusterItems = mCurrCluster.size();
- boolean geographicallySeparateItem = false;
- boolean itemAddedToCurrentCluster = false;
-
- // Determine if this item should go in the current cluster or be the
- // start of a new cluster.
- if (numCurrClusterItems == 0) {
- mCurrCluster.addItem(currentItem);
- } else {
- SmallItem prevItem = mCurrCluster.getLastItem();
- if (isGeographicallySeparated(prevItem, currentItem)) {
- mClusters.add(mCurrCluster);
- geographicallySeparateItem = true;
- } else if (numCurrClusterItems > mMaxClusterSize) {
- splitAndAddCurrentCluster();
- } else if (timeDistance(prevItem, currentItem) < mClusterSplitTime) {
- mCurrCluster.addItem(currentItem);
- itemAddedToCurrentCluster = true;
- } else if (numClusters > 0 && numCurrClusterItems < mMinClusterSize
- && !mCurrCluster.mGeographicallySeparatedFromPrevCluster) {
- mergeAndAddCurrentCluster();
- } else {
- mClusters.add(mCurrCluster);
- }
-
- // Creating a new cluster and adding the current item to it.
- if (!itemAddedToCurrentCluster) {
- mCurrCluster = new Cluster();
- if (geographicallySeparateItem) {
- mCurrCluster.mGeographicallySeparatedFromPrevCluster = true;
- }
- mCurrCluster.addItem(currentItem);
- }
- }
- } else {
- if (mCurrCluster.size() > 0) {
- int numClusters = mClusters.size();
- int numCurrClusterItems = mCurrCluster.size();
-
- // The last cluster may potentially be too big or too small.
- if (numCurrClusterItems > mMaxClusterSize) {
- splitAndAddCurrentCluster();
- } else if (numClusters > 0 && numCurrClusterItems < mMinClusterSize
- && !mCurrCluster.mGeographicallySeparatedFromPrevCluster) {
- mergeAndAddCurrentCluster();
- } else {
- mClusters.add(mCurrCluster);
- }
- mCurrCluster = new Cluster();
- }
- }
- }
-
- private void splitAndAddCurrentCluster() {
- ArrayList<SmallItem> currClusterItems = mCurrCluster.getItems();
- int numCurrClusterItems = mCurrCluster.size();
- int secondPartitionStartIndex = getPartitionIndexForCurrentCluster();
- if (secondPartitionStartIndex != -1) {
- Cluster partitionedCluster = new Cluster();
- for (int j = 0; j < secondPartitionStartIndex; j++) {
- partitionedCluster.addItem(currClusterItems.get(j));
- }
- mClusters.add(partitionedCluster);
- partitionedCluster = new Cluster();
- for (int j = secondPartitionStartIndex; j < numCurrClusterItems; j++) {
- partitionedCluster.addItem(currClusterItems.get(j));
- }
- mClusters.add(partitionedCluster);
- } else {
- mClusters.add(mCurrCluster);
- }
- }
-
- private int getPartitionIndexForCurrentCluster() {
- int partitionIndex = -1;
- float largestChange = MIN_PARTITION_CHANGE_FACTOR;
- ArrayList<SmallItem> currClusterItems = mCurrCluster.getItems();
- int numCurrClusterItems = mCurrCluster.size();
- int minClusterSize = mMinClusterSize;
-
- // Could be slightly more efficient here but this code seems cleaner.
- if (numCurrClusterItems > minClusterSize + 1) {
- for (int i = minClusterSize; i < numCurrClusterItems - minClusterSize; i++) {
- SmallItem prevItem = currClusterItems.get(i - 1);
- SmallItem currItem = currClusterItems.get(i);
- SmallItem nextItem = currClusterItems.get(i + 1);
-
- long timeNext = nextItem.dateInMs;
- long timeCurr = currItem.dateInMs;
- long timePrev = prevItem.dateInMs;
-
- if (timeNext == 0 || timeCurr == 0 || timePrev == 0) continue;
-
- long diff1 = Math.abs(timeNext - timeCurr);
- long diff2 = Math.abs(timeCurr - timePrev);
-
- float change = Math.max(diff1 / (diff2 + 0.01f), diff2 / (diff1 + 0.01f));
- if (change > largestChange) {
- if (timeDistance(currItem, prevItem) > mLargeClusterSplitTime) {
- partitionIndex = i;
- largestChange = change;
- } else if (timeDistance(nextItem, currItem) > mLargeClusterSplitTime) {
- partitionIndex = i + 1;
- largestChange = change;
- }
- }
- }
- }
- return partitionIndex;
- }
-
- private void mergeAndAddCurrentCluster() {
- int numClusters = mClusters.size();
- Cluster prevCluster = mClusters.get(numClusters - 1);
- ArrayList<SmallItem> currClusterItems = mCurrCluster.getItems();
- int numCurrClusterItems = mCurrCluster.size();
- if (prevCluster.size() < mMinClusterSize) {
- for (int i = 0; i < numCurrClusterItems; i++) {
- prevCluster.addItem(currClusterItems.get(i));
- }
- mClusters.set(numClusters - 1, prevCluster);
- } else {
- mClusters.add(mCurrCluster);
- }
- }
-
- // Returns true if a, b are sufficiently geographically separated.
- private static boolean isGeographicallySeparated(SmallItem itemA, SmallItem itemB) {
- if (!GalleryUtils.isValidLocation(itemA.lat, itemA.lng)
- || !GalleryUtils.isValidLocation(itemB.lat, itemB.lng)) {
- return false;
- }
-
- double distance = GalleryUtils.fastDistanceMeters(
- Math.toRadians(itemA.lat),
- Math.toRadians(itemA.lng),
- Math.toRadians(itemB.lat),
- Math.toRadians(itemB.lng));
- return (GalleryUtils.toMile(distance) > GEOGRAPHIC_DISTANCE_CUTOFF_IN_MILES);
- }
-
- // Returns the time interval between the two items in milliseconds.
- private static long timeDistance(SmallItem a, SmallItem b) {
- return Math.abs(a.dateInMs - b.dateInMs);
- }
-}
-
-class SmallItem {
- Path path;
- long dateInMs;
- double lat, lng;
-}
-
-class Cluster {
- @SuppressWarnings("unused")
- private static final String TAG = "Cluster";
- private static final String MMDDYY_FORMAT = "MMddyy";
-
- // This is for TimeClustering only.
- public boolean mGeographicallySeparatedFromPrevCluster = false;
-
- private ArrayList<SmallItem> mItems = new ArrayList<SmallItem>();
-
- public Cluster() {
- }
-
- public void addItem(SmallItem item) {
- mItems.add(item);
- }
-
- public int size() {
- return mItems.size();
- }
-
- public SmallItem getLastItem() {
- int n = mItems.size();
- return (n == 0) ? null : mItems.get(n - 1);
- }
-
- public ArrayList<SmallItem> getItems() {
- return mItems;
- }
-
- public String generateCaption(Context context) {
- int n = mItems.size();
- long minTimestamp = 0;
- long maxTimestamp = 0;
-
- for (int i = 0; i < n; i++) {
- long t = mItems.get(i).dateInMs;
- if (t == 0) continue;
- if (minTimestamp == 0) {
- minTimestamp = maxTimestamp = t;
- } else {
- minTimestamp = Math.min(minTimestamp, t);
- maxTimestamp = Math.max(maxTimestamp, t);
- }
- }
- if (minTimestamp == 0) return "";
-
- String caption;
- String minDay = DateFormat.format(MMDDYY_FORMAT, minTimestamp)
- .toString();
- String maxDay = DateFormat.format(MMDDYY_FORMAT, maxTimestamp)
- .toString();
-
- if (minDay.substring(4).equals(maxDay.substring(4))) {
- // The items are from the same year - show at least as
- // much granularity as abbrev_all allows.
- caption = DateUtils.formatDateRange(context, minTimestamp,
- maxTimestamp, DateUtils.FORMAT_ABBREV_ALL);
-
- // Get a more granular date range string if the min and
- // max timestamp are on the same day and from the
- // current year.
- if (minDay.equals(maxDay)) {
- int flags = DateUtils.FORMAT_ABBREV_MONTH | DateUtils.FORMAT_SHOW_DATE;
- // Contains the year only if the date does not
- // correspond to the current year.
- String dateRangeWithOptionalYear = DateUtils.formatDateTime(
- context, minTimestamp, flags);
- String dateRangeWithYear = DateUtils.formatDateTime(
- context, minTimestamp, flags | DateUtils.FORMAT_SHOW_YEAR);
- if (!dateRangeWithOptionalYear.equals(dateRangeWithYear)) {
- // This means both dates are from the same year
- // - show the time.
- // Not enough room to display the time range.
- // Pick the mid-point.
- long midTimestamp = (minTimestamp + maxTimestamp) / 2;
- caption = DateUtils.formatDateRange(context, midTimestamp,
- midTimestamp, DateUtils.FORMAT_SHOW_TIME | flags);
- }
- }
- } else {
- // The items are not from the same year - only show
- // month and year.
- int flags = DateUtils.FORMAT_NO_MONTH_DAY
- | DateUtils.FORMAT_ABBREV_MONTH | DateUtils.FORMAT_SHOW_DATE;
- caption = DateUtils.formatDateRange(context, minTimestamp,
- maxTimestamp, flags);
- }
-
- return caption;
- }
-}
diff --git a/src/com/android/gallery3d/data/UnlockImage.java b/src/com/android/gallery3d/data/UnlockImage.java
deleted file mode 100644
index ed3b485c4..000000000
--- a/src/com/android/gallery3d/data/UnlockImage.java
+++ /dev/null
@@ -1,34 +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.data;
-
-import com.android.gallery3d.R;
-import com.android.gallery3d.app.GalleryApp;
-
-public class UnlockImage extends ActionImage {
- @SuppressWarnings("unused")
- private static final String TAG = "UnlockImage";
-
- public UnlockImage(Path path, GalleryApp application) {
- super(path, application, R.drawable.placeholder_locked);
- }
-
- @Override
- public int getSupportedOperations() {
- return super.getSupportedOperations() | SUPPORT_UNLOCK;
- }
-}
diff --git a/src/com/android/gallery3d/data/UriImage.java b/src/com/android/gallery3d/data/UriImage.java
deleted file mode 100644
index e8875b572..000000000
--- a/src/com/android/gallery3d/data/UriImage.java
+++ /dev/null
@@ -1,298 +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.data;
-
-import android.content.ContentResolver;
-import android.graphics.Bitmap;
-import android.graphics.Bitmap.Config;
-import android.graphics.BitmapFactory.Options;
-import android.graphics.BitmapRegionDecoder;
-import android.net.Uri;
-import android.os.ParcelFileDescriptor;
-
-import com.android.gallery3d.app.GalleryApp;
-import com.android.gallery3d.app.PanoramaMetadataSupport;
-import com.android.gallery3d.common.BitmapUtils;
-import com.android.gallery3d.common.Utils;
-import com.android.gallery3d.util.ThreadPool.CancelListener;
-import com.android.gallery3d.util.ThreadPool.Job;
-import com.android.gallery3d.util.ThreadPool.JobContext;
-
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.InputStream;
-import java.net.URI;
-import java.net.URL;
-
-public class UriImage extends MediaItem {
- private static final String TAG = "UriImage";
-
- private static final int STATE_INIT = 0;
- private static final int STATE_DOWNLOADING = 1;
- private static final int STATE_DOWNLOADED = 2;
- private static final int STATE_ERROR = -1;
-
- private final Uri mUri;
- private final String mContentType;
-
- private DownloadCache.Entry mCacheEntry;
- private ParcelFileDescriptor mFileDescriptor;
- private int mState = STATE_INIT;
- private int mWidth;
- private int mHeight;
- private int mRotation;
- private PanoramaMetadataSupport mPanoramaMetadata = new PanoramaMetadataSupport(this);
-
- private GalleryApp mApplication;
-
- public UriImage(GalleryApp application, Path path, Uri uri, String contentType) {
- super(path, nextVersionNumber());
- mUri = uri;
- mApplication = Utils.checkNotNull(application);
- mContentType = contentType;
- }
-
- @Override
- public Job<Bitmap> requestImage(int type) {
- return new BitmapJob(type);
- }
-
- @Override
- public Job<BitmapRegionDecoder> requestLargeImage() {
- return new RegionDecoderJob();
- }
-
- private void openFileOrDownloadTempFile(JobContext jc) {
- int state = openOrDownloadInner(jc);
- synchronized (this) {
- mState = state;
- if (mState != STATE_DOWNLOADED) {
- if (mFileDescriptor != null) {
- Utils.closeSilently(mFileDescriptor);
- mFileDescriptor = null;
- }
- }
- notifyAll();
- }
- }
-
- private int openOrDownloadInner(JobContext jc) {
- String scheme = mUri.getScheme();
- if (ContentResolver.SCHEME_CONTENT.equals(scheme)
- || ContentResolver.SCHEME_ANDROID_RESOURCE.equals(scheme)
- || ContentResolver.SCHEME_FILE.equals(scheme)) {
- try {
- if (MIME_TYPE_JPEG.equalsIgnoreCase(mContentType)) {
- InputStream is = mApplication.getContentResolver()
- .openInputStream(mUri);
- mRotation = Exif.getOrientation(is);
- Utils.closeSilently(is);
- }
- mFileDescriptor = mApplication.getContentResolver()
- .openFileDescriptor(mUri, "r");
- if (jc.isCancelled()) return STATE_INIT;
- return STATE_DOWNLOADED;
- } catch (FileNotFoundException e) {
- Log.w(TAG, "fail to open: " + mUri, e);
- return STATE_ERROR;
- }
- } else {
- try {
- URL url = new URI(mUri.toString()).toURL();
- mCacheEntry = mApplication.getDownloadCache().download(jc, url);
- if (jc.isCancelled()) return STATE_INIT;
- if (mCacheEntry == null) {
- Log.w(TAG, "download failed " + url);
- return STATE_ERROR;
- }
- if (MIME_TYPE_JPEG.equalsIgnoreCase(mContentType)) {
- InputStream is = new FileInputStream(mCacheEntry.cacheFile);
- mRotation = Exif.getOrientation(is);
- Utils.closeSilently(is);
- }
- mFileDescriptor = ParcelFileDescriptor.open(
- mCacheEntry.cacheFile, ParcelFileDescriptor.MODE_READ_ONLY);
- return STATE_DOWNLOADED;
- } catch (Throwable t) {
- Log.w(TAG, "download error", t);
- return STATE_ERROR;
- }
- }
- }
-
- private boolean prepareInputFile(JobContext jc) {
- jc.setCancelListener(new CancelListener() {
- @Override
- public void onCancel() {
- synchronized (this) {
- notifyAll();
- }
- }
- });
-
- while (true) {
- synchronized (this) {
- if (jc.isCancelled()) return false;
- if (mState == STATE_INIT) {
- mState = STATE_DOWNLOADING;
- // Then leave the synchronized block and continue.
- } else if (mState == STATE_ERROR) {
- return false;
- } else if (mState == STATE_DOWNLOADED) {
- return true;
- } else /* if (mState == STATE_DOWNLOADING) */ {
- try {
- wait();
- } catch (InterruptedException ex) {
- // ignored.
- }
- continue;
- }
- }
- // This is only reached for STATE_INIT->STATE_DOWNLOADING
- openFileOrDownloadTempFile(jc);
- }
- }
-
- private class RegionDecoderJob implements Job<BitmapRegionDecoder> {
- @Override
- public BitmapRegionDecoder run(JobContext jc) {
- if (!prepareInputFile(jc)) return null;
- BitmapRegionDecoder decoder = DecodeUtils.createBitmapRegionDecoder(
- jc, mFileDescriptor.getFileDescriptor(), false);
- mWidth = decoder.getWidth();
- mHeight = decoder.getHeight();
- return decoder;
- }
- }
-
- private class BitmapJob implements Job<Bitmap> {
- private int mType;
-
- protected BitmapJob(int type) {
- mType = type;
- }
-
- @Override
- public Bitmap run(JobContext jc) {
- if (!prepareInputFile(jc)) return null;
- int targetSize = MediaItem.getTargetSize(mType);
- Options options = new Options();
- options.inPreferredConfig = Config.ARGB_8888;
- Bitmap bitmap = DecodeUtils.decodeThumbnail(jc,
- mFileDescriptor.getFileDescriptor(), options, targetSize, mType);
-
- if (jc.isCancelled() || bitmap == null) {
- return null;
- }
-
- if (mType == MediaItem.TYPE_MICROTHUMBNAIL) {
- bitmap = BitmapUtils.resizeAndCropCenter(bitmap, targetSize, true);
- } else {
- bitmap = BitmapUtils.resizeDownBySideLength(bitmap, targetSize, true);
- }
- return bitmap;
- }
- }
-
- @Override
- public int getSupportedOperations() {
- int supported = SUPPORT_EDIT | SUPPORT_SETAS;
- if (isSharable()) supported |= SUPPORT_SHARE;
- if (BitmapUtils.isSupportedByRegionDecoder(mContentType)) {
- supported |= SUPPORT_FULL_IMAGE;
- }
- return supported;
- }
-
- @Override
- public void getPanoramaSupport(PanoramaSupportCallback callback) {
- mPanoramaMetadata.getPanoramaSupport(mApplication, callback);
- }
-
- @Override
- public void clearCachedPanoramaSupport() {
- mPanoramaMetadata.clearCachedValues();
- }
-
- private boolean isSharable() {
- // We cannot grant read permission to the receiver since we put
- // the data URI in EXTRA_STREAM instead of the data part of an intent
- // And there are issues in MediaUploader and Bluetooth file sender to
- // share a general image data. So, we only share for local file.
- return ContentResolver.SCHEME_FILE.equals(mUri.getScheme());
- }
-
- @Override
- public int getMediaType() {
- return MEDIA_TYPE_IMAGE;
- }
-
- @Override
- public Uri getContentUri() {
- return mUri;
- }
-
- @Override
- public MediaDetails getDetails() {
- MediaDetails details = super.getDetails();
- if (mWidth != 0 && mHeight != 0) {
- details.addDetail(MediaDetails.INDEX_WIDTH, mWidth);
- details.addDetail(MediaDetails.INDEX_HEIGHT, mHeight);
- }
- if (mContentType != null) {
- details.addDetail(MediaDetails.INDEX_MIMETYPE, mContentType);
- }
- if (ContentResolver.SCHEME_FILE.equals(mUri.getScheme())) {
- String filePath = mUri.getPath();
- details.addDetail(MediaDetails.INDEX_PATH, filePath);
- MediaDetails.extractExifInfo(details, filePath);
- }
- return details;
- }
-
- @Override
- public String getMimeType() {
- return mContentType;
- }
-
- @Override
- protected void finalize() throws Throwable {
- try {
- if (mFileDescriptor != null) {
- Utils.closeSilently(mFileDescriptor);
- }
- } finally {
- super.finalize();
- }
- }
-
- @Override
- public int getWidth() {
- return 0;
- }
-
- @Override
- public int getHeight() {
- return 0;
- }
-
- @Override
- public int getRotation() {
- return mRotation;
- }
-}
diff --git a/src/com/android/gallery3d/data/UriSource.java b/src/com/android/gallery3d/data/UriSource.java
deleted file mode 100644
index f66bacd7b..000000000
--- a/src/com/android/gallery3d/data/UriSource.java
+++ /dev/null
@@ -1,95 +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.data;
-
-import android.content.ContentResolver;
-import android.net.Uri;
-import android.webkit.MimeTypeMap;
-
-import com.android.gallery3d.app.GalleryApp;
-
-import java.io.UnsupportedEncodingException;
-import java.net.URLDecoder;
-import java.net.URLEncoder;
-
-class UriSource extends MediaSource {
- @SuppressWarnings("unused")
- private static final String TAG = "UriSource";
- private static final String IMAGE_TYPE_PREFIX = "image/";
- private static final String IMAGE_TYPE_ANY = "image/*";
- private static final String CHARSET_UTF_8 = "utf-8";
-
- private GalleryApp mApplication;
-
- public UriSource(GalleryApp context) {
- super("uri");
- mApplication = context;
- }
-
- @Override
- public MediaObject createMediaObject(Path path) {
- String segment[] = path.split();
- if (segment.length != 3) {
- throw new RuntimeException("bad path: " + path);
- }
- try {
- String uri = URLDecoder.decode(segment[1], CHARSET_UTF_8);
- String type = URLDecoder.decode(segment[2], CHARSET_UTF_8);
- return new UriImage(mApplication, path, Uri.parse(uri), type);
- } catch (UnsupportedEncodingException e) {
- throw new AssertionError(e);
- }
- }
-
- private String getMimeType(Uri uri) {
- if (ContentResolver.SCHEME_FILE.equals(uri.getScheme())) {
- String extension =
- MimeTypeMap.getFileExtensionFromUrl(uri.toString());
- String type = MimeTypeMap.getSingleton()
- .getMimeTypeFromExtension(extension.toLowerCase());
- if (type != null) return type;
- }
- // Assume the type is image if the type cannot be resolved
- // This could happen for "http" URI.
- String type = mApplication.getContentResolver().getType(uri);
- if (type == null) type = "image/*";
- return type;
- }
-
- @Override
- public Path findPathByUri(Uri uri, String type) {
- String mimeType = getMimeType(uri);
-
- // Try to find a most specific type but it has to be started with "image/"
- if ((type == null) || (IMAGE_TYPE_ANY.equals(type)
- && mimeType.startsWith(IMAGE_TYPE_PREFIX))) {
- type = mimeType;
- }
-
- if (type.startsWith(IMAGE_TYPE_PREFIX)) {
- try {
- return Path.fromString("/uri/"
- + URLEncoder.encode(uri.toString(), CHARSET_UTF_8)
- + "/" +URLEncoder.encode(type, CHARSET_UTF_8));
- } catch (UnsupportedEncodingException e) {
- throw new AssertionError(e);
- }
- }
- // We have no clues that it is an image
- return null;
- }
-}