diff options
Diffstat (limited to 'src/com/android/gallery3d/gadget/MediaSetSource.java')
-rw-r--r-- | src/com/android/gallery3d/gadget/MediaSetSource.java | 233 |
1 files changed, 233 insertions, 0 deletions
diff --git a/src/com/android/gallery3d/gadget/MediaSetSource.java b/src/com/android/gallery3d/gadget/MediaSetSource.java new file mode 100644 index 000000000..458651c98 --- /dev/null +++ b/src/com/android/gallery3d/gadget/MediaSetSource.java @@ -0,0 +1,233 @@ +/* + * 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.gadget; + +import android.graphics.Bitmap; +import android.net.Uri; +import android.os.Binder; + +import com.android.gallery3d.common.Utils; +import com.android.gallery3d.data.ContentListener; +import com.android.gallery3d.data.DataManager; +import com.android.gallery3d.data.MediaItem; +import com.android.gallery3d.data.MediaObject; +import com.android.gallery3d.data.MediaSet; +import com.android.gallery3d.data.Path; + +import java.util.ArrayList; +import java.util.Arrays; + +public class MediaSetSource implements WidgetSource, ContentListener { + private static final String TAG = "MediaSetSource"; + + private DataManager mDataManager; + private Path mAlbumPath; + + private WidgetSource mSource; + + private MediaSet mRootSet; + private ContentListener mListener; + + public MediaSetSource(DataManager manager, String albumPath) { + MediaSet mediaSet = (MediaSet) manager.getMediaObject(albumPath); + if (mediaSet != null) { + mSource = new CheckedMediaSetSource(mediaSet); + return; + } + + // Initialize source to an empty source until the album path can be resolved + mDataManager = Utils.checkNotNull(manager); + mAlbumPath = Path.fromString(albumPath); + mSource = new EmptySource(); + monitorRootPath(); + } + + @Override + public int size() { + return mSource.size(); + } + + @Override + public Bitmap getImage(int index) { + return mSource.getImage(index); + } + + @Override + public Uri getContentUri(int index) { + return mSource.getContentUri(index); + } + + @Override + public synchronized void setContentListener(ContentListener listener) { + if (mRootSet != null) { + mListener = listener; + } else { + mSource.setContentListener(listener); + } + } + + @Override + public void reload() { + mSource.reload(); + } + + @Override + public void close() { + mSource.close(); + } + + @Override + public void onContentDirty() { + resolveAlbumPath(); + } + + private void monitorRootPath() { + String rootPath = mDataManager.getTopSetPath(DataManager.INCLUDE_ALL); + mRootSet = (MediaSet) mDataManager.getMediaObject(rootPath); + mRootSet.addContentListener(this); + } + + private synchronized void resolveAlbumPath() { + if (mDataManager == null) return; + MediaSet mediaSet = (MediaSet) mDataManager.getMediaObject(mAlbumPath); + if (mediaSet != null) { + // Clear the reference instead of removing the listener + // to get around a concurrent modification exception. + mRootSet = null; + + mSource = new CheckedMediaSetSource(mediaSet); + if (mListener != null) { + mListener.onContentDirty(); + mSource.setContentListener(mListener); + mListener = null; + } + mDataManager = null; + mAlbumPath = null; + } + } + + private static class CheckedMediaSetSource implements WidgetSource, ContentListener { + private static final int CACHE_SIZE = 32; + + @SuppressWarnings("unused") + private static final String TAG = "CheckedMediaSetSource"; + + private MediaSet mSource; + private MediaItem mCache[] = new MediaItem[CACHE_SIZE]; + private int mCacheStart; + private int mCacheEnd; + private long mSourceVersion = MediaObject.INVALID_DATA_VERSION; + + private ContentListener mContentListener; + + public CheckedMediaSetSource(MediaSet source) { + mSource = Utils.checkNotNull(source); + mSource.addContentListener(this); + } + + @Override + public void close() { + mSource.removeContentListener(this); + } + + private void ensureCacheRange(int index) { + if (index >= mCacheStart && index < mCacheEnd) return; + + long token = Binder.clearCallingIdentity(); + try { + mCacheStart = index; + ArrayList<MediaItem> items = mSource.getMediaItem(mCacheStart, CACHE_SIZE); + mCacheEnd = mCacheStart + items.size(); + items.toArray(mCache); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + @Override + public synchronized Uri getContentUri(int index) { + ensureCacheRange(index); + if (index < mCacheStart || index >= mCacheEnd) return null; + return mCache[index - mCacheStart].getContentUri(); + } + + @Override + public synchronized Bitmap getImage(int index) { + ensureCacheRange(index); + if (index < mCacheStart || index >= mCacheEnd) return null; + return WidgetUtils.createWidgetBitmap(mCache[index - mCacheStart]); + } + + @Override + public void reload() { + long version = mSource.reload(); + if (mSourceVersion != version) { + mSourceVersion = version; + mCacheStart = 0; + mCacheEnd = 0; + Arrays.fill(mCache, null); + } + } + + @Override + public void setContentListener(ContentListener listener) { + mContentListener = listener; + } + + @Override + public int size() { + long token = Binder.clearCallingIdentity(); + try { + return mSource.getMediaItemCount(); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + @Override + public void onContentDirty() { + if (mContentListener != null) mContentListener.onContentDirty(); + } + } + + private static class EmptySource implements WidgetSource { + + @Override + public int size() { + return 0; + } + + @Override + public Bitmap getImage(int index) { + throw new UnsupportedOperationException(); + } + + @Override + public Uri getContentUri(int index) { + throw new UnsupportedOperationException(); + } + + @Override + public void setContentListener(ContentListener listener) {} + + @Override + public void reload() {} + + @Override + public void close() {} + } +} |