summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOwen Lin <owenlin@google.com>2012-03-16 13:51:49 +0800
committerOwen Lin <owenlin@google.com>2012-03-20 19:22:10 +0800
commit813ba6f4c7f6c36928bf926f7856eb744a823b43 (patch)
treea5f8862f961cbf8b913aae0216ddaac11bb49779
parente80b47691bfc340f76464b97bac5ad6fe9f561de (diff)
downloadandroid_packages_apps_Snap-813ba6f4c7f6c36928bf926f7856eb744a823b43.tar.gz
android_packages_apps_Snap-813ba6f4c7f6c36928bf926f7856eb744a823b43.tar.bz2
android_packages_apps_Snap-813ba6f4c7f6c36928bf926f7856eb744a823b43.zip
Make top level albums can be loaded concurrently.
Change-Id: I1acef9fc9a442c36ad1d9d0931b0defc6091bf33 fix: 5947962
-rw-r--r--src/com/android/gallery3d/data/LocalAlbumSet.java121
-rw-r--r--src/com/android/gallery3d/data/MtpDeviceSet.java72
2 files changed, 124 insertions, 69 deletions
diff --git a/src/com/android/gallery3d/data/LocalAlbumSet.java b/src/com/android/gallery3d/data/LocalAlbumSet.java
index 24d6d32a5..0575e9b65 100644
--- a/src/com/android/gallery3d/data/LocalAlbumSet.java
+++ b/src/com/android/gallery3d/data/LocalAlbumSet.java
@@ -29,15 +29,19 @@ import android.util.Log;
import com.android.gallery3d.R;
import com.android.gallery3d.app.GalleryApp;
import com.android.gallery3d.common.Utils;
-import com.android.gallery3d.util.GalleryUtils;
+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 {
+public class LocalAlbumSet extends MediaSet
+ implements FutureListener<ArrayList<MediaSet>> {
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");
@@ -94,6 +98,8 @@ public class LocalAlbumSet extends MediaSet {
private final ChangeNotifier mNotifierImage;
private final ChangeNotifier mNotifierVideo;
private final String mName;
+ private Future<ArrayList<MediaSet>> mLoadTask;
+ private ArrayList<MediaSet> mLoadBuffer;
public LocalAlbumSet(Path path, GalleryApp application) {
super(path, nextVersionNumber());
@@ -131,7 +137,7 @@ public class LocalAlbumSet extends MediaSet {
return mName;
}
- private BucketEntry[] loadBucketEntries() {
+ private BucketEntry[] loadBucketEntries(JobContext jc) {
Uri uri = mBaseUri;
Log.v("DebugLoadingTime", "start quering media provider");
@@ -141,7 +147,6 @@ public class LocalAlbumSet extends MediaSet {
Log.w(TAG, "cannot open local database: " + uri);
return new BucketEntry[0];
}
-
ArrayList<BucketEntry> buffer = new ArrayList<BucketEntry>();
int typeBits = 0;
if ((mType & MEDIA_TYPE_IMAGE) != 0) {
@@ -160,6 +165,7 @@ public class LocalAlbumSet extends MediaSet {
buffer.add(entry);
}
}
+ if (jc.isCancelled()) return null;
}
Log.v("DebugLoadingTime", "got " + buffer.size() + " buckets");
} finally {
@@ -176,55 +182,60 @@ public class LocalAlbumSet extends MediaSet {
return -1;
}
- @SuppressWarnings("unchecked")
- protected ArrayList<MediaSet> loadSubMediaSets() {
- // Note: it will be faster if we only select media_type and bucket_id.
- // need to test the performance if that is worth
-
- GalleryUtils.assertNotInRenderThread();
- BucketEntry[] entries = loadBucketEntries();
- int offset = 0;
+ private class AlbumsLoader implements ThreadPool.Job<ArrayList<MediaSet>> {
- // 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);
- }
+ @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 = loadBucketEntries(jc);
+
+ 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) {
- albums.add(getLocalAlbum(dataManager,
- mType, mPath, entry.bucketId, entry.bucketName));
- }
- for (int i = 0, n = albums.size(); i < n; ++i) {
- albums.get(i).reload();
+ ArrayList<MediaSet> albums = new ArrayList<MediaSet>();
+ DataManager dataManager = mApplication.getDataManager();
+ for (BucketEntry entry : entries) {
+ MediaSet album = getLocalAlbum(dataManager,
+ mType, mPath, entry.bucketId, entry.bucketName);
+ album.reload();
+ albums.add(album);
+ }
+ return albums;
}
- return albums;
}
private MediaSet getLocalAlbum(
DataManager manager, int type, Path parent, int id, String name) {
- 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);
+ 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));
}
- throw new IllegalArgumentException(String.valueOf(type));
}
public static String getBucketName(ContentResolver resolver, int bucketId) {
@@ -250,15 +261,31 @@ public class LocalAlbumSet extends MediaSet {
}
@Override
- public long reload() {
+ // synchronized on this function for
+ // 1. Prevent calling reload() concurrently.
+ // 2. Prevent calling onFutureDone() and reload() concurrently
+ public synchronized long reload() {
// "|" is used instead of "||" because we want to clear both flags.
if (mNotifierImage.isDirty() | mNotifierVideo.isDirty()) {
+ if (mLoadTask != null) mLoadTask.cancel();
+ mLoadTask = mApplication.getThreadPool().submit(new AlbumsLoader(), this);
+ }
+ if (mLoadBuffer != null) {
+ mAlbums = mLoadBuffer;
+ mLoadBuffer = null;
mDataVersion = nextVersionNumber();
- mAlbums = loadSubMediaSets();
}
return mDataVersion;
}
+ @Override
+ public synchronized void onFutureDone(Future<ArrayList<MediaSet>> future) {
+ if (mLoadTask != future) return; // ignore, wait for the latest task
+ mLoadBuffer = future.get();
+ if (mLoadBuffer == null) mLoadBuffer = new ArrayList<MediaSet>();
+ notifyContentChanged();
+ }
+
// For debug only. Fake there is a ContentObserver.onChange() event.
void fakeChange() {
mNotifierImage.fakeChange();
diff --git a/src/com/android/gallery3d/data/MtpDeviceSet.java b/src/com/android/gallery3d/data/MtpDeviceSet.java
index 0d0e67ec3..dd79bc1cb 100644
--- a/src/com/android/gallery3d/data/MtpDeviceSet.java
+++ b/src/com/android/gallery3d/data/MtpDeviceSet.java
@@ -22,22 +22,30 @@ import android.util.Log;
import com.android.gallery3d.R;
import com.android.gallery3d.app.GalleryApp;
+import com.android.gallery3d.util.Future;
+import com.android.gallery3d.util.FutureListener;
import com.android.gallery3d.util.MediaSetUtils;
+import com.android.gallery3d.util.ThreadPool.Job;
+import com.android.gallery3d.util.ThreadPool.JobContext;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
// MtpDeviceSet -- MtpDevice -- MtpImage
-public class MtpDeviceSet extends MediaSet {
+public class MtpDeviceSet extends MediaSet
+ implements FutureListener<ArrayList<MediaSet>> {
private static final String TAG = "MtpDeviceSet";
private GalleryApp mApplication;
- private final ArrayList<MediaSet> mDeviceSet = new ArrayList<MediaSet>();
private final ChangeNotifier mNotifier;
private final MtpContext mMtpContext;
private final String mName;
+ private Future<ArrayList<MediaSet>> mLoadTask;
+ private ArrayList<MediaSet> mDeviceSet = new ArrayList<MediaSet>();
+ private ArrayList<MediaSet> mLoadBuffer;
+
public MtpDeviceSet(Path path, GalleryApp application, MtpContext mtpContext) {
super(path, nextVersionNumber());
mApplication = application;
@@ -46,26 +54,33 @@ public class MtpDeviceSet extends MediaSet {
mName = application.getResources().getString(R.string.set_label_mtp_devices);
}
- private void loadDevices() {
- DataManager dataManager = mApplication.getDataManager();
- // Enumerate all devices
- mDeviceSet.clear();
- List<android.mtp.MtpDevice> devices = mMtpContext.getMtpClient().getDeviceList();
- Log.v(TAG, "loadDevices: " + devices + ", size=" + devices.size());
- for (android.mtp.MtpDevice mtpDevice : devices) {
- int deviceId = mtpDevice.getDeviceId();
- Path childPath = mPath.getChild(deviceId);
- MtpDevice device = (MtpDevice) dataManager.peekMediaObject(childPath);
- if (device == null) {
- device = new MtpDevice(childPath, mApplication, deviceId, mMtpContext);
+ private class DevicesLoader implements Job<ArrayList<MediaSet>> {
+ @Override
+ public ArrayList<MediaSet> run(JobContext jc) {
+ DataManager dataManager = mApplication.getDataManager();
+ ArrayList<MediaSet> result = new ArrayList<MediaSet>();
+
+ // Enumerate all devices
+ List<android.mtp.MtpDevice> devices = mMtpContext.getMtpClient().getDeviceList();
+ Log.v(TAG, "loadDevices: " + devices + ", size=" + devices.size());
+ for (android.mtp.MtpDevice mtpDevice : devices) {
+ synchronized (DataManager.LOCK) {
+ int deviceId = mtpDevice.getDeviceId();
+ Path childPath = mPath.getChild(deviceId);
+ MtpDevice device = (MtpDevice) dataManager.peekMediaObject(childPath);
+ if (device == null) {
+ device = new MtpDevice(childPath, mApplication, deviceId, mMtpContext);
+ }
+ Log.d(TAG, "add device " + device);
+ result.add(device);
+ }
}
- Log.d(TAG, "add device " + device);
- mDeviceSet.add(device);
- }
+ Collections.sort(result, MediaSetUtils.NAME_COMPARATOR);
- Collections.sort(mDeviceSet, MediaSetUtils.NAME_COMPARATOR);
- for (int i = 0, n = mDeviceSet.size(); i < n; i++) {
- mDeviceSet.get(i).reload();
+ for (int i = 0, n = result.size(); i < n; ++i) {
+ result.get(i).reload();
+ }
+ return result;
}
}
@@ -99,11 +114,24 @@ public class MtpDeviceSet extends MediaSet {
}
@Override
- public long reload() {
+ public synchronized long reload() {
if (mNotifier.isDirty()) {
+ if (mLoadTask != null) mLoadTask.cancel();
+ mLoadTask = mApplication.getThreadPool().submit(new DevicesLoader(), this);
+ }
+ if (mLoadBuffer != null) {
+ mDeviceSet = mLoadBuffer;
+ mLoadBuffer = null;
mDataVersion = nextVersionNumber();
- loadDevices();
}
return mDataVersion;
}
+
+ @Override
+ public synchronized void onFutureDone(Future<ArrayList<MediaSet>> future) {
+ if (future != mLoadTask) return;
+ mLoadBuffer = future.get();
+ if (mLoadBuffer == null) mLoadBuffer = new ArrayList<MediaSet>();
+ notifyContentChanged();
+ }
}