PhotoSource.java revision bed703ef28f013639db3cd7a6b8a6e94d61075da
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 46bed703ef28f013639db3cd7a6b8a6e94d61075daChris Wren // An invalid cursor position to represent the uninitialized state. 47bed703ef28f013639db3cd7a6b8a6e94d61075daChris Wren protected static final int INVALID = -2; 48bed703ef28f013639db3cd7a6b8a6e94d61075daChris Wren 4983fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren // This should be large enough for BitmapFactory to decode the header so 5083fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren // that we can mark and reset the input stream to avoid duplicate network i/o 5183fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren private static final int BUFFER_SIZE = 128 * 1024; 5283fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren 53d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren public class ImageData { 5483fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren public String id; 5583fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren public String url; 5683fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren public int orientation; 57d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 58c6bebae5e07c0108294d05e33fbace209d2f9b0dChris Wren InputStream getStream(int longSide) { 59c6bebae5e07c0108294d05e33fbace209d2f9b0dChris Wren return PhotoSource.this.getStream(this, longSide); 60d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } 61d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } 62d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 63e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren public class AlbumData { 64d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren public String id; 65d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren public String title; 66d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren public String thumbnailUrl; 67e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren public String account; 68d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren public long updated; 69d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 70e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren public String getType() { 71e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren String type = PhotoSource.this.getClass().getName(); 72e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren log(TAG, "type is " + type); 73e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren return type; 74d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } 7583fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren } 7683fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren 7783fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren private final LinkedList<ImageData> mImageQueue; 7883fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren private final int mMaxQueueSize; 795b4b44688dac0053be77b282b7501bd291efb0d3Chris Wren private final float mMaxCropRatio; 8058e2a16d9237d2a5674a97062b5d614d8d397845Chris Wren private final int mBadImageSkipLimit; 81b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren private final PhotoSource mFallbackSource; 8283fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren 83d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren protected final Context mContext; 8483fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren protected final Resources mResources; 8583fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren protected final Random mRNG; 86d9b659aa5dfa4a3af96582ae49ba9ae145854a84Chris Wren protected final AlbumSettings mSettings; 87d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren protected final ContentResolver mResolver; 88d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 89d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren protected String mSourceName; 9083fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren 91d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren public PhotoSource(Context context, SharedPreferences settings) { 92b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren this(context, settings, new StockSource(context, settings)); 93b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren } 94b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren 95b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren public PhotoSource(Context context, SharedPreferences settings, PhotoSource fallbackSource) { 9683fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren mSourceName = TAG; 9783fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren mContext = context; 98d9b659aa5dfa4a3af96582ae49ba9ae145854a84Chris Wren mSettings = AlbumSettings.getAlbumSettings(settings); 9983fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren mResolver = mContext.getContentResolver(); 10083fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren mResources = context.getResources(); 10183fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren mImageQueue = new LinkedList<ImageData>(); 10283fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren mMaxQueueSize = mResources.getInteger(R.integer.image_queue_size); 1035b4b44688dac0053be77b282b7501bd291efb0d3Chris Wren mMaxCropRatio = mResources.getInteger(R.integer.max_crop_ratio) / 1000000f; 10458e2a16d9237d2a5674a97062b5d614d8d397845Chris Wren mBadImageSkipLimit = mResources.getInteger(R.integer.bad_image_skip_limit); 10583fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren mRNG = new Random(); 106b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren mFallbackSource = fallbackSource; 10783fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren } 10883fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren 10983fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren protected void fillQueue() { 11083fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren log(TAG, "filling queue"); 11183fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren mImageQueue.addAll(findImages(mMaxQueueSize - mImageQueue.size())); 11283fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren Collections.shuffle(mImageQueue); 11383fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren log(TAG, "queue contains: " + mImageQueue.size() + " items."); 11483fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren } 11583fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren 11683fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren public Bitmap next(BitmapFactory.Options options, int longSide, int shortSide) { 11783fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren log(TAG, "decoding a picasa resource to " + longSide + ", " + shortSide); 11883fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren Bitmap image = null; 1195006d4093ad1455ee98c157a71f57e9ea42b4daeChris Wren ImageData imageData = null; 12058e2a16d9237d2a5674a97062b5d614d8d397845Chris Wren int tries = 0; 12183fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren 12258e2a16d9237d2a5674a97062b5d614d8d397845Chris Wren while (image == null && tries < mBadImageSkipLimit) { 1235006d4093ad1455ee98c157a71f57e9ea42b4daeChris Wren synchronized(mImageQueue) { 1245006d4093ad1455ee98c157a71f57e9ea42b4daeChris Wren if (mImageQueue.isEmpty()) { 1255006d4093ad1455ee98c157a71f57e9ea42b4daeChris Wren fillQueue(); 1265006d4093ad1455ee98c157a71f57e9ea42b4daeChris Wren } 12758e2a16d9237d2a5674a97062b5d614d8d397845Chris Wren 1285006d4093ad1455ee98c157a71f57e9ea42b4daeChris Wren imageData = mImageQueue.poll(); 1295006d4093ad1455ee98c157a71f57e9ea42b4daeChris Wren } 13068bc9d986e8eb882dc5f15defea0dab45c440ab6Chris Wren if (imageData != null) { 1315006d4093ad1455ee98c157a71f57e9ea42b4daeChris Wren image = load(imageData, options, longSide, shortSide); 13268bc9d986e8eb882dc5f15defea0dab45c440ab6Chris Wren imageData = null; 13358e2a16d9237d2a5674a97062b5d614d8d397845Chris Wren } 13483fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren 13558e2a16d9237d2a5674a97062b5d614d8d397845Chris Wren tries++; 136b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren } 13783fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren 138b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren if (image == null && mFallbackSource != null) { 139b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren image = load((ImageData) mFallbackSource.findImages(1).toArray()[0], 14058e2a16d9237d2a5674a97062b5d614d8d397845Chris Wren options, longSide, shortSide); 141b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren } 14283fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren 143b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren return image; 144b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren } 14583fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren 146b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren public Bitmap load(ImageData data, BitmapFactory.Options options, int longSide, int shortSide) { 147b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren log(TAG, "decoding photo resource to " + longSide + ", " + shortSide); 148c6bebae5e07c0108294d05e33fbace209d2f9b0dChris Wren InputStream is = data.getStream(longSide); 149b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren 150b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren Bitmap image = null; 151b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren try { 152b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren BufferedInputStream bis = new BufferedInputStream(is); 153b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren bis.mark(BUFFER_SIZE); 154b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren 155b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren options.inJustDecodeBounds = true; 156b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren options.inSampleSize = 1; 157b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren image = BitmapFactory.decodeStream(new BufferedInputStream(bis), null, options); 158b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren int rawLongSide = Math.max(options.outWidth, options.outHeight); 159b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren int rawShortSide = Math.min(options.outWidth, options.outHeight); 160b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren log(TAG, "I see bounds of " + rawLongSide + ", " + rawShortSide); 161b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren 162b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren if (rawLongSide != -1 && rawShortSide != -1) { 163b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren float insideRatio = Math.max((float) longSide / (float) rawLongSide, 164b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren (float) shortSide / (float) rawShortSide); 165b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren float outsideRatio = Math.max((float) longSide / (float) rawLongSide, 166b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren (float) shortSide / (float) rawShortSide); 167b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren float ratio = (outsideRatio / insideRatio < mMaxCropRatio ? 168b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren outsideRatio : insideRatio); 169b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren 170b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren while (ratio < 0.5) { 171b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren options.inSampleSize *= 2; 172b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren ratio *= 2; 17383fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren } 174b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren 175b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren log(TAG, "decoding with inSampleSize " + options.inSampleSize); 176b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren bis.reset(); 177b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren options.inJustDecodeBounds = false; 178b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren image = BitmapFactory.decodeStream(bis, null, options); 179b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren rawLongSide = Math.max(options.outWidth, options.outHeight); 180b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren rawShortSide = Math.max(options.outWidth, options.outHeight); 18189ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren if (image != null && rawLongSide != -1 && rawShortSide != -1) { 18289ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren ratio = Math.max((float) longSide / (float) rawLongSide, 18389ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren (float) shortSide / (float) rawShortSide); 18489ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren 18589ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren if (Math.abs(ratio - 1.0f) > 0.001) { 18689ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren log(TAG, "still too big, scaling down by " + ratio); 18789ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren options.outWidth = (int) (ratio * options.outWidth); 18889ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren options.outHeight = (int) (ratio * options.outHeight); 18989ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren 19089ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren image = Bitmap.createScaledBitmap(image, 19189ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren options.outWidth, options.outHeight, 19289ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren true); 19389ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren } 194b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren 19589ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren if (data.orientation != 0) { 19689ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren log(TAG, "rotated by " + data.orientation + ": fixing"); 1979ab175f5902c66a266261ccf191bc2d213918ecaChris Wren Matrix matrix = new Matrix(); 1989ab175f5902c66a266261ccf191bc2d213918ecaChris Wren matrix.setRotate(data.orientation, 1999ab175f5902c66a266261ccf191bc2d213918ecaChris Wren (float) Math.floor(image.getWidth() / 2f), 2009ab175f5902c66a266261ccf191bc2d213918ecaChris Wren (float) Math.floor(image.getHeight() / 2f)); 2019ab175f5902c66a266261ccf191bc2d213918ecaChris Wren image = Bitmap.createBitmap(image, 0, 0, 2029ab175f5902c66a266261ccf191bc2d213918ecaChris Wren options.outWidth, options.outHeight, 2039ab175f5902c66a266261ccf191bc2d213918ecaChris Wren matrix, true); 20489ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren if (data.orientation == 90 || data.orientation == 270) { 20589ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren int tmp = options.outWidth; 20689ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren options.outWidth = options.outHeight; 20789ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren options.outHeight = tmp; 20889ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren } 20983fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren } 210b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren 21189ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren log(TAG, "returning bitmap " + image.getWidth() + ", " + image.getHeight()); 21289ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren } else { 21389ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren image = null; 21489ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren } 215b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren } else { 21689ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren image = null; 21789ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren } 21889ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren if (image == null) { 21989ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren log(TAG, "Stream decoding failed with no error" + 22089ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren (options.mCancel ? " due to cancelation." : ".")); 221b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren } 2225006d4093ad1455ee98c157a71f57e9ea42b4daeChris Wren } catch (OutOfMemoryError ome) { 2235006d4093ad1455ee98c157a71f57e9ea42b4daeChris Wren log(TAG, "OUT OF MEMORY: " + ome); 2245006d4093ad1455ee98c157a71f57e9ea42b4daeChris Wren image = null; 225b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren } catch (FileNotFoundException fnf) { 226b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren log(TAG, "file not found: " + fnf); 2275006d4093ad1455ee98c157a71f57e9ea42b4daeChris Wren image = null; 228b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren } catch (IOException ioe) { 229b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren log(TAG, "i/o exception: " + ioe); 2305006d4093ad1455ee98c157a71f57e9ea42b4daeChris Wren image = null; 231b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren } finally { 232b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren try { 233b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren if (is != null) { 234b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren is.close(); 23583fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren } 236b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren } catch (Throwable t) { 237b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren log(TAG, "close fail: " + t.toString()); 23883fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren } 23983fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren } 24083fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren 24183fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren return image; 24283fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren } 24383fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren 24483fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren public void setSeed(long seed) { 24583fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren mRNG.setSeed(seed); 24683fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren } 24783fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren 248b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren protected static void log(String tag, String message) { 24983fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren if (DEBUG) { 25083fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren Log.i(tag, message); 25183fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren } 25283fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren } 25383fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren 254bed703ef28f013639db3cd7a6b8a6e94d61075daChris Wren protected int pickRandomStart(int total, int max) { 255bed703ef28f013639db3cd7a6b8a6e94d61075daChris Wren if (max >= total) { 256bed703ef28f013639db3cd7a6b8a6e94d61075daChris Wren return -1; 257bed703ef28f013639db3cd7a6b8a6e94d61075daChris Wren } else { 258bed703ef28f013639db3cd7a6b8a6e94d61075daChris Wren return (mRNG.nextInt() % (total - max)) - 1; 259bed703ef28f013639db3cd7a6b8a6e94d61075daChris Wren } 260bed703ef28f013639db3cd7a6b8a6e94d61075daChris Wren } 261bed703ef28f013639db3cd7a6b8a6e94d61075daChris Wren 262c6bebae5e07c0108294d05e33fbace209d2f9b0dChris Wren protected abstract InputStream getStream(ImageData data, int longSide); 26383fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren protected abstract Collection<ImageData> findImages(int howMany); 264d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren public abstract Collection<AlbumData> findAlbums(); 26583fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren} 266