Home | History | Annotate | Download | only in phototable
      1 /*
      2  * Copyright (C) 2012 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 package com.android.dreams.phototable;
     17 
     18 import android.content.Context;
     19 import android.content.SharedPreferences;
     20 import android.database.Cursor;
     21 import android.provider.MediaStore;
     22 
     23 import java.io.FileInputStream;
     24 import java.io.InputStream;
     25 import java.util.Collection;
     26 import java.util.HashMap;
     27 import java.util.LinkedList;
     28 import java.util.Set;
     29 
     30 /**
     31  * Loads images from the local store.
     32  */
     33 public class LocalSource extends CursorPhotoSource {
     34     private static final String TAG = "PhotoTable.LocalSource";
     35 
     36     private final String mUnknownAlbumName;
     37     private final String mLocalSourceName;
     38     private Set<String> mFoundAlbumIds;
     39     private int mLastPosition;
     40 
     41     public LocalSource(Context context, SharedPreferences settings) {
     42         super(context, settings);
     43         mLocalSourceName = mResources.getString(R.string.local_source_name, "Photos on Device");
     44         mUnknownAlbumName = mResources.getString(R.string.unknown_album_name, "Unknown");
     45         mSourceName = TAG;
     46         mLastPosition = INVALID;
     47         fillQueue();
     48     }
     49 
     50     private Set<String> getFoundAlbums() {
     51         if (mFoundAlbumIds == null) {
     52             findAlbums();
     53         }
     54         return mFoundAlbumIds;
     55     }
     56 
     57     @Override
     58     public Collection<AlbumData> findAlbums() {
     59         log(TAG, "finding albums");
     60         HashMap<String, AlbumData> foundAlbums = new HashMap<String, AlbumData>();
     61 
     62         String[] projection = {MediaStore.Images.Media.DATA, MediaStore.Images.Media.BUCKET_ID,
     63                 MediaStore.Images.Media.BUCKET_DISPLAY_NAME, MediaStore.Images.Media.DATE_TAKEN};
     64         // This is a horrible hack that closes the where clause and injects a grouping clause.
     65         Cursor cursor = mResolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
     66                 projection, null, null, null);
     67         if (cursor != null) {
     68             cursor.moveToPosition(-1);
     69 
     70             int dataIndex = cursor.getColumnIndex(MediaStore.Images.Media.DATA);
     71             int bucketIndex = cursor.getColumnIndex(MediaStore.Images.Media.BUCKET_ID);
     72             int nameIndex = cursor.getColumnIndex(MediaStore.Images.Media.BUCKET_DISPLAY_NAME);
     73             int updatedIndex = cursor.getColumnIndex(MediaStore.Images.Media.DATE_TAKEN);
     74 
     75             if (bucketIndex < 0) {
     76                 log(TAG, "can't find the ID column!");
     77             } else {
     78                 while (cursor.moveToNext()) {
     79                     String id = TAG + ":" + cursor.getString(bucketIndex);
     80                     AlbumData data = foundAlbums.get(id);
     81                     if (foundAlbums.get(id) == null) {
     82                         data = new AlbumData();
     83                         data.id = id;
     84                         data.account = mLocalSourceName;
     85 
     86                         if (dataIndex >= 0) {
     87                             data.thumbnailUrl = cursor.getString(dataIndex);
     88                         }
     89 
     90                         if (nameIndex >= 0) {
     91                             data.title = cursor.getString(nameIndex);
     92                         } else {
     93                             data.title = mUnknownAlbumName;
     94                         }
     95 
     96                         log(TAG, data.title + " found");
     97                         foundAlbums.put(id, data);
     98                     }
     99                     if (updatedIndex >= 0) {
    100                         long updated = cursor.getLong(updatedIndex);
    101                         data.updated = (data.updated == 0 ?
    102                                         updated :
    103                                         Math.min(data.updated, updated));
    104                     }
    105                 }
    106             }
    107             cursor.close();
    108 
    109         }
    110         log(TAG, "found " + foundAlbums.size() + " items.");
    111         mFoundAlbumIds = foundAlbums.keySet();
    112         return foundAlbums.values();
    113     }
    114 
    115     @Override
    116     protected void openCursor(ImageData data) {
    117         log(TAG, "opening single album");
    118 
    119         String[] projection = {MediaStore.Images.Media.DATA, MediaStore.Images.Media.ORIENTATION,
    120                 MediaStore.Images.Media.BUCKET_ID, MediaStore.Images.Media.BUCKET_DISPLAY_NAME};
    121         String selection = MediaStore.Images.Media.BUCKET_ID + " = '" + data.albumId + "'";
    122 
    123         data.cursor = mResolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
    124                 projection, selection, null, null);
    125     }
    126 
    127     @Override
    128     protected void findPosition(ImageData data) {
    129         if (data.position == -1) {
    130             if (data.cursor == null) {
    131                 openCursor(data);
    132             }
    133             if (data.cursor != null) {
    134                 int dataIndex = data.cursor.getColumnIndex(MediaStore.Images.Media.DATA);
    135                 data.cursor.moveToPosition(-1);
    136                 while (data.position == -1 && data.cursor.moveToNext()) {
    137                     String url = data.cursor.getString(dataIndex);
    138                     if (url != null && url.equals(data.url)) {
    139                         data.position = data.cursor.getPosition();
    140                     }
    141                 }
    142                 if (data.position == -1) {
    143                     // oops!  The image isn't in this album. How did we get here?
    144                     data.position = INVALID;
    145                 }
    146             }
    147         }
    148     }
    149 
    150     @Override
    151     protected ImageData unpackImageData(Cursor cursor, ImageData data) {
    152         if (data == null) {
    153             data = new ImageData();
    154         }
    155         int dataIndex = cursor.getColumnIndex(MediaStore.Images.Media.DATA);
    156         int orientationIndex = cursor.getColumnIndex(MediaStore.Images.Media.ORIENTATION);
    157         int bucketIndex = cursor.getColumnIndex(MediaStore.Images.Media.BUCKET_ID);
    158 
    159         data.url = cursor.getString(dataIndex);
    160         data.albumId = cursor.getString(bucketIndex);
    161         data.position = UNINITIALIZED;
    162         data.cursor = null;
    163         data.orientation = cursor.getInt(orientationIndex);
    164 
    165         return data;
    166     }
    167 
    168     @Override
    169     protected Collection<ImageData> findImages(int howMany) {
    170         log(TAG, "finding images");
    171         LinkedList<ImageData> foundImages = new LinkedList<ImageData>();
    172 
    173         String[] projection = {MediaStore.Images.Media.DATA, MediaStore.Images.Media.ORIENTATION,
    174                 MediaStore.Images.Media.BUCKET_ID, MediaStore.Images.Media.BUCKET_DISPLAY_NAME};
    175         String selection = "";
    176         for (String id : getFoundAlbums()) {
    177             if (mSettings.isAlbumEnabled(id)) {
    178                 String[] parts = id.split(":");
    179                 if (parts.length > 1) {
    180                     if (selection.length() > 0) {
    181                         selection += " OR ";
    182                     }
    183                     selection += MediaStore.Images.Media.BUCKET_ID + " = '" + parts[1] + "'";
    184                 }
    185             }
    186         }
    187         if (selection.isEmpty()) {
    188             return foundImages;
    189         }
    190 
    191         Cursor cursor = mResolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
    192                 projection, selection, null, null);
    193         if (cursor != null) {
    194             int dataIndex = cursor.getColumnIndex(MediaStore.Images.Media.DATA);
    195 
    196             if (cursor.getCount() > howMany && mLastPosition == INVALID) {
    197                 mLastPosition = pickRandomStart(cursor.getCount(), howMany);
    198             }
    199             cursor.moveToPosition(mLastPosition);
    200 
    201             if (dataIndex < 0) {
    202                 log(TAG, "can't find the DATA column!");
    203             } else {
    204                 while (foundImages.size() < howMany && cursor.moveToNext()) {
    205                     ImageData data = unpackImageData(cursor, null);
    206                     foundImages.offer(data);
    207                     mLastPosition = cursor.getPosition();
    208                 }
    209                 if (cursor.isAfterLast()) {
    210                     mLastPosition = -1;
    211                 }
    212                 if (cursor.isBeforeFirst()) {
    213                     mLastPosition = INVALID;
    214                 }
    215             }
    216 
    217             cursor.close();
    218         }
    219         log(TAG, "found " + foundImages.size() + " items.");
    220         return foundImages;
    221     }
    222 
    223     @Override
    224     protected InputStream getStream(ImageData data, int longSide) {
    225         FileInputStream fis = null;
    226         try {
    227             log(TAG, "opening:" + data.url);
    228             fis = new FileInputStream(data.url);
    229         } catch (Exception ex) {
    230             log(TAG, ex.toString());
    231             fis = null;
    232         }
    233 
    234         return (InputStream) fis;
    235     }
    236 }
    237 
    238