summaryrefslogtreecommitdiffstats
path: root/src/com/android/dreams/phototable/PhotoSource.java
diff options
context:
space:
mode:
authorChris Wren <cwren@android.com>2012-09-05 17:35:10 -0400
committerChris Wren <cwren@android.com>2012-09-05 17:38:47 -0400
commit83fee9012b6d5c5940de5b96fe8d98653ba14c0d (patch)
treeefe4be787e7390528834a1d9e608cf66603808a0 /src/com/android/dreams/phototable/PhotoSource.java
parentc1501041b64faa6c205a93baf403c4c87a0c1acf (diff)
downloadandroid_packages_screensavers_PhotoTable-83fee9012b6d5c5940de5b96fe8d98653ba14c0d.tar.gz
android_packages_screensavers_PhotoTable-83fee9012b6d5c5940de5b96fe8d98653ba14c0d.tar.bz2
android_packages_screensavers_PhotoTable-83fee9012b6d5c5940de5b96fe8d98653ba14c0d.zip
refactor photo sources and other cleanup.
Change-Id: I22fda6f1e443776133bc9e0e242d4a6081eb1ba3
Diffstat (limited to 'src/com/android/dreams/phototable/PhotoSource.java')
-rw-r--r--src/com/android/dreams/phototable/PhotoSource.java183
1 files changed, 183 insertions, 0 deletions
diff --git a/src/com/android/dreams/phototable/PhotoSource.java b/src/com/android/dreams/phototable/PhotoSource.java
new file mode 100644
index 0000000..2851c6c
--- /dev/null
+++ b/src/com/android/dreams/phototable/PhotoSource.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.dreams.phototable;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.res.Resources;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Matrix;
+import android.net.Uri;
+import android.provider.MediaStore;
+import android.util.Log;
+
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.BufferedInputStream;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.Random;
+
+/**
+ * Picks a random image from a source of photos.
+ */
+public abstract class PhotoSource {
+ private static final String TAG = "PhotoTable.PhotoSource";
+ private static final boolean DEBUG = false;
+
+ // This should be large enough for BitmapFactory to decode the header so
+ // that we can mark and reset the input stream to avoid duplicate network i/o
+ private static final int BUFFER_SIZE = 128 * 1024;
+
+ public static class ImageData {
+ public String id;
+ public String url;
+ public int orientation;
+ public int type;
+ }
+
+ private final Context mContext;
+ private final LinkedList<ImageData> mImageQueue;
+ private final int mMaxQueueSize;
+
+ protected final Resources mResources;
+ protected ContentResolver mResolver;
+ protected String mSourceName;
+ protected final Random mRNG;
+
+ public PhotoSource(Context context) {
+ mSourceName = TAG;
+ mContext = context;
+ mResolver = mContext.getContentResolver();
+ mResources = context.getResources();
+ mImageQueue = new LinkedList<ImageData>();
+ mMaxQueueSize = mResources.getInteger(R.integer.image_queue_size);
+ mRNG = new Random();
+ }
+
+ protected void fillQueue() {
+ log(TAG, "filling queue");
+ mImageQueue.addAll(findImages(mMaxQueueSize - mImageQueue.size()));
+ Collections.shuffle(mImageQueue);
+ log(TAG, "queue contains: " + mImageQueue.size() + " items.");
+ }
+
+ public Bitmap next(BitmapFactory.Options options, int longSide, int shortSide) {
+ log(TAG, "decoding a picasa resource to " + longSide + ", " + shortSide);
+ Bitmap image = null;
+
+ if (mImageQueue.isEmpty()) {
+ fillQueue();
+ }
+
+ if (!mImageQueue.isEmpty()) {
+ ImageData data = mImageQueue.poll();
+ InputStream is = null;
+ try {
+ is = getStream(data);
+ BufferedInputStream bis = new BufferedInputStream(is);
+ bis.mark(BUFFER_SIZE);
+
+ options.inJustDecodeBounds = true;
+ options.inSampleSize = 1;
+ image = BitmapFactory.decodeStream(new BufferedInputStream(bis), null, options);
+ int rawLongSide = Math.max(options.outWidth, options.outHeight);
+ int rawShortSide = Math.min(options.outWidth, options.outHeight);
+ log(TAG, "I see bounds of " + rawLongSide + ", " + rawShortSide);
+
+ if (rawLongSide != -1 && rawShortSide != -1) {
+ float ratio = Math.max((float) longSide / (float) rawLongSide,
+ (float) shortSide / (float) rawShortSide);
+ while (ratio < 0.5) {
+ options.inSampleSize *= 2;
+ ratio *= 2;
+ }
+
+ log(TAG, "decoding with inSampleSize " + options.inSampleSize);
+ bis.reset();
+ options.inJustDecodeBounds = false;
+ image = BitmapFactory.decodeStream(bis, null, options);
+ rawLongSide = Math.max(options.outWidth, options.outHeight);
+ rawShortSide = Math.max(options.outWidth, options.outHeight);
+ ratio = Math.max((float) longSide / (float) rawLongSide,
+ (float) shortSide / (float) rawShortSide);
+
+ if (ratio < 1.0f) {
+ log(TAG, "still too big, scaling down by " + ratio);
+ options.outWidth = (int) (ratio * options.outWidth);
+ options.outHeight = (int) (ratio * options.outHeight);
+ image = Bitmap.createScaledBitmap(image,
+ options.outWidth, options.outHeight,
+ true);
+ }
+
+ if (data.orientation != 0) {
+ log(TAG, "rotated by " + data.orientation + ": fixing");
+ if (data.orientation == 90 || data.orientation == 270) {
+ int tmp = options.outWidth;
+ options.outWidth = options.outHeight;
+ options.outHeight = tmp;
+ }
+ Matrix matrix = new Matrix();
+ matrix.setRotate(data.orientation,
+ (float) image.getWidth() / 2,
+ (float) image.getHeight() / 2);
+ image = Bitmap.createBitmap(image, 0, 0,
+ options.outHeight, options.outWidth,
+ matrix, true);
+ }
+
+ log(TAG, "returning bitmap " + image.getWidth() + ", " + image.getHeight());
+ } else {
+ log(TAG, "decoding failed with no error: " + options.mCancel);
+ }
+ } catch (FileNotFoundException fnf) {
+ log(TAG, "file not found: " + fnf);
+ } catch (IOException ioe) {
+ log(TAG, "i/o exception: " + ioe);
+ } finally {
+ try {
+ if (is != null) {
+ is.close();
+ }
+ } catch (Throwable t) {
+ log(TAG, "close fail: " + t.toString());
+ }
+ }
+ } else {
+ log(TAG, mSourceName + " has no images.");
+ }
+
+ return image;
+ }
+
+ public void setSeed(long seed) {
+ mRNG.setSeed(seed);
+ }
+
+ protected void log(String tag, String message) {
+ if (DEBUG) {
+ Log.i(tag, message);
+ }
+ }
+
+ protected abstract InputStream getStream(ImageData data);
+ protected abstract Collection<ImageData> findImages(int howMany);
+}