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