| /* |
| * 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.Gallery; |
| import com.android.gallery3d.app.GalleryApp; |
| import com.android.gallery3d.data.MediaSet.ItemConsumer; |
| |
| import android.content.ContentProviderClient; |
| import android.content.ContentUris; |
| import android.content.UriMatcher; |
| import android.net.Uri; |
| import android.provider.MediaStore; |
| |
| 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); |
| } |
| |
| @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}); |
| } |
| 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_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("/merge/{/local/image,/local/video}") |
| .getChild(id); |
| } |
| } |
| |
| @Override |
| public Path findPathByUri(Uri uri) { |
| 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); |
| } |
| } |
| } 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 LocalImage) { |
| return Path.fromString("/local/image/").getChild( |
| String.valueOf(((LocalImage) object).getBucketId())); |
| } else if (object instanceof LocalVideo) { |
| return Path.fromString("/local/video/").getChild( |
| String.valueOf(((LocalVideo) 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> { |
| 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; |
| } |
| } |