diff options
Diffstat (limited to 'src/com/android/gallery3d/data/SecureAlbum.java')
-rw-r--r-- | src/com/android/gallery3d/data/SecureAlbum.java | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/src/com/android/gallery3d/data/SecureAlbum.java b/src/com/android/gallery3d/data/SecureAlbum.java new file mode 100644 index 000000000..204f848f8 --- /dev/null +++ b/src/com/android/gallery3d/data/SecureAlbum.java @@ -0,0 +1,206 @@ +/* + * 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) { + } +} |