1c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren/*
2c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren * Copyright (C) 2012 The Android Open Source Project
3c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren *
4c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren * Licensed under the Apache License, Version 2.0 (the "License");
5c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren * you may not use this file except in compliance with the License.
6c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren * You may obtain a copy of the License at
7c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren *
8c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren *      http://www.apache.org/licenses/LICENSE-2.0
9c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren *
10c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren * Unless required by applicable law or agreed to in writing, software
11c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren * distributed under the License is distributed on an "AS IS" BASIS,
12c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren * See the License for the specific language governing permissions and
14c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren * limitations under the License.
15c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren */
16c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wrenpackage com.android.dreams.phototable;
17c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren
18c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wrenimport android.content.Context;
19d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wrenimport android.content.SharedPreferences;
20c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wrenimport android.database.Cursor;
21729f5231bf95ec7946fc4c510d44db303b07614dChris Wrenimport android.net.Uri;
22c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wrenimport android.provider.MediaStore;
23c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren
24c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wrenimport java.io.FileInputStream;
2583fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wrenimport java.io.InputStream;
2683fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wrenimport java.util.Collection;
27d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wrenimport java.util.HashMap;
28c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wrenimport java.util.LinkedList;
29d9b659aa5dfa4a3af96582ae49ba9ae145854a84Chris Wrenimport java.util.Set;
30c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren
31c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren/**
3283fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren * Loads images from the local store.
33c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren */
3488d80f4471c900628e2cb6eef23029b99af48e09Chris Wrenpublic class LocalSource extends CursorPhotoSource {
35c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren    private static final String TAG = "PhotoTable.LocalSource";
36c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren
37e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren    private final String mUnknownAlbumName;
38e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren    private final String mLocalSourceName;
39d9b659aa5dfa4a3af96582ae49ba9ae145854a84Chris Wren    private Set<String> mFoundAlbumIds;
40bed703ef28f013639db3cd7a6b8a6e94d61075daChris Wren    private int mLastPosition;
41c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren
42d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren    public LocalSource(Context context, SharedPreferences settings) {
43d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren        super(context, settings);
44e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren        mLocalSourceName = mResources.getString(R.string.local_source_name, "Photos on Device");
45e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren        mUnknownAlbumName = mResources.getString(R.string.unknown_album_name, "Unknown");
4683fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren        mSourceName = TAG;
47bed703ef28f013639db3cd7a6b8a6e94d61075daChris Wren        mLastPosition = INVALID;
48c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren        fillQueue();
49c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren    }
50c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren
51d9b659aa5dfa4a3af96582ae49ba9ae145854a84Chris Wren    private Set<String> getFoundAlbums() {
52d9b659aa5dfa4a3af96582ae49ba9ae145854a84Chris Wren        if (mFoundAlbumIds == null) {
53d9b659aa5dfa4a3af96582ae49ba9ae145854a84Chris Wren            findAlbums();
54d9b659aa5dfa4a3af96582ae49ba9ae145854a84Chris Wren        }
55d9b659aa5dfa4a3af96582ae49ba9ae145854a84Chris Wren        return mFoundAlbumIds;
56d9b659aa5dfa4a3af96582ae49ba9ae145854a84Chris Wren    }
57d9b659aa5dfa4a3af96582ae49ba9ae145854a84Chris Wren
5883fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren    @Override
59d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren    public Collection<AlbumData> findAlbums() {
60d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren        log(TAG, "finding albums");
61d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren        HashMap<String, AlbumData> foundAlbums = new HashMap<String, AlbumData>();
62729f5231bf95ec7946fc4c510d44db303b07614dChris Wren        findAlbums(false, foundAlbums);
63729f5231bf95ec7946fc4c510d44db303b07614dChris Wren        findAlbums(true, foundAlbums);
64d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren
65729f5231bf95ec7946fc4c510d44db303b07614dChris Wren        log(TAG, "found " + foundAlbums.size() + " items.");
66729f5231bf95ec7946fc4c510d44db303b07614dChris Wren        mFoundAlbumIds = foundAlbums.keySet();
67729f5231bf95ec7946fc4c510d44db303b07614dChris Wren        return foundAlbums.values();
68729f5231bf95ec7946fc4c510d44db303b07614dChris Wren    }
69729f5231bf95ec7946fc4c510d44db303b07614dChris Wren
70729f5231bf95ec7946fc4c510d44db303b07614dChris Wren    public void findAlbums(boolean internal, HashMap<String, AlbumData> foundAlbums) {
71729f5231bf95ec7946fc4c510d44db303b07614dChris Wren        Uri uri = internal ? MediaStore.Images.Media.INTERNAL_CONTENT_URI
72729f5231bf95ec7946fc4c510d44db303b07614dChris Wren            : MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
73d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren        String[] projection = {MediaStore.Images.Media.DATA, MediaStore.Images.Media.BUCKET_ID,
74d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                MediaStore.Images.Media.BUCKET_DISPLAY_NAME, MediaStore.Images.Media.DATE_TAKEN};
75d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren        // This is a horrible hack that closes the where clause and injects a grouping clause.
76729f5231bf95ec7946fc4c510d44db303b07614dChris Wren        Cursor cursor = mResolver.query(uri, projection, null, null, null);
77d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren        if (cursor != null) {
78bed703ef28f013639db3cd7a6b8a6e94d61075daChris Wren            cursor.moveToPosition(-1);
79d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren
80d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren            int dataIndex = cursor.getColumnIndex(MediaStore.Images.Media.DATA);
81d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren            int bucketIndex = cursor.getColumnIndex(MediaStore.Images.Media.BUCKET_ID);
82d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren            int nameIndex = cursor.getColumnIndex(MediaStore.Images.Media.BUCKET_DISPLAY_NAME);
83d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren            int updatedIndex = cursor.getColumnIndex(MediaStore.Images.Media.DATE_TAKEN);
84d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren
85d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren            if (bucketIndex < 0) {
86d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                log(TAG, "can't find the ID column!");
87d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren            } else {
88bed703ef28f013639db3cd7a6b8a6e94d61075daChris Wren                while (cursor.moveToNext()) {
89729f5231bf95ec7946fc4c510d44db303b07614dChris Wren                    String id = constructId(internal, cursor.getString(bucketIndex));
90d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                    AlbumData data = foundAlbums.get(id);
91d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                    if (foundAlbums.get(id) == null) {
92d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                        data = new AlbumData();
93d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                        data.id = id;
94e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren                        data.account = mLocalSourceName;
95d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren
96d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                        if (dataIndex >= 0) {
97d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                            data.thumbnailUrl = cursor.getString(dataIndex);
98d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                        }
99d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren
100d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                        if (nameIndex >= 0) {
101d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                            data.title = cursor.getString(nameIndex);
102d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                        } else {
103e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren                            data.title = mUnknownAlbumName;
104d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                        }
105d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren
106d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                        log(TAG, data.title + " found");
107d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                        foundAlbums.put(id, data);
108d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                    }
109d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                    if (updatedIndex >= 0) {
110d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                        long updated = cursor.getLong(updatedIndex);
111d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                        data.updated = (data.updated == 0 ?
112d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                                        updated :
113d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                                        Math.min(data.updated, updated));
114d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                    }
115d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                }
116d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren            }
117d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren            cursor.close();
118d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren        }
119729f5231bf95ec7946fc4c510d44db303b07614dChris Wren    }
120729f5231bf95ec7946fc4c510d44db303b07614dChris Wren
121729f5231bf95ec7946fc4c510d44db303b07614dChris Wren    public static String constructId(boolean internal, String bucketId) {
122729f5231bf95ec7946fc4c510d44db303b07614dChris Wren        return TAG + ":" + bucketId + (internal ? ":i" : "");
123d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren    }
124d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren
125d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren    @Override
12688d80f4471c900628e2cb6eef23029b99af48e09Chris Wren    protected void openCursor(ImageData data) {
12788d80f4471c900628e2cb6eef23029b99af48e09Chris Wren        log(TAG, "opening single album");
12888d80f4471c900628e2cb6eef23029b99af48e09Chris Wren
12988d80f4471c900628e2cb6eef23029b99af48e09Chris Wren        String[] projection = {MediaStore.Images.Media.DATA, MediaStore.Images.Media.ORIENTATION,
13088d80f4471c900628e2cb6eef23029b99af48e09Chris Wren                MediaStore.Images.Media.BUCKET_ID, MediaStore.Images.Media.BUCKET_DISPLAY_NAME};
13188d80f4471c900628e2cb6eef23029b99af48e09Chris Wren        String selection = MediaStore.Images.Media.BUCKET_ID + " = '" + data.albumId + "'";
13288d80f4471c900628e2cb6eef23029b99af48e09Chris Wren
133729f5231bf95ec7946fc4c510d44db303b07614dChris Wren        data.cursor = mResolver.query(data.uri, projection, selection, null, null);
13488d80f4471c900628e2cb6eef23029b99af48e09Chris Wren    }
13588d80f4471c900628e2cb6eef23029b99af48e09Chris Wren
13688d80f4471c900628e2cb6eef23029b99af48e09Chris Wren    @Override
13788d80f4471c900628e2cb6eef23029b99af48e09Chris Wren    protected void findPosition(ImageData data) {
13888d80f4471c900628e2cb6eef23029b99af48e09Chris Wren        if (data.position == -1) {
13988d80f4471c900628e2cb6eef23029b99af48e09Chris Wren            if (data.cursor == null) {
14088d80f4471c900628e2cb6eef23029b99af48e09Chris Wren                openCursor(data);
14188d80f4471c900628e2cb6eef23029b99af48e09Chris Wren            }
14288d80f4471c900628e2cb6eef23029b99af48e09Chris Wren            if (data.cursor != null) {
14388d80f4471c900628e2cb6eef23029b99af48e09Chris Wren                int dataIndex = data.cursor.getColumnIndex(MediaStore.Images.Media.DATA);
14488d80f4471c900628e2cb6eef23029b99af48e09Chris Wren                data.cursor.moveToPosition(-1);
14588d80f4471c900628e2cb6eef23029b99af48e09Chris Wren                while (data.position == -1 && data.cursor.moveToNext()) {
14688d80f4471c900628e2cb6eef23029b99af48e09Chris Wren                    String url = data.cursor.getString(dataIndex);
14788d80f4471c900628e2cb6eef23029b99af48e09Chris Wren                    if (url != null && url.equals(data.url)) {
14888d80f4471c900628e2cb6eef23029b99af48e09Chris Wren                        data.position = data.cursor.getPosition();
14988d80f4471c900628e2cb6eef23029b99af48e09Chris Wren                    }
15088d80f4471c900628e2cb6eef23029b99af48e09Chris Wren                }
15188d80f4471c900628e2cb6eef23029b99af48e09Chris Wren                if (data.position == -1) {
15288d80f4471c900628e2cb6eef23029b99af48e09Chris Wren                    // oops!  The image isn't in this album. How did we get here?
15388d80f4471c900628e2cb6eef23029b99af48e09Chris Wren                    data.position = INVALID;
15488d80f4471c900628e2cb6eef23029b99af48e09Chris Wren                }
15588d80f4471c900628e2cb6eef23029b99af48e09Chris Wren            }
15688d80f4471c900628e2cb6eef23029b99af48e09Chris Wren        }
15788d80f4471c900628e2cb6eef23029b99af48e09Chris Wren    }
15888d80f4471c900628e2cb6eef23029b99af48e09Chris Wren
15988d80f4471c900628e2cb6eef23029b99af48e09Chris Wren    @Override
16088d80f4471c900628e2cb6eef23029b99af48e09Chris Wren    protected ImageData unpackImageData(Cursor cursor, ImageData data) {
16188d80f4471c900628e2cb6eef23029b99af48e09Chris Wren        if (data == null) {
16288d80f4471c900628e2cb6eef23029b99af48e09Chris Wren            data = new ImageData();
16388d80f4471c900628e2cb6eef23029b99af48e09Chris Wren        }
16488d80f4471c900628e2cb6eef23029b99af48e09Chris Wren        int dataIndex = cursor.getColumnIndex(MediaStore.Images.Media.DATA);
16588d80f4471c900628e2cb6eef23029b99af48e09Chris Wren        int orientationIndex = cursor.getColumnIndex(MediaStore.Images.Media.ORIENTATION);
16688d80f4471c900628e2cb6eef23029b99af48e09Chris Wren        int bucketIndex = cursor.getColumnIndex(MediaStore.Images.Media.BUCKET_ID);
16788d80f4471c900628e2cb6eef23029b99af48e09Chris Wren
16888d80f4471c900628e2cb6eef23029b99af48e09Chris Wren        data.url = cursor.getString(dataIndex);
16988d80f4471c900628e2cb6eef23029b99af48e09Chris Wren        data.albumId = cursor.getString(bucketIndex);
17088d80f4471c900628e2cb6eef23029b99af48e09Chris Wren        data.position = UNINITIALIZED;
17188d80f4471c900628e2cb6eef23029b99af48e09Chris Wren        data.cursor = null;
17288d80f4471c900628e2cb6eef23029b99af48e09Chris Wren        data.orientation = cursor.getInt(orientationIndex);
17388d80f4471c900628e2cb6eef23029b99af48e09Chris Wren
17488d80f4471c900628e2cb6eef23029b99af48e09Chris Wren        return data;
17588d80f4471c900628e2cb6eef23029b99af48e09Chris Wren    }
17688d80f4471c900628e2cb6eef23029b99af48e09Chris Wren
17788d80f4471c900628e2cb6eef23029b99af48e09Chris Wren    @Override
17883fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren    protected Collection<ImageData> findImages(int howMany) {
17983fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren        log(TAG, "finding images");
18083fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren        LinkedList<ImageData> foundImages = new LinkedList<ImageData>();
181729f5231bf95ec7946fc4c510d44db303b07614dChris Wren        boolean internalFirst = mRNG.nextInt(2) == 0;  // filp a coin to be fair
182729f5231bf95ec7946fc4c510d44db303b07614dChris Wren        findImages(internalFirst, howMany, foundImages);
183729f5231bf95ec7946fc4c510d44db303b07614dChris Wren        findImages(!internalFirst, howMany - foundImages.size(), foundImages);
184729f5231bf95ec7946fc4c510d44db303b07614dChris Wren        log(TAG, "found " + foundImages.size() + " items.");
185729f5231bf95ec7946fc4c510d44db303b07614dChris Wren        return foundImages;
186729f5231bf95ec7946fc4c510d44db303b07614dChris Wren    }
18783fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren
188729f5231bf95ec7946fc4c510d44db303b07614dChris Wren    protected void findImages(boolean internal, int howMany, LinkedList<ImageData> foundImages ) {
189729f5231bf95ec7946fc4c510d44db303b07614dChris Wren        Uri uri = internal ? MediaStore.Images.Media.INTERNAL_CONTENT_URI
190729f5231bf95ec7946fc4c510d44db303b07614dChris Wren            : MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
19183fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren        String[] projection = {MediaStore.Images.Media.DATA, MediaStore.Images.Media.ORIENTATION,
19283fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren                MediaStore.Images.Media.BUCKET_ID, MediaStore.Images.Media.BUCKET_DISPLAY_NAME};
19383fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren        String selection = "";
194d9b659aa5dfa4a3af96582ae49ba9ae145854a84Chris Wren        for (String id : getFoundAlbums()) {
195729f5231bf95ec7946fc4c510d44db303b07614dChris Wren            if (isInternalId(id) == internal && mSettings.isAlbumEnabled(id)) {
196d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                String[] parts = id.split(":");
197d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                if (parts.length > 1) {
198d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                    if (selection.length() > 0) {
199d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                        selection += " OR ";
200d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                    }
201d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                    selection += MediaStore.Images.Media.BUCKET_ID + " = '" + parts[1] + "'";
202d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                }
20383fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren            }
20483fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren        }
205d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren        if (selection.isEmpty()) {
206729f5231bf95ec7946fc4c510d44db303b07614dChris Wren            return;
207d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren        }
208729f5231bf95ec7946fc4c510d44db303b07614dChris Wren        Cursor cursor = mResolver.query(uri, projection, selection, null, null);
209c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren        if (cursor != null) {
21088d80f4471c900628e2cb6eef23029b99af48e09Chris Wren            int dataIndex = cursor.getColumnIndex(MediaStore.Images.Media.DATA);
21188d80f4471c900628e2cb6eef23029b99af48e09Chris Wren
212bed703ef28f013639db3cd7a6b8a6e94d61075daChris Wren            if (cursor.getCount() > howMany && mLastPosition == INVALID) {
213bed703ef28f013639db3cd7a6b8a6e94d61075daChris Wren                mLastPosition = pickRandomStart(cursor.getCount(), howMany);
214c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren            }
215bed703ef28f013639db3cd7a6b8a6e94d61075daChris Wren            cursor.moveToPosition(mLastPosition);
216c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren
217c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren            if (dataIndex < 0) {
21883fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren                log(TAG, "can't find the DATA column!");
219c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren            } else {
220bed703ef28f013639db3cd7a6b8a6e94d61075daChris Wren                while (foundImages.size() < howMany && cursor.moveToNext()) {
22188d80f4471c900628e2cb6eef23029b99af48e09Chris Wren                    ImageData data = unpackImageData(cursor, null);
222729f5231bf95ec7946fc4c510d44db303b07614dChris Wren                    data.uri = uri;
22383fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren                    foundImages.offer(data);
224bed703ef28f013639db3cd7a6b8a6e94d61075daChris Wren                    mLastPosition = cursor.getPosition();
225c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren                }
226c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren                if (cursor.isAfterLast()) {
227bed703ef28f013639db3cd7a6b8a6e94d61075daChris Wren                    mLastPosition = -1;
228bed703ef28f013639db3cd7a6b8a6e94d61075daChris Wren                }
229bed703ef28f013639db3cd7a6b8a6e94d61075daChris Wren                if (cursor.isBeforeFirst()) {
230bed703ef28f013639db3cd7a6b8a6e94d61075daChris Wren                    mLastPosition = INVALID;
231c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren                }
232c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren            }
23383fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren
234c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren            cursor.close();
235c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren        }
236729f5231bf95ec7946fc4c510d44db303b07614dChris Wren    }
237729f5231bf95ec7946fc4c510d44db303b07614dChris Wren
238729f5231bf95ec7946fc4c510d44db303b07614dChris Wren    private boolean isInternalId(String id) {
239729f5231bf95ec7946fc4c510d44db303b07614dChris Wren        return id.endsWith("i");
240c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren    }
241c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren
24283fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren    @Override
243c6bebae5e07c0108294d05e33fbace209d2f9b0dChris Wren    protected InputStream getStream(ImageData data, int longSide) {
24483fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren        FileInputStream fis = null;
24583fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren        try {
24683fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren            log(TAG, "opening:" + data.url);
24783fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren            fis = new FileInputStream(data.url);
24883fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren        } catch (Exception ex) {
24983fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren            log(TAG, ex.toString());
25083fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren            fis = null;
251c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren        }
252c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren
25383fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren        return (InputStream) fis;
254c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren    }
255c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren}
25688d80f4471c900628e2cb6eef23029b99af48e09Chris Wren
257