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; 26729f5231bf95ec7946fc4c510d44db303b07614dChris Wrenimport android.net.Uri; 2783fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wrenimport android.util.Log; 2883fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren 2988d80f4471c900628e2cb6eef23029b99af48e09Chris Wrenimport java.io.BufferedInputStream; 3083fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wrenimport java.io.FileNotFoundException; 3183fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wrenimport java.io.IOException; 3288d80f4471c900628e2cb6eef23029b99af48e09Chris Wrenimport java.io.InputStream; 3383fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wrenimport java.util.Collection; 3483fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wrenimport java.util.Collections; 3588d80f4471c900628e2cb6eef23029b99af48e09Chris Wrenimport java.util.HashMap; 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 4823ab8f3366a5eeecd36c5f489a47eb6b8f03bc56Chris Wren private static final int BUFFER_SIZE = 32 * 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 5588d80f4471c900628e2cb6eef23029b99af48e09Chris Wren protected String albumId; 5688d80f4471c900628e2cb6eef23029b99af48e09Chris Wren protected Cursor cursor; 5788d80f4471c900628e2cb6eef23029b99af48e09Chris Wren protected int position; 58729f5231bf95ec7946fc4c510d44db303b07614dChris Wren protected Uri uri; 5988d80f4471c900628e2cb6eef23029b99af48e09Chris Wren 60c6bebae5e07c0108294d05e33fbace209d2f9b0dChris Wren InputStream getStream(int longSide) { 61c6bebae5e07c0108294d05e33fbace209d2f9b0dChris Wren return PhotoSource.this.getStream(this, longSide); 62d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } 6388d80f4471c900628e2cb6eef23029b99af48e09Chris Wren ImageData naturalNext() { 6488d80f4471c900628e2cb6eef23029b99af48e09Chris Wren return PhotoSource.this.naturalNext(this); 6588d80f4471c900628e2cb6eef23029b99af48e09Chris Wren } 6688d80f4471c900628e2cb6eef23029b99af48e09Chris Wren ImageData naturalPrevious() { 6788d80f4471c900628e2cb6eef23029b99af48e09Chris Wren return PhotoSource.this.naturalPrevious(this); 6888d80f4471c900628e2cb6eef23029b99af48e09Chris Wren } 69bcfd4439d730a4d783a02596c8ab444796323aadChris Wren public void donePaging() { 70bcfd4439d730a4d783a02596c8ab444796323aadChris Wren PhotoSource.this.donePaging(this); 71bcfd4439d730a4d783a02596c8ab444796323aadChris Wren } 72d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } 73d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 74e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren public class AlbumData { 75d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren public String id; 76d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren public String title; 77d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren public String thumbnailUrl; 78e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren public String account; 79d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren public long updated; 80d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 81e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren public String getType() { 82e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren String type = PhotoSource.this.getClass().getName(); 83e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren log(TAG, "type is " + type); 84e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren return type; 85d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } 8683fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren } 8783fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren 8883fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren private final LinkedList<ImageData> mImageQueue; 8983fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren private final int mMaxQueueSize; 905b4b44688dac0053be77b282b7501bd291efb0d3Chris Wren private final float mMaxCropRatio; 9158e2a16d9237d2a5674a97062b5d614d8d397845Chris Wren private final int mBadImageSkipLimit; 92b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren private final PhotoSource mFallbackSource; 9388d80f4471c900628e2cb6eef23029b99af48e09Chris Wren private final HashMap<Bitmap, ImageData> mImageMap; 9483fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren 95d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren protected final Context mContext; 9683fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren protected final Resources mResources; 9783fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren protected final Random mRNG; 98d9b659aa5dfa4a3af96582ae49ba9ae145854a84Chris Wren protected final AlbumSettings mSettings; 99d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren protected final ContentResolver mResolver; 100d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 101d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren protected String mSourceName; 10283fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren 103d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren public PhotoSource(Context context, SharedPreferences settings) { 104b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren this(context, settings, new StockSource(context, settings)); 105b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren } 106b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren 107b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren public PhotoSource(Context context, SharedPreferences settings, PhotoSource fallbackSource) { 10883fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren mSourceName = TAG; 10983fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren mContext = context; 110d9b659aa5dfa4a3af96582ae49ba9ae145854a84Chris Wren mSettings = AlbumSettings.getAlbumSettings(settings); 11183fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren mResolver = mContext.getContentResolver(); 11283fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren mResources = context.getResources(); 11383fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren mImageQueue = new LinkedList<ImageData>(); 11483fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren mMaxQueueSize = mResources.getInteger(R.integer.image_queue_size); 1155b4b44688dac0053be77b282b7501bd291efb0d3Chris Wren mMaxCropRatio = mResources.getInteger(R.integer.max_crop_ratio) / 1000000f; 11658e2a16d9237d2a5674a97062b5d614d8d397845Chris Wren mBadImageSkipLimit = mResources.getInteger(R.integer.bad_image_skip_limit); 11788d80f4471c900628e2cb6eef23029b99af48e09Chris Wren mImageMap = new HashMap<Bitmap, ImageData>(); 11883fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren mRNG = new Random(); 119b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren mFallbackSource = fallbackSource; 12083fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren } 12183fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren 12283fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren protected void fillQueue() { 12383fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren log(TAG, "filling queue"); 12483fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren mImageQueue.addAll(findImages(mMaxQueueSize - mImageQueue.size())); 12583fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren Collections.shuffle(mImageQueue); 12683fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren log(TAG, "queue contains: " + mImageQueue.size() + " items."); 12783fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren } 12883fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren 12983fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren public Bitmap next(BitmapFactory.Options options, int longSide, int shortSide) { 13083fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren log(TAG, "decoding a picasa resource to " + longSide + ", " + shortSide); 13183fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren Bitmap image = null; 1325006d4093ad1455ee98c157a71f57e9ea42b4daeChris Wren ImageData imageData = null; 13358e2a16d9237d2a5674a97062b5d614d8d397845Chris Wren int tries = 0; 13483fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren 13558e2a16d9237d2a5674a97062b5d614d8d397845Chris Wren while (image == null && tries < mBadImageSkipLimit) { 1365006d4093ad1455ee98c157a71f57e9ea42b4daeChris Wren synchronized(mImageQueue) { 1375006d4093ad1455ee98c157a71f57e9ea42b4daeChris Wren if (mImageQueue.isEmpty()) { 1385006d4093ad1455ee98c157a71f57e9ea42b4daeChris Wren fillQueue(); 1395006d4093ad1455ee98c157a71f57e9ea42b4daeChris Wren } 1405006d4093ad1455ee98c157a71f57e9ea42b4daeChris Wren imageData = mImageQueue.poll(); 1415006d4093ad1455ee98c157a71f57e9ea42b4daeChris Wren } 14268bc9d986e8eb882dc5f15defea0dab45c440ab6Chris Wren if (imageData != null) { 1435006d4093ad1455ee98c157a71f57e9ea42b4daeChris Wren image = load(imageData, options, longSide, shortSide); 14488d80f4471c900628e2cb6eef23029b99af48e09Chris Wren mImageMap.put(image, imageData); 14568bc9d986e8eb882dc5f15defea0dab45c440ab6Chris Wren imageData = null; 14658e2a16d9237d2a5674a97062b5d614d8d397845Chris Wren } 14783fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren 14858e2a16d9237d2a5674a97062b5d614d8d397845Chris Wren tries++; 149b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren } 15083fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren 151b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren if (image == null && mFallbackSource != null) { 152b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren image = load((ImageData) mFallbackSource.findImages(1).toArray()[0], 15358e2a16d9237d2a5674a97062b5d614d8d397845Chris Wren options, longSide, shortSide); 154b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren } 15583fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren 156b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren return image; 157b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren } 15883fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren 159b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren public Bitmap load(ImageData data, BitmapFactory.Options options, int longSide, int shortSide) { 160b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren log(TAG, "decoding photo resource to " + longSide + ", " + shortSide); 161c6bebae5e07c0108294d05e33fbace209d2f9b0dChris Wren InputStream is = data.getStream(longSide); 162b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren 163b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren Bitmap image = null; 164b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren try { 165b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren BufferedInputStream bis = new BufferedInputStream(is); 166b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren bis.mark(BUFFER_SIZE); 167b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren 168b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren options.inJustDecodeBounds = true; 169b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren options.inSampleSize = 1; 170b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren image = BitmapFactory.decodeStream(new BufferedInputStream(bis), null, options); 171b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren int rawLongSide = Math.max(options.outWidth, options.outHeight); 172b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren int rawShortSide = Math.min(options.outWidth, options.outHeight); 173b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren log(TAG, "I see bounds of " + rawLongSide + ", " + rawShortSide); 174b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren 175b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren if (rawLongSide != -1 && rawShortSide != -1) { 176b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren float insideRatio = Math.max((float) longSide / (float) rawLongSide, 177b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren (float) shortSide / (float) rawShortSide); 178b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren float outsideRatio = Math.max((float) longSide / (float) rawLongSide, 179b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren (float) shortSide / (float) rawShortSide); 180b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren float ratio = (outsideRatio / insideRatio < mMaxCropRatio ? 181b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren outsideRatio : insideRatio); 182b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren 183b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren while (ratio < 0.5) { 184b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren options.inSampleSize *= 2; 185b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren ratio *= 2; 18683fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren } 187b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren 188b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren log(TAG, "decoding with inSampleSize " + options.inSampleSize); 18923ab8f3366a5eeecd36c5f489a47eb6b8f03bc56Chris Wren try { 19023ab8f3366a5eeecd36c5f489a47eb6b8f03bc56Chris Wren bis.reset(); 19123ab8f3366a5eeecd36c5f489a47eb6b8f03bc56Chris Wren } catch (IOException ioe) { 19223ab8f3366a5eeecd36c5f489a47eb6b8f03bc56Chris Wren // start over, something went wrong and we read too far into the image. 19323ab8f3366a5eeecd36c5f489a47eb6b8f03bc56Chris Wren bis.close(); 19423ab8f3366a5eeecd36c5f489a47eb6b8f03bc56Chris Wren is = data.getStream(longSide); 19523ab8f3366a5eeecd36c5f489a47eb6b8f03bc56Chris Wren bis = new BufferedInputStream(is); 19623ab8f3366a5eeecd36c5f489a47eb6b8f03bc56Chris Wren log(TAG, "resetting the stream"); 19723ab8f3366a5eeecd36c5f489a47eb6b8f03bc56Chris Wren } 198b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren options.inJustDecodeBounds = false; 199b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren image = BitmapFactory.decodeStream(bis, null, options); 200b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren rawLongSide = Math.max(options.outWidth, options.outHeight); 201b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren rawShortSide = Math.max(options.outWidth, options.outHeight); 20289ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren if (image != null && rawLongSide != -1 && rawShortSide != -1) { 20389ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren ratio = Math.max((float) longSide / (float) rawLongSide, 20489ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren (float) shortSide / (float) rawShortSide); 20589ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren 20689ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren if (Math.abs(ratio - 1.0f) > 0.001) { 20789ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren log(TAG, "still too big, scaling down by " + ratio); 20889ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren options.outWidth = (int) (ratio * options.outWidth); 20989ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren options.outHeight = (int) (ratio * options.outHeight); 21089ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren 21189ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren image = Bitmap.createScaledBitmap(image, 21289ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren options.outWidth, options.outHeight, 21389ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren true); 21489ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren } 215b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren 21689ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren if (data.orientation != 0) { 21789ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren log(TAG, "rotated by " + data.orientation + ": fixing"); 2189ab175f5902c66a266261ccf191bc2d213918ecaChris Wren Matrix matrix = new Matrix(); 2199ab175f5902c66a266261ccf191bc2d213918ecaChris Wren matrix.setRotate(data.orientation, 2209ab175f5902c66a266261ccf191bc2d213918ecaChris Wren (float) Math.floor(image.getWidth() / 2f), 2219ab175f5902c66a266261ccf191bc2d213918ecaChris Wren (float) Math.floor(image.getHeight() / 2f)); 2229ab175f5902c66a266261ccf191bc2d213918ecaChris Wren image = Bitmap.createBitmap(image, 0, 0, 2239ab175f5902c66a266261ccf191bc2d213918ecaChris Wren options.outWidth, options.outHeight, 2249ab175f5902c66a266261ccf191bc2d213918ecaChris Wren matrix, true); 22589ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren if (data.orientation == 90 || data.orientation == 270) { 22689ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren int tmp = options.outWidth; 22789ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren options.outWidth = options.outHeight; 22889ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren options.outHeight = tmp; 22989ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren } 23083fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren } 231b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren 23289ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren log(TAG, "returning bitmap " + image.getWidth() + ", " + image.getHeight()); 23389ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren } else { 23489ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren image = null; 23589ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren } 236b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren } else { 23789ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren image = null; 23889ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren } 23989ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren if (image == null) { 24089ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren log(TAG, "Stream decoding failed with no error" + 24189ada9791087c8004f300ddd9e8ba58fbc84eaaeChris Wren (options.mCancel ? " due to cancelation." : ".")); 242b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren } 2435006d4093ad1455ee98c157a71f57e9ea42b4daeChris Wren } catch (OutOfMemoryError ome) { 2445006d4093ad1455ee98c157a71f57e9ea42b4daeChris Wren log(TAG, "OUT OF MEMORY: " + ome); 2455006d4093ad1455ee98c157a71f57e9ea42b4daeChris Wren image = null; 246b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren } catch (FileNotFoundException fnf) { 247b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren log(TAG, "file not found: " + fnf); 2485006d4093ad1455ee98c157a71f57e9ea42b4daeChris Wren image = null; 249b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren } catch (IOException ioe) { 250b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren log(TAG, "i/o exception: " + ioe); 2515006d4093ad1455ee98c157a71f57e9ea42b4daeChris Wren image = null; 252b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren } finally { 253b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren try { 254b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren if (is != null) { 255b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren is.close(); 25683fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren } 257b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren } catch (Throwable t) { 258b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren log(TAG, "close fail: " + t.toString()); 25983fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren } 26083fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren } 26183fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren 26283fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren return image; 26383fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren } 26483fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren 26583fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren public void setSeed(long seed) { 26683fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren mRNG.setSeed(seed); 26783fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren } 26883fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren 269b8235acb0fdc33c50e864ec801b93b9750d7600cChris Wren protected static void log(String tag, String message) { 27083fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren if (DEBUG) { 27183fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren Log.i(tag, message); 27283fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren } 27383fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren } 27483fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren 275bed703ef28f013639db3cd7a6b8a6e94d61075daChris Wren protected int pickRandomStart(int total, int max) { 276bed703ef28f013639db3cd7a6b8a6e94d61075daChris Wren if (max >= total) { 277bed703ef28f013639db3cd7a6b8a6e94d61075daChris Wren return -1; 278bed703ef28f013639db3cd7a6b8a6e94d61075daChris Wren } else { 279bed703ef28f013639db3cd7a6b8a6e94d61075daChris Wren return (mRNG.nextInt() % (total - max)) - 1; 280bed703ef28f013639db3cd7a6b8a6e94d61075daChris Wren } 281bed703ef28f013639db3cd7a6b8a6e94d61075daChris Wren } 282bed703ef28f013639db3cd7a6b8a6e94d61075daChris Wren 28388d80f4471c900628e2cb6eef23029b99af48e09Chris Wren public Bitmap naturalNext(Bitmap current, BitmapFactory.Options options, 28488d80f4471c900628e2cb6eef23029b99af48e09Chris Wren int longSide, int shortSide) { 28588d80f4471c900628e2cb6eef23029b99af48e09Chris Wren Bitmap image = null; 28688d80f4471c900628e2cb6eef23029b99af48e09Chris Wren ImageData data = mImageMap.get(current); 28788d80f4471c900628e2cb6eef23029b99af48e09Chris Wren if (data != null) { 28888d80f4471c900628e2cb6eef23029b99af48e09Chris Wren ImageData next = data.naturalNext(); 28988d80f4471c900628e2cb6eef23029b99af48e09Chris Wren if (next != null) { 29088d80f4471c900628e2cb6eef23029b99af48e09Chris Wren image = load(next, options, longSide, shortSide); 29188d80f4471c900628e2cb6eef23029b99af48e09Chris Wren mImageMap.put(image, next); 29288d80f4471c900628e2cb6eef23029b99af48e09Chris Wren } 29388d80f4471c900628e2cb6eef23029b99af48e09Chris Wren } 29488d80f4471c900628e2cb6eef23029b99af48e09Chris Wren return image; 29588d80f4471c900628e2cb6eef23029b99af48e09Chris Wren } 29688d80f4471c900628e2cb6eef23029b99af48e09Chris Wren 29788d80f4471c900628e2cb6eef23029b99af48e09Chris Wren public Bitmap naturalPrevious(Bitmap current, BitmapFactory.Options options, 29888d80f4471c900628e2cb6eef23029b99af48e09Chris Wren int longSide, int shortSide) { 29988d80f4471c900628e2cb6eef23029b99af48e09Chris Wren Bitmap image = null; 30088d80f4471c900628e2cb6eef23029b99af48e09Chris Wren ImageData data = mImageMap.get(current); 30188d80f4471c900628e2cb6eef23029b99af48e09Chris Wren if (current != null) { 30288d80f4471c900628e2cb6eef23029b99af48e09Chris Wren ImageData prev = data.naturalPrevious(); 30388d80f4471c900628e2cb6eef23029b99af48e09Chris Wren if (prev != null) { 30488d80f4471c900628e2cb6eef23029b99af48e09Chris Wren image = load(prev, options, longSide, shortSide); 30588d80f4471c900628e2cb6eef23029b99af48e09Chris Wren mImageMap.put(image, prev); 30688d80f4471c900628e2cb6eef23029b99af48e09Chris Wren } 30788d80f4471c900628e2cb6eef23029b99af48e09Chris Wren } 30888d80f4471c900628e2cb6eef23029b99af48e09Chris Wren return image; 30988d80f4471c900628e2cb6eef23029b99af48e09Chris Wren } 31088d80f4471c900628e2cb6eef23029b99af48e09Chris Wren 311bcfd4439d730a4d783a02596c8ab444796323aadChris Wren public void donePaging(Bitmap current) { 312bcfd4439d730a4d783a02596c8ab444796323aadChris Wren ImageData data = mImageMap.get(current); 313bcfd4439d730a4d783a02596c8ab444796323aadChris Wren if (data != null) { 314bcfd4439d730a4d783a02596c8ab444796323aadChris Wren data.donePaging(); 315bcfd4439d730a4d783a02596c8ab444796323aadChris Wren } 316bcfd4439d730a4d783a02596c8ab444796323aadChris Wren } 317bcfd4439d730a4d783a02596c8ab444796323aadChris Wren 318bcfd4439d730a4d783a02596c8ab444796323aadChris Wren public void recycle(Bitmap trash) { 319bcfd4439d730a4d783a02596c8ab444796323aadChris Wren if (trash != null) { 320bcfd4439d730a4d783a02596c8ab444796323aadChris Wren mImageMap.remove(trash); 321bcfd4439d730a4d783a02596c8ab444796323aadChris Wren trash.recycle(); 322bcfd4439d730a4d783a02596c8ab444796323aadChris Wren } 323bcfd4439d730a4d783a02596c8ab444796323aadChris Wren } 324bcfd4439d730a4d783a02596c8ab444796323aadChris Wren 325c6bebae5e07c0108294d05e33fbace209d2f9b0dChris Wren protected abstract InputStream getStream(ImageData data, int longSide); 32683fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren protected abstract Collection<ImageData> findImages(int howMany); 32788d80f4471c900628e2cb6eef23029b99af48e09Chris Wren protected abstract ImageData naturalNext(ImageData current); 32888d80f4471c900628e2cb6eef23029b99af48e09Chris Wren protected abstract ImageData naturalPrevious(ImageData current); 329bcfd4439d730a4d783a02596c8ab444796323aadChris Wren protected abstract void donePaging(ImageData current); 33088d80f4471c900628e2cb6eef23029b99af48e09Chris Wren 331d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren public abstract Collection<AlbumData> findAlbums(); 33283fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren} 333