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.util.Log; 2783fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren 2888d80f4471c900628e2cb6eef23029b99af48e09Chris Wrenimport java.io.BufferedInputStream; 2983fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wrenimport java.io.FileNotFoundException; 3083fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wrenimport java.io.IOException; 3188d80f4471c900628e2cb6eef23029b99af48e09Chris Wrenimport java.io.InputStream; 3283fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wrenimport java.util.Collection; 3383fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wrenimport java.util.Collections; 3488d80f4471c900628e2cb6eef23029b99af48e09Chris Wrenimport java.util.HashMap; 3583fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wrenimport java.util.LinkedList; 3683fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wrenimport java.util.Random; 3783fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren 3883fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren/** 3983fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren * Picks a random image from a source of photos. 4083fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren */ 4183fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wrenpublic abstract class PhotoSource { 4283fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren private static final String TAG = "PhotoTable.PhotoSource"; 43b7fe7200dcc6efc90aa5441bb8366d3205452c3eChris Wren private static final boolean DEBUG = false; 4483fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren 4583fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren // This should be large enough for BitmapFactory to decode the header so 4683fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren // that we can mark and reset the input stream to avoid duplicate network i/o 4783fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren private static final int BUFFER_SIZE = 128 * 1024; 4883fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren 49d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren public class ImageData { 5083fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren public String id; 5183fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren public String url; 5283fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren public int orientation; 53d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 5488d80f4471c900628e2cb6eef23029b99af48e09Chris Wren protected String albumId; 5588d80f4471c900628e2cb6eef23029b99af48e09Chris Wren protected Cursor cursor; 5688d80f4471c900628e2cb6eef23029b99af48e09Chris Wren protected int position; 5788d80f4471c900628e2cb6eef23029b99af48e09Chris Wren 58c6bebae5e07c0108294d05e33fbace209d2f9b0dChris Wren InputStream getStream(int longSide) { 59c6bebae5e07c0108294d05e33fbace209d2f9b0dChris Wren return PhotoSource.this.getStream(this, longSide); 60d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } 6188d80f4471c900628e2cb6eef23029b99af48e09Chris Wren ImageData naturalNext() { 6288d80f4471c900628e2cb6eef23029b99af48e09Chris Wren return PhotoSource.this.naturalNext(this); 6388d80f4471c900628e2cb6eef23029b99af48e09Chris Wren } 6488d80f4471c900628e2cb6eef23029b99af48e09Chris Wren ImageData naturalPrevious() { 6588d80f4471c900628e2cb6eef23029b99af48e09Chris Wren return PhotoSource.this.naturalPrevious(this); 6688d80f4471c900628e2cb6eef23029b99af48e09Chris Wren } 67bcfd4439d730a4d783a02596c8ab444796323aadChris Wren public void donePaging() { 68bcfd4439d730a4d783a02596c8ab444796323aadChris Wren PhotoSource.this.donePaging(this); 69bcfd4439d730a4d783a02596c8ab444796323aadChris Wren } 70d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } 71d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 72e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren public class AlbumData { 73d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren public String id; 74d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren public String title; 75d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren public String thumbnailUrl; 76e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren public String account; 77d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren public long updated; 78d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 79e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren public String getType() { 80e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren String type = PhotoSource.this.getClass().getName(); 81e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren log(TAG, "type is " + type); 82e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren return type; 83d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } 8483fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren } 8583fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren 8683fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren private final LinkedList<ImageData> mImageQueue; 8783fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren private final int mMaxQueueSize; 885b4b44688dac0053be77b282b7501bd291efb0d3Chris Wren private final float mMaxCropRatio; 8958e2a16d9237d2a5674a97062b5d614d8d397845Chris Wren private final int mBadImageSkipLimit; 90b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren private final PhotoSource mFallbackSource; 9188d80f4471c900628e2cb6eef23029b99af48e09Chris Wren private final HashMap<Bitmap, ImageData> mImageMap; 9283fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren 93d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren protected final Context mContext; 9483fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren protected final Resources mResources; 9583fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren protected final Random mRNG; 96d9b659aa5dfa4a3af96582ae49ba9ae145854a84Chris Wren protected final AlbumSettings mSettings; 97d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren protected final ContentResolver mResolver; 98d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 99d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren protected String mSourceName; 10083fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren 101d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren public PhotoSource(Context context, SharedPreferences settings) { 102b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren this(context, settings, new StockSource(context, settings)); 103b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren } 104b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren 105b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren public PhotoSource(Context context, SharedPreferences settings, PhotoSource fallbackSource) { 10683fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren mSourceName = TAG; 10783fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren mContext = context; 108d9b659aa5dfa4a3af96582ae49ba9ae145854a84Chris Wren mSettings = AlbumSettings.getAlbumSettings(settings); 10983fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren mResolver = mContext.getContentResolver(); 11083fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren mResources = context.getResources(); 11183fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren mImageQueue = new LinkedList<ImageData>(); 11283fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren mMaxQueueSize = mResources.getInteger(R.integer.image_queue_size); 1135b4b44688dac0053be77b282b7501bd291efb0d3Chris Wren mMaxCropRatio = mResources.getInteger(R.integer.max_crop_ratio) / 1000000f; 11458e2a16d9237d2a5674a97062b5d614d8d397845Chris Wren mBadImageSkipLimit = mResources.getInteger(R.integer.bad_image_skip_limit); 11588d80f4471c900628e2cb6eef23029b99af48e09Chris Wren mImageMap = new HashMap<Bitmap, ImageData>(); 11683fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren mRNG = new Random(); 117b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren mFallbackSource = fallbackSource; 11883fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren } 11983fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren 12083fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren protected void fillQueue() { 12183fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren log(TAG, "filling queue"); 12283fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren mImageQueue.addAll(findImages(mMaxQueueSize - mImageQueue.size())); 12383fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren Collections.shuffle(mImageQueue); 12483fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren log(TAG, "queue contains: " + mImageQueue.size() + " items."); 12583fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren } 12683fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren 12783fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren public Bitmap next(BitmapFactory.Options options, int longSide, int shortSide) { 12883fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren log(TAG, "decoding a picasa resource to " + longSide + ", " + shortSide); 12983fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren Bitmap image = null; 1305006d4093ad1455ee98c157a71f57e9ea42b4daeChris Wren ImageData imageData = null; 13158e2a16d9237d2a5674a97062b5d614d8d397845Chris Wren int tries = 0; 13283fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren 13358e2a16d9237d2a5674a97062b5d614d8d397845Chris Wren while (image == null && tries < mBadImageSkipLimit) { 1345006d4093ad1455ee98c157a71f57e9ea42b4daeChris Wren synchronized(mImageQueue) { 1355006d4093ad1455ee98c157a71f57e9ea42b4daeChris Wren if (mImageQueue.isEmpty()) { 1365006d4093ad1455ee98c157a71f57e9ea42b4daeChris Wren fillQueue(); 1375006d4093ad1455ee98c157a71f57e9ea42b4daeChris Wren } 1385006d4093ad1455ee98c157a71f57e9ea42b4daeChris Wren imageData = mImageQueue.poll(); 1395006d4093ad1455ee98c157a71f57e9ea42b4daeChris Wren } 14068bc9d986e8eb882dc5f15defea0dab45c440ab6Chris Wren if (imageData != null) { 1415006d4093ad1455ee98c157a71f57e9ea42b4daeChris Wren image = load(imageData, options, longSide, shortSide); 14288d80f4471c900628e2cb6eef23029b99af48e09Chris Wren mImageMap.put(image, imageData); 14368bc9d986e8eb882dc5f15defea0dab45c440ab6Chris Wren imageData = null; 14458e2a16d9237d2a5674a97062b5d614d8d397845Chris Wren } 14583fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren 14658e2a16d9237d2a5674a97062b5d614d8d397845Chris Wren tries++; 147b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren } 14883fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren 149b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren if (image == null && mFallbackSource != null) { 150b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren image = load((ImageData) mFallbackSource.findImages(1).toArray()[0], 15158e2a16d9237d2a5674a97062b5d614d8d397845Chris Wren options, longSide, shortSide); 152b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren } 15383fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren 154b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren return image; 155b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren } 15683fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren 157b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren public Bitmap load(ImageData data, BitmapFactory.Options options, int longSide, int shortSide) { 158b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren log(TAG, "decoding photo resource to " + longSide + ", " + shortSide); 159c6bebae5e07c0108294d05e33fbace209d2f9b0dChris Wren InputStream is = data.getStream(longSide); 160b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren 161b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren Bitmap image = null; 162b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren try { 163b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren BufferedInputStream bis = new BufferedInputStream(is); 164b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren bis.mark(BUFFER_SIZE); 165b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren 166b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren options.inJustDecodeBounds = true; 167b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren options.inSampleSize = 1; 168b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren image = BitmapFactory.decodeStream(new BufferedInputStream(bis), null, options); 169b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren int rawLongSide = Math.max(options.outWidth, options.outHeight); 170b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren int rawShortSide = Math.min(options.outWidth, options.outHeight); 171b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren log(TAG, "I see bounds of " + rawLongSide + ", " + rawShortSide); 172b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren 173b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren if (rawLongSide != -1 && rawShortSide != -1) { 174b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren float insideRatio = Math.max((float) longSide / (float) rawLongSide, 175b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren (float) shortSide / (float) rawShortSide); 176b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren float outsideRatio = Math.max((float) longSide / (float) rawLongSide, 177b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren (float) shortSide / (float) rawShortSide); 178b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren float ratio = (outsideRatio / insideRatio < mMaxCropRatio ? 179b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren outsideRatio : insideRatio); 180b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren 181b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren while (ratio < 0.5) { 182b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren options.inSampleSize *= 2; 183b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren ratio *= 2; 18483fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren } 185b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren 186b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren log(TAG, "decoding with inSampleSize " + options.inSampleSize); 187b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren bis.reset(); 188b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren options.inJustDecodeBounds = false; 189b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren image = BitmapFactory.decodeStream(bis, null, options); 190b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren rawLongSide = Math.max(options.outWidth, options.outHeight); 191b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren rawShortSide = Math.max(options.outWidth, options.outHeight); 19289ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren if (image != null && rawLongSide != -1 && rawShortSide != -1) { 19389ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren ratio = Math.max((float) longSide / (float) rawLongSide, 19489ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren (float) shortSide / (float) rawShortSide); 19589ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren 19689ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren if (Math.abs(ratio - 1.0f) > 0.001) { 19789ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren log(TAG, "still too big, scaling down by " + ratio); 19889ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren options.outWidth = (int) (ratio * options.outWidth); 19989ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren options.outHeight = (int) (ratio * options.outHeight); 20089ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren 20189ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren image = Bitmap.createScaledBitmap(image, 20289ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren options.outWidth, options.outHeight, 20389ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren true); 20489ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren } 205b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren 20689ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren if (data.orientation != 0) { 20789ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren log(TAG, "rotated by " + data.orientation + ": fixing"); 2089ab175f5902c66a266261ccf191bc2d213918ecaChris Wren Matrix matrix = new Matrix(); 2099ab175f5902c66a266261ccf191bc2d213918ecaChris Wren matrix.setRotate(data.orientation, 2109ab175f5902c66a266261ccf191bc2d213918ecaChris Wren (float) Math.floor(image.getWidth() / 2f), 2119ab175f5902c66a266261ccf191bc2d213918ecaChris Wren (float) Math.floor(image.getHeight() / 2f)); 2129ab175f5902c66a266261ccf191bc2d213918ecaChris Wren image = Bitmap.createBitmap(image, 0, 0, 2139ab175f5902c66a266261ccf191bc2d213918ecaChris Wren options.outWidth, options.outHeight, 2149ab175f5902c66a266261ccf191bc2d213918ecaChris Wren matrix, true); 21589ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren if (data.orientation == 90 || data.orientation == 270) { 21689ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren int tmp = options.outWidth; 21789ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren options.outWidth = options.outHeight; 21889ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren options.outHeight = tmp; 21989ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren } 22083fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren } 221b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren 22289ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren log(TAG, "returning bitmap " + image.getWidth() + ", " + image.getHeight()); 22389ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren } else { 22489ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren image = null; 22589ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren } 226b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren } else { 22789ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren image = null; 22889ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren } 22989ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren if (image == null) { 23089ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren log(TAG, "Stream decoding failed with no error" + 23189ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren (options.mCancel ? " due to cancelation." : ".")); 232b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren } 2335006d4093ad1455ee98c157a71f57e9ea42b4daeChris Wren } catch (OutOfMemoryError ome) { 2345006d4093ad1455ee98c157a71f57e9ea42b4daeChris Wren log(TAG, "OUT OF MEMORY: " + ome); 2355006d4093ad1455ee98c157a71f57e9ea42b4daeChris Wren image = null; 236b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren } catch (FileNotFoundException fnf) { 237b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren log(TAG, "file not found: " + fnf); 2385006d4093ad1455ee98c157a71f57e9ea42b4daeChris Wren image = null; 239b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren } catch (IOException ioe) { 240b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren log(TAG, "i/o exception: " + ioe); 2415006d4093ad1455ee98c157a71f57e9ea42b4daeChris Wren image = null; 242b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren } finally { 243b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren try { 244b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren if (is != null) { 245b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren is.close(); 24683fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren } 247b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren } catch (Throwable t) { 248b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren log(TAG, "close fail: " + t.toString()); 24983fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren } 25083fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren } 25183fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren 25283fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren return image; 25383fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren } 25483fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren 25583fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren public void setSeed(long seed) { 25683fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren mRNG.setSeed(seed); 25783fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren } 25883fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren 259b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren protected static void log(String tag, String message) { 26083fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren if (DEBUG) { 26183fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren Log.i(tag, message); 26283fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren } 26383fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren } 26483fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren 265bed703ef28f013639db3cd7a6b8a6e94d61075daChris Wren protected int pickRandomStart(int total, int max) { 266bed703ef28f013639db3cd7a6b8a6e94d61075daChris Wren if (max >= total) { 267bed703ef28f013639db3cd7a6b8a6e94d61075daChris Wren return -1; 268bed703ef28f013639db3cd7a6b8a6e94d61075daChris Wren } else { 269bed703ef28f013639db3cd7a6b8a6e94d61075daChris Wren return (mRNG.nextInt() % (total - max)) - 1; 270bed703ef28f013639db3cd7a6b8a6e94d61075daChris Wren } 271bed703ef28f013639db3cd7a6b8a6e94d61075daChris Wren } 272bed703ef28f013639db3cd7a6b8a6e94d61075daChris Wren 27388d80f4471c900628e2cb6eef23029b99af48e09Chris Wren public Bitmap naturalNext(Bitmap current, BitmapFactory.Options options, 27488d80f4471c900628e2cb6eef23029b99af48e09Chris Wren int longSide, int shortSide) { 27588d80f4471c900628e2cb6eef23029b99af48e09Chris Wren Bitmap image = null; 27688d80f4471c900628e2cb6eef23029b99af48e09Chris Wren ImageData data = mImageMap.get(current); 27788d80f4471c900628e2cb6eef23029b99af48e09Chris Wren if (data != null) { 27888d80f4471c900628e2cb6eef23029b99af48e09Chris Wren ImageData next = data.naturalNext(); 27988d80f4471c900628e2cb6eef23029b99af48e09Chris Wren if (next != null) { 28088d80f4471c900628e2cb6eef23029b99af48e09Chris Wren image = load(next, options, longSide, shortSide); 28188d80f4471c900628e2cb6eef23029b99af48e09Chris Wren mImageMap.put(image, next); 28288d80f4471c900628e2cb6eef23029b99af48e09Chris Wren } 28388d80f4471c900628e2cb6eef23029b99af48e09Chris Wren } 28488d80f4471c900628e2cb6eef23029b99af48e09Chris Wren return image; 28588d80f4471c900628e2cb6eef23029b99af48e09Chris Wren } 28688d80f4471c900628e2cb6eef23029b99af48e09Chris Wren 28788d80f4471c900628e2cb6eef23029b99af48e09Chris Wren public Bitmap naturalPrevious(Bitmap current, BitmapFactory.Options options, 28888d80f4471c900628e2cb6eef23029b99af48e09Chris Wren int longSide, int shortSide) { 28988d80f4471c900628e2cb6eef23029b99af48e09Chris Wren Bitmap image = null; 29088d80f4471c900628e2cb6eef23029b99af48e09Chris Wren ImageData data = mImageMap.get(current); 29188d80f4471c900628e2cb6eef23029b99af48e09Chris Wren if (current != null) { 29288d80f4471c900628e2cb6eef23029b99af48e09Chris Wren ImageData prev = data.naturalPrevious(); 29388d80f4471c900628e2cb6eef23029b99af48e09Chris Wren if (prev != null) { 29488d80f4471c900628e2cb6eef23029b99af48e09Chris Wren image = load(prev, options, longSide, shortSide); 29588d80f4471c900628e2cb6eef23029b99af48e09Chris Wren mImageMap.put(image, prev); 29688d80f4471c900628e2cb6eef23029b99af48e09Chris Wren } 29788d80f4471c900628e2cb6eef23029b99af48e09Chris Wren } 29888d80f4471c900628e2cb6eef23029b99af48e09Chris Wren return image; 29988d80f4471c900628e2cb6eef23029b99af48e09Chris Wren } 30088d80f4471c900628e2cb6eef23029b99af48e09Chris Wren 301bcfd4439d730a4d783a02596c8ab444796323aadChris Wren public void donePaging(Bitmap current) { 302bcfd4439d730a4d783a02596c8ab444796323aadChris Wren ImageData data = mImageMap.get(current); 303bcfd4439d730a4d783a02596c8ab444796323aadChris Wren if (data != null) { 304bcfd4439d730a4d783a02596c8ab444796323aadChris Wren data.donePaging(); 305bcfd4439d730a4d783a02596c8ab444796323aadChris Wren } 306bcfd4439d730a4d783a02596c8ab444796323aadChris Wren } 307bcfd4439d730a4d783a02596c8ab444796323aadChris Wren 308bcfd4439d730a4d783a02596c8ab444796323aadChris Wren public void recycle(Bitmap trash) { 309bcfd4439d730a4d783a02596c8ab444796323aadChris Wren if (trash != null) { 310bcfd4439d730a4d783a02596c8ab444796323aadChris Wren mImageMap.remove(trash); 311bcfd4439d730a4d783a02596c8ab444796323aadChris Wren trash.recycle(); 312bcfd4439d730a4d783a02596c8ab444796323aadChris Wren } 313bcfd4439d730a4d783a02596c8ab444796323aadChris Wren } 314bcfd4439d730a4d783a02596c8ab444796323aadChris Wren 315c6bebae5e07c0108294d05e33fbace209d2f9b0dChris Wren protected abstract InputStream getStream(ImageData data, int longSide); 31683fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren protected abstract Collection<ImageData> findImages(int howMany); 31788d80f4471c900628e2cb6eef23029b99af48e09Chris Wren protected abstract ImageData naturalNext(ImageData current); 31888d80f4471c900628e2cb6eef23029b99af48e09Chris Wren protected abstract ImageData naturalPrevious(ImageData current); 319bcfd4439d730a4d783a02596c8ab444796323aadChris Wren protected abstract void donePaging(ImageData current); 32088d80f4471c900628e2cb6eef23029b99af48e09Chris Wren 321d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren public abstract Collection<AlbumData> findAlbums(); 32283fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren} 323