Home | History | Annotate | Download | only in shims
      1 /*
      2  * Copyright (C) 2013 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.photos.shims;
     18 
     19 import android.content.AsyncTaskLoader;
     20 import android.content.Context;
     21 import android.database.Cursor;
     22 import android.database.MatrixCursor;
     23 import android.graphics.drawable.Drawable;
     24 import android.net.Uri;
     25 import android.provider.MediaStore.Files.FileColumns;
     26 import android.util.SparseArray;
     27 
     28 import com.android.gallery3d.data.ContentListener;
     29 import com.android.gallery3d.data.DataManager;
     30 import com.android.gallery3d.data.MediaItem;
     31 import com.android.gallery3d.data.MediaObject;
     32 import com.android.gallery3d.data.MediaSet;
     33 import com.android.gallery3d.data.MediaSet.ItemConsumer;
     34 import com.android.gallery3d.data.MediaSet.SyncListener;
     35 import com.android.gallery3d.data.Path;
     36 import com.android.gallery3d.util.Future;
     37 import com.android.photos.data.PhotoSetLoader;
     38 
     39 import java.util.ArrayList;
     40 
     41 /**
     42  * Returns all MediaItems in a MediaSet, wrapping them in a cursor to appear
     43  * like a PhotoSetLoader
     44  */
     45 public class MediaItemsLoader extends AsyncTaskLoader<Cursor> implements LoaderCompatShim<Cursor> {
     46 
     47     private static final SyncListener sNullListener = new SyncListener() {
     48         @Override
     49         public void onSyncDone(MediaSet mediaSet, int resultCode) {
     50         }
     51     };
     52 
     53     private final MediaSet mMediaSet;
     54     private final DataManager mDataManager;
     55     private Future<Integer> mSyncTask = null;
     56     private ContentListener mObserver = new ContentListener() {
     57         @Override
     58         public void onContentDirty() {
     59             onContentChanged();
     60         }
     61     };
     62     private SparseArray<MediaItem> mMediaItems;
     63 
     64     public MediaItemsLoader(Context context) {
     65         super(context);
     66         mDataManager = DataManager.from(context);
     67         String path = mDataManager.getTopSetPath(DataManager.INCLUDE_ALL);
     68         mMediaSet = mDataManager.getMediaSet(path);
     69     }
     70 
     71     public MediaItemsLoader(Context context, String parentPath) {
     72         super(context);
     73         mDataManager = DataManager.from(getContext());
     74         mMediaSet = mDataManager.getMediaSet(parentPath);
     75     }
     76 
     77     @Override
     78     protected void onStartLoading() {
     79         super.onStartLoading();
     80         mMediaSet.addContentListener(mObserver);
     81         mSyncTask = mMediaSet.requestSync(sNullListener);
     82         forceLoad();
     83     }
     84 
     85     @Override
     86     protected boolean onCancelLoad() {
     87         if (mSyncTask != null) {
     88             mSyncTask.cancel();
     89             mSyncTask = null;
     90         }
     91         return super.onCancelLoad();
     92     }
     93 
     94     @Override
     95     protected void onStopLoading() {
     96         super.onStopLoading();
     97         cancelLoad();
     98         mMediaSet.removeContentListener(mObserver);
     99     }
    100 
    101     @Override
    102     protected void onReset() {
    103         super.onReset();
    104         onStopLoading();
    105     }
    106 
    107     @Override
    108     public Cursor loadInBackground() {
    109         // TODO: This probably doesn't work
    110         mMediaSet.reload();
    111         final MatrixCursor cursor = new MatrixCursor(PhotoSetLoader.PROJECTION);
    112         final Object[] row = new Object[PhotoSetLoader.PROJECTION.length];
    113         final SparseArray<MediaItem> mediaItems = new SparseArray<MediaItem>();
    114         mMediaSet.enumerateTotalMediaItems(new ItemConsumer() {
    115             @Override
    116             public void consume(int index, MediaItem item) {
    117                 row[PhotoSetLoader.INDEX_ID] = index;
    118                 row[PhotoSetLoader.INDEX_DATA] = item.getContentUri().toString();
    119                 row[PhotoSetLoader.INDEX_DATE_ADDED] = item.getDateInMs();
    120                 row[PhotoSetLoader.INDEX_HEIGHT] = item.getHeight();
    121                 row[PhotoSetLoader.INDEX_WIDTH] = item.getWidth();
    122                 row[PhotoSetLoader.INDEX_WIDTH] = item.getWidth();
    123                 int rawMediaType = item.getMediaType();
    124                 int mappedMediaType = FileColumns.MEDIA_TYPE_NONE;
    125                 if (rawMediaType == MediaItem.MEDIA_TYPE_IMAGE) {
    126                     mappedMediaType = FileColumns.MEDIA_TYPE_IMAGE;
    127                 } else if (rawMediaType == MediaItem.MEDIA_TYPE_VIDEO) {
    128                     mappedMediaType = FileColumns.MEDIA_TYPE_VIDEO;
    129                 }
    130                 row[PhotoSetLoader.INDEX_MEDIA_TYPE] = mappedMediaType;
    131                 row[PhotoSetLoader.INDEX_SUPPORTED_OPERATIONS] =
    132                         item.getSupportedOperations();
    133                 cursor.addRow(row);
    134                 mediaItems.append(index, item);
    135             }
    136         });
    137         synchronized (mMediaSet) {
    138             mMediaItems = mediaItems;
    139         }
    140         return cursor;
    141     }
    142 
    143     @Override
    144     public Drawable drawableForItem(Cursor item, Drawable recycle) {
    145         BitmapJobDrawable drawable = null;
    146         if (recycle == null || !(recycle instanceof BitmapJobDrawable)) {
    147             drawable = new BitmapJobDrawable();
    148         } else {
    149             drawable = (BitmapJobDrawable) recycle;
    150         }
    151         int index = item.getInt(PhotoSetLoader.INDEX_ID);
    152         drawable.setMediaItem(mMediaItems.get(index));
    153         return drawable;
    154     }
    155 
    156     public static int getThumbnailSize() {
    157         return MediaItem.getTargetSize(MediaItem.TYPE_MICROTHUMBNAIL);
    158     }
    159 
    160     @Override
    161     public Uri uriForItem(Cursor item) {
    162         int index = item.getInt(PhotoSetLoader.INDEX_ID);
    163         MediaItem mi = mMediaItems.get(index);
    164         return mi == null ? null : mi.getContentUri();
    165     }
    166 
    167     @Override
    168     public ArrayList<Uri> urisForSubItems(Cursor item) {
    169         return null;
    170     }
    171 
    172     @Override
    173     public void deleteItemWithPath(Object path) {
    174         MediaObject o = mDataManager.getMediaObject((Path) path);
    175         if (o != null) {
    176             o.delete();
    177         }
    178     }
    179 
    180     @Override
    181     public Object getPathForItem(Cursor item) {
    182         int index = item.getInt(PhotoSetLoader.INDEX_ID);
    183         MediaItem mi = mMediaItems.get(index);
    184         if (mi != null) {
    185             return mi.getPath();
    186         }
    187         return null;
    188     }
    189 
    190 }
    191