PhotoSource.java revision c6bebae5e07c0108294d05e33fbace209d2f9b0d
183fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren/*
283fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren * Copyright (C) 2012 The Android Open Source Project
383fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren *
483fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren * Licensed under the Apache License, Version 2.0 (the "License");
583fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren * you may not use this file except in compliance with the License.
683fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren * You may obtain a copy of the License at
783fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren *
883fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren *      http://www.apache.org/licenses/LICENSE-2.0
983fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren *
1083fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren * Unless required by applicable law or agreed to in writing, software
1183fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren * distributed under the License is distributed on an "AS IS" BASIS,
1283fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1383fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren * See the License for the specific language governing permissions and
1483fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren * limitations under the License.
1583fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren */
1683fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wrenpackage com.android.dreams.phototable;
1783fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren
1883fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wrenimport android.content.ContentResolver;
1983fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wrenimport android.content.Context;
20d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wrenimport android.content.SharedPreferences;
2183fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wrenimport android.content.res.Resources;
2283fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wrenimport android.database.Cursor;
2383fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wrenimport android.graphics.Bitmap;
2483fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wrenimport android.graphics.BitmapFactory;
2583fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wrenimport android.graphics.Matrix;
2683fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wrenimport android.net.Uri;
2783fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wrenimport android.provider.MediaStore;
2883fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wrenimport android.util.Log;
2983fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren
3083fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wrenimport java.io.FileNotFoundException;
3183fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wrenimport java.io.InputStream;
3283fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wrenimport java.io.IOException;
3383fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wrenimport java.io.BufferedInputStream;
3483fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wrenimport java.util.Collection;
3583fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wrenimport java.util.Collections;
3683fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wrenimport java.util.LinkedList;
3783fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wrenimport java.util.Random;
3883fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren
3983fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren/**
4083fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren * Picks a random image from a source of photos.
4183fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren */
4283fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wrenpublic abstract class PhotoSource {
4383fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren    private static final String TAG = "PhotoTable.PhotoSource";
44b7fe7200dcc6efc90aa5441bb8366d3205452c3eChris Wren    private static final boolean DEBUG = false;
4583fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren
4683fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren    // This should be large enough for BitmapFactory to decode the header so
4783fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren    // that we can mark and reset the input stream to avoid duplicate network i/o
4883fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren    private static final int BUFFER_SIZE = 128 * 1024;
4983fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren
50d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren    public class ImageData {
5183fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren        public String id;
5283fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren        public String url;
5383fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren        public int orientation;
54d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren
55c6bebae5e07c0108294d05e33fbace209d2f9b0dChris Wren        InputStream getStream(int longSide) {
56c6bebae5e07c0108294d05e33fbace209d2f9b0dChris Wren            return PhotoSource.this.getStream(this, longSide);
57d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren        }
58d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren    }
59d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren
60e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren    public class AlbumData {
61d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren        public String id;
62d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren        public String title;
63d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren        public String thumbnailUrl;
64e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren        public String account;
65d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren        public long updated;
66d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren
67e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren        public String getType() {
68e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren            String type = PhotoSource.this.getClass().getName();
69e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren            log(TAG, "type is " + type);
70e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren            return type;
71d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren        }
7283fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren    }
7383fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren
7483fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren    private final LinkedList<ImageData> mImageQueue;
7583fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren    private final int mMaxQueueSize;
765b4b44688dac0053be77b282b7501bd291efb0d3Chris Wren    private final float mMaxCropRatio;
7758e2a16d9237d2a5674a97062b5d614d8d397845Chris Wren    private final int mBadImageSkipLimit;
78b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren    private final PhotoSource mFallbackSource;
7983fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren
80d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren    protected final Context mContext;
8183fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren    protected final Resources mResources;
8283fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren    protected final Random mRNG;
83d9b659aa5dfa4a3af96582ae49ba9ae145854a84Chris Wren    protected final AlbumSettings mSettings;
84d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren    protected final ContentResolver mResolver;
85d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren
86d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren    protected String mSourceName;
8783fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren
88d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren    public PhotoSource(Context context, SharedPreferences settings) {
89b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren        this(context, settings, new StockSource(context, settings));
90b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren    }
91b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren
92b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren    public PhotoSource(Context context, SharedPreferences settings, PhotoSource fallbackSource) {
9383fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren        mSourceName = TAG;
9483fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren        mContext = context;
95d9b659aa5dfa4a3af96582ae49ba9ae145854a84Chris Wren        mSettings = AlbumSettings.getAlbumSettings(settings);
9683fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren        mResolver = mContext.getContentResolver();
9783fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren        mResources = context.getResources();
9883fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren        mImageQueue = new LinkedList<ImageData>();
9983fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren        mMaxQueueSize = mResources.getInteger(R.integer.image_queue_size);
1005b4b44688dac0053be77b282b7501bd291efb0d3Chris Wren        mMaxCropRatio = mResources.getInteger(R.integer.max_crop_ratio) / 1000000f;
10158e2a16d9237d2a5674a97062b5d614d8d397845Chris Wren        mBadImageSkipLimit = mResources.getInteger(R.integer.bad_image_skip_limit);
10283fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren        mRNG = new Random();
103b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren        mFallbackSource = fallbackSource;
10483fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren    }
10583fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren
10683fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren    protected void fillQueue() {
10783fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren        log(TAG, "filling queue");
10883fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren        mImageQueue.addAll(findImages(mMaxQueueSize - mImageQueue.size()));
10983fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren        Collections.shuffle(mImageQueue);
11083fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren        log(TAG, "queue contains: " + mImageQueue.size() + " items.");
11183fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren    }
11283fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren
11383fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren    public Bitmap next(BitmapFactory.Options options, int longSide, int shortSide) {
11483fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren        log(TAG, "decoding a picasa resource to " +  longSide + ", " + shortSide);
11583fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren        Bitmap image = null;
1165006d4093ad1455ee98c157a71f57e9ea42b4daeChris Wren        ImageData imageData = null;
11758e2a16d9237d2a5674a97062b5d614d8d397845Chris Wren        int tries = 0;
11883fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren
11958e2a16d9237d2a5674a97062b5d614d8d397845Chris Wren        while (image == null && tries < mBadImageSkipLimit) {
1205006d4093ad1455ee98c157a71f57e9ea42b4daeChris Wren            synchronized(mImageQueue) {
1215006d4093ad1455ee98c157a71f57e9ea42b4daeChris Wren                if (mImageQueue.isEmpty()) {
1225006d4093ad1455ee98c157a71f57e9ea42b4daeChris Wren                    fillQueue();
1235006d4093ad1455ee98c157a71f57e9ea42b4daeChris Wren                }
12458e2a16d9237d2a5674a97062b5d614d8d397845Chris Wren
1255006d4093ad1455ee98c157a71f57e9ea42b4daeChris Wren                imageData = mImageQueue.poll();
1265006d4093ad1455ee98c157a71f57e9ea42b4daeChris Wren            }
12758e2a16d9237d2a5674a97062b5d614d8d397845Chris Wren            if (!mImageQueue.isEmpty()) {
1285006d4093ad1455ee98c157a71f57e9ea42b4daeChris Wren                image = load(imageData, options, longSide, shortSide);
12958e2a16d9237d2a5674a97062b5d614d8d397845Chris Wren            }
13083fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren
13158e2a16d9237d2a5674a97062b5d614d8d397845Chris Wren            tries++;
132b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren        }
13383fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren
134b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren        if (image == null && mFallbackSource != null) {
135b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren            image = load((ImageData) mFallbackSource.findImages(1).toArray()[0],
13658e2a16d9237d2a5674a97062b5d614d8d397845Chris Wren                    options, longSide, shortSide);
137b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren        }
13883fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren
139b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren        return image;
140b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren    }
14183fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren
142b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren    public Bitmap load(ImageData data, BitmapFactory.Options options, int longSide, int shortSide) {
143b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren        log(TAG, "decoding photo resource to " +  longSide + ", " + shortSide);
144c6bebae5e07c0108294d05e33fbace209d2f9b0dChris Wren        InputStream is = data.getStream(longSide);
145b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren
146b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren        Bitmap image = null;
147b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren        try {
148b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren            BufferedInputStream bis = new BufferedInputStream(is);
149b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren            bis.mark(BUFFER_SIZE);
150b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren
151b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren            options.inJustDecodeBounds = true;
152b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren            options.inSampleSize = 1;
153b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren            image = BitmapFactory.decodeStream(new BufferedInputStream(bis), null, options);
154b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren            int rawLongSide = Math.max(options.outWidth, options.outHeight);
155b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren            int rawShortSide = Math.min(options.outWidth, options.outHeight);
156b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren            log(TAG, "I see bounds of " +  rawLongSide + ", " + rawShortSide);
157b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren
158b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren            if (rawLongSide != -1 && rawShortSide != -1) {
159b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren                float insideRatio = Math.max((float) longSide / (float) rawLongSide,
160b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren                                             (float) shortSide / (float) rawShortSide);
161b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren                float outsideRatio = Math.max((float) longSide / (float) rawLongSide,
162b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren                                              (float) shortSide / (float) rawShortSide);
163b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren                float ratio = (outsideRatio / insideRatio < mMaxCropRatio ?
164b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren                               outsideRatio : insideRatio);
165b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren
166b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren                while (ratio < 0.5) {
167b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren                    options.inSampleSize *= 2;
168b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren                    ratio *= 2;
16983fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren                }
170b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren
171b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren                log(TAG, "decoding with inSampleSize " +  options.inSampleSize);
172b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren                bis.reset();
173b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren                options.inJustDecodeBounds = false;
174b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren                image = BitmapFactory.decodeStream(bis, null, options);
175b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren                rawLongSide = Math.max(options.outWidth, options.outHeight);
176b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren                rawShortSide = Math.max(options.outWidth, options.outHeight);
17789ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren                if (image != null && rawLongSide != -1 && rawShortSide != -1) {
17889ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren                    ratio = Math.max((float) longSide / (float) rawLongSide,
17989ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren                            (float) shortSide / (float) rawShortSide);
18089ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren
18189ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren                    if (Math.abs(ratio - 1.0f) > 0.001) {
18289ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren                        log(TAG, "still too big, scaling down by " + ratio);
18389ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren                        options.outWidth = (int) (ratio * options.outWidth);
18489ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren                        options.outHeight = (int) (ratio * options.outHeight);
18589ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren
18689ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren                        image = Bitmap.createScaledBitmap(image,
18789ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren                                options.outWidth, options.outHeight,
18889ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren                                true);
18989ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren                    }
190b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren
19189ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren                    if (data.orientation != 0) {
19289ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren                        log(TAG, "rotated by " + data.orientation + ": fixing");
19389ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren                        if (data.orientation == 90 || data.orientation == 270) {
19489ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren                            int tmp = options.outWidth;
19589ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren                            options.outWidth = options.outHeight;
19689ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren                            options.outHeight = tmp;
19789ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren                        }
19889ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren                        Matrix matrix = new Matrix();
19989ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren                        matrix.setRotate(data.orientation,
20089ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren                                         (float) image.getWidth() / 2,
20189ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren                                         (float) image.getHeight() / 2);
20289ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren                        image = Bitmap.createBitmap(image, 0, 0,
20389ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren                                                    options.outHeight, options.outWidth,
20489ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren                                                    matrix, true);
20583fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren                    }
206b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren
20789ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren                    log(TAG, "returning bitmap " + image.getWidth() + ", " + image.getHeight());
20889ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren                } else {
20989ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren                    image = null;
21089ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren                }
211b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren            } else {
21289ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren                image = null;
21389ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren            }
21489ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren            if (image == null) {
21589ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren                log(TAG, "Stream decoding failed with no error" +
21689ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren                        (options.mCancel ? " due to cancelation." : "."));
217b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren            }
2185006d4093ad1455ee98c157a71f57e9ea42b4daeChris Wren        } catch (OutOfMemoryError ome) {
2195006d4093ad1455ee98c157a71f57e9ea42b4daeChris Wren            log(TAG, "OUT OF MEMORY: " + ome);
2205006d4093ad1455ee98c157a71f57e9ea42b4daeChris Wren            image = null;
221b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren        } catch (FileNotFoundException fnf) {
222b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren            log(TAG, "file not found: " + fnf);
2235006d4093ad1455ee98c157a71f57e9ea42b4daeChris Wren            image = null;
224b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren        } catch (IOException ioe) {
225b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren            log(TAG, "i/o exception: " + ioe);
2265006d4093ad1455ee98c157a71f57e9ea42b4daeChris Wren            image = null;
227b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren        } finally {
228b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren            try {
229b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren                if (is != null) {
230b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren                    is.close();
23183fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren                }
232b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren            } catch (Throwable t) {
233b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren                log(TAG, "close fail: " + t.toString());
23483fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren            }
23583fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren        }
23683fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren
23783fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren        return image;
23883fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren    }
23983fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren
24083fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren    public void setSeed(long seed) {
24183fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren        mRNG.setSeed(seed);
24283fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren    }
24383fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren
244b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren    protected static void log(String tag, String message) {
24583fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren        if (DEBUG) {
24683fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren            Log.i(tag, message);
24783fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren        }
24883fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren    }
24983fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren
250c6bebae5e07c0108294d05e33fbace209d2f9b0dChris Wren    protected abstract InputStream getStream(ImageData data, int longSide);
25183fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren    protected abstract Collection<ImageData> findImages(int howMany);
252d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren    public abstract Collection<AlbumData> findAlbums();
25383fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren}
254