From b8235acb0fdc33c50e864ec801b93b9750d7600c Mon Sep 17 00:00:00 2001 From: Chris Wren Date: Wed, 26 Sep 2012 10:25:53 -0400 Subject: refine handling of exceptional cases: no settings, network failure, load error. Bug: 7194196 Bug: 7152553 Change-Id: I4335e46fe3a61a09ce3b14a02bb199a84126e53f --- .../android/dreams/phototable/AlbumSettings.java | 7 +- src/com/android/dreams/phototable/BummerView.java | 106 +++++++++++++ .../android/dreams/phototable/FlipperDream.java | 10 +- .../dreams/phototable/FlipperDreamSettings.java | 1 + src/com/android/dreams/phototable/PhotoSource.java | 168 +++++++++++---------- .../dreams/phototable/PhotoSourcePlexor.java | 12 -- .../android/dreams/phototable/PhotoTableDream.java | 24 ++- .../dreams/phototable/PhotoTableDreamSettings.java | 1 + .../android/dreams/phototable/PicasaSource.java | 1 - src/com/android/dreams/phototable/StockSource.java | 38 ++--- 10 files changed, 247 insertions(+), 121 deletions(-) create mode 100644 src/com/android/dreams/phototable/BummerView.java (limited to 'src') diff --git a/src/com/android/dreams/phototable/AlbumSettings.java b/src/com/android/dreams/phototable/AlbumSettings.java index 6a26a3c..502cd3f 100644 --- a/src/com/android/dreams/phototable/AlbumSettings.java +++ b/src/com/android/dreams/phototable/AlbumSettings.java @@ -24,13 +24,12 @@ import java.util.Set; * Common utilities for album settings. */ public class AlbumSettings { - public static final String ALBUM_SET = "Enabled Album Set"; + public static final String ALBUM_SET = "Enabled Album Set V2"; public static Set getEnabledAlbums(SharedPreferences settings) { Set enabled = settings.getStringSet(ALBUM_SET, null); if (enabled == null) { enabled = new HashSet(); - enabled.add(StockSource.ALBUM_ID); setEnabledAlbums(settings, enabled); } return enabled; @@ -41,4 +40,8 @@ public class AlbumSettings { editor.putStringSet(ALBUM_SET, value); editor.apply(); } + + public static boolean isConfigured(SharedPreferences settings) { + return getEnabledAlbums(settings).size() != 0; + } } diff --git a/src/com/android/dreams/phototable/BummerView.java b/src/com/android/dreams/phototable/BummerView.java new file mode 100644 index 0000000..ff0a11f --- /dev/null +++ b/src/com/android/dreams/phototable/BummerView.java @@ -0,0 +1,106 @@ +/* + * 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.Context; +import android.os.Handler; +import android.os.Message; +import android.util.AttributeSet; +import android.view.View; +import android.widget.TextView; + +public class BummerView extends TextView { + public static final int START = 1; + public static final int MOVE = 2; + + private int mDelay = 10000; // ms + private int mAnimTime = 2000; // ms + private boolean mAnimate = false; + + private Handler mHandler = new Handler() { + @Override + public void handleMessage(Message m) { + boolean animate = false; + switch (m.what) { + case MOVE: + animate = mAnimate; + // fall through + case START: + final View parent = (View) BummerView.this.getParent(); + if (parent == null) + return; + + final float framew = parent.getMeasuredWidth(); + final float frameh = parent.getMeasuredHeight(); + final float textw = getMeasuredWidth(); + final float texth = getMeasuredHeight(); + + final float newx = (float) (Math.random() * (framew - textw)); + final float newy = (float) (Math.random() * (frameh - texth)); + if (animate) { + animate().x(newx) + .y(newy) + .setDuration(mAnimTime) + .start(); + } else { + setX(newx); + setY(newy); + } + setVisibility(View.VISIBLE); + + removeMessages(MOVE); + sendEmptyMessageDelayed(MOVE, mDelay); + break; + } + } + }; + + public BummerView(Context context) { + super(context); + } + + public BummerView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public BummerView(Context context, AttributeSet attrs, int flags) { + super(context, attrs, flags); + } + + public void setAnimationParams(boolean animate, int delay, int animTime) { + mAnimate = animate; + mDelay = delay; + mAnimTime = animTime; + } + + @Override + public void onAttachedToWindow() { + final View parent = (View) this.getParent(); + parent.addOnLayoutChangeListener(new OnLayoutChangeListener() { + public void onLayoutChange(View v, int left, int top, int right, int bottom, + int oldLeft, int oldTop, int oldRight, int oldBottom) { + if (v == parent && right != oldRight) { + mHandler.removeMessages(MOVE); + mHandler.sendEmptyMessage(START); + } + } + }); + + mHandler.sendEmptyMessage(START); + } + +} diff --git a/src/com/android/dreams/phototable/FlipperDream.java b/src/com/android/dreams/phototable/FlipperDream.java index 32a43d1..f64b7cb 100644 --- a/src/com/android/dreams/phototable/FlipperDream.java +++ b/src/com/android/dreams/phototable/FlipperDream.java @@ -15,6 +15,7 @@ */ package com.android.dreams.phototable; +import android.content.SharedPreferences; import android.service.dreams.Dream; /** @@ -32,7 +33,14 @@ public class FlipperDream extends Dream { @Override public void onAttachedToWindow() { super.onAttachedToWindow(); + + SharedPreferences settings = getSharedPreferences(FlipperDreamSettings.PREFS_NAME, 0); + if (AlbumSettings.isConfigured(settings)) { + setContentView(R.layout.carousel); + } else { + setContentView(R.layout.bummer); + } + setFullscreen(true); - setContentView(R.layout.carousel); } } diff --git a/src/com/android/dreams/phototable/FlipperDreamSettings.java b/src/com/android/dreams/phototable/FlipperDreamSettings.java index 720599f..cac415c 100644 --- a/src/com/android/dreams/phototable/FlipperDreamSettings.java +++ b/src/com/android/dreams/phototable/FlipperDreamSettings.java @@ -48,5 +48,6 @@ public class FlipperDreamSettings extends ListActivity { R.layout.album, new LinkedList(mPhotoSource.findAlbums())); setListAdapter(mAdapter); + setContentView(R.layout.settingslist); } } diff --git a/src/com/android/dreams/phototable/PhotoSource.java b/src/com/android/dreams/phototable/PhotoSource.java index c2b423b..44e00d9 100644 --- a/src/com/android/dreams/phototable/PhotoSource.java +++ b/src/com/android/dreams/phototable/PhotoSource.java @@ -41,7 +41,7 @@ import java.util.Random; */ public abstract class PhotoSource { private static final String TAG = "PhotoTable.PhotoSource"; - private static final boolean DEBUG = false; + private static final boolean DEBUG = true; // 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 @@ -74,6 +74,7 @@ public abstract class PhotoSource { private final LinkedList mImageQueue; private final int mMaxQueueSize; private final float mMaxCropRatio; + private final PhotoSource mFallbackSource; protected final Context mContext; protected final Resources mResources; @@ -84,6 +85,10 @@ public abstract class PhotoSource { protected String mSourceName; public PhotoSource(Context context, SharedPreferences settings) { + this(context, settings, new StockSource(context, settings)); + } + + public PhotoSource(Context context, SharedPreferences settings, PhotoSource fallbackSource) { mSourceName = TAG; mContext = context; mSettings = settings; @@ -93,6 +98,7 @@ public abstract class PhotoSource { mMaxQueueSize = mResources.getInteger(R.integer.image_queue_size); mMaxCropRatio = mResources.getInteger(R.integer.max_crop_ratio) / 1000000f; mRNG = new Random(); + mFallbackSource = fallbackSource; } protected void fillQueue() { @@ -111,87 +117,97 @@ public abstract class PhotoSource { } if (!mImageQueue.isEmpty()) { - ImageData data = mImageQueue.poll(); - InputStream is = null; - try { - is = data.getStream(); - 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 insideRatio = Math.max((float) longSide / (float) rawLongSide, - (float) shortSide / (float) rawShortSide); - float outsideRatio = Math.max((float) longSide / (float) rawLongSide, - (float) shortSide / (float) rawShortSide); - float ratio = (outsideRatio / insideRatio < mMaxCropRatio ? - outsideRatio : insideRatio); - - while (ratio < 0.5) { - options.inSampleSize *= 2; - ratio *= 2; - } + image = load(mImageQueue.poll(), options, longSide, shortSide); + } - 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 (image == null && mFallbackSource != null) { + image = load((ImageData) mFallbackSource.findImages(1).toArray()[0], + options, longSide, shortSide); + } - 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); - } + return image; + } - log(TAG, "returning bitmap " + image.getWidth() + ", " + image.getHeight()); - } else { - log(TAG, "decoding failed with no error: " + options.mCancel); + public Bitmap load(ImageData data, BitmapFactory.Options options, int longSide, int shortSide) { + log(TAG, "decoding photo resource to " + longSide + ", " + shortSide); + InputStream is = data.getStream(); + + Bitmap image = null; + try { + 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 insideRatio = Math.max((float) longSide / (float) rawLongSide, + (float) shortSide / (float) rawShortSide); + float outsideRatio = Math.max((float) longSide / (float) rawLongSide, + (float) shortSide / (float) rawShortSide); + float ratio = (outsideRatio / insideRatio < mMaxCropRatio ? + outsideRatio : insideRatio); + + while (ratio < 0.5) { + options.inSampleSize *= 2; + ratio *= 2; } - } 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(); + + 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 (Math.abs(ratio - 1.0f) > 0.001) { + 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; } - } catch (Throwable t) { - log(TAG, "close fail: " + t.toString()); + 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; @@ -201,7 +217,7 @@ public abstract class PhotoSource { mRNG.setSeed(seed); } - protected void log(String tag, String message) { + protected static void log(String tag, String message) { if (DEBUG) { Log.i(tag, message); } diff --git a/src/com/android/dreams/phototable/PhotoSourcePlexor.java b/src/com/android/dreams/phototable/PhotoSourcePlexor.java index 7cf207e..cf19d80 100644 --- a/src/com/android/dreams/phototable/PhotoSourcePlexor.java +++ b/src/com/android/dreams/phototable/PhotoSourcePlexor.java @@ -34,7 +34,6 @@ public class PhotoSourcePlexor extends PhotoSource { private final PhotoSource mPicasaSource; private final PhotoSource mLocalSource; - private final PhotoSource mStockSource; private SharedPreferences mSettings; public PhotoSourcePlexor(Context context, SharedPreferences settings) { @@ -42,7 +41,6 @@ public class PhotoSourcePlexor extends PhotoSource { mSourceName = TAG; mPicasaSource = new PicasaSource(context, settings); mLocalSource = new LocalSource(context, settings); - mStockSource = new StockSource(context, settings); } @Override @@ -56,11 +54,6 @@ public class PhotoSourcePlexor extends PhotoSource { foundAlbums.addAll(mLocalSource.findAlbums()); log(TAG, "found " + foundAlbums.size() + " user albums"); - if (foundAlbums.isEmpty()) { - foundAlbums.addAll(mStockSource.findAlbums()); - } - log(TAG, "found " + foundAlbums.size() + " albums"); - return foundAlbums; } @@ -75,11 +68,6 @@ public class PhotoSourcePlexor extends PhotoSource { foundImages.addAll(mLocalSource.findImages(howMany)); log(TAG, "found " + foundImages.size() + " user images"); - if (foundImages.isEmpty()) { - foundImages.addAll(mStockSource.findImages(howMany)); - } - log(TAG, "found " + foundImages.size() + " images"); - return foundImages; } diff --git a/src/com/android/dreams/phototable/PhotoTableDream.java b/src/com/android/dreams/phototable/PhotoTableDream.java index cebd3f8..21ae694 100644 --- a/src/com/android/dreams/phototable/PhotoTableDream.java +++ b/src/com/android/dreams/phototable/PhotoTableDream.java @@ -16,10 +16,14 @@ package com.android.dreams.phototable; import android.content.Context; +import android.content.SharedPreferences; +import android.content.res.Resources; import android.service.dreams.Dream; import android.view.LayoutInflater; import android.view.ViewGroup; +import java.util.Set; + /** * Example interactive screen saver: flick photos onto a table. */ @@ -38,10 +42,22 @@ public class PhotoTableDream extends Dream { super.onAttachedToWindow(); LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); - ViewGroup view = (ViewGroup) inflater.inflate(R.layout.table, null); - PhotoTable table = (PhotoTable) view.findViewById(R.id.table); - table.setDream(this); - setContentView(view); + SharedPreferences settings = getSharedPreferences(PhotoTableDreamSettings.PREFS_NAME, 0); + Set enabledAlbums = AlbumSettings.getEnabledAlbums(settings); + if (AlbumSettings.isConfigured(settings)) { + ViewGroup view = (ViewGroup) inflater.inflate(R.layout.table, null); + PhotoTable table = (PhotoTable) view.findViewById(R.id.table); + table.setDream(this); + setContentView(view); + } else { + Resources resources = getResources(); + ViewGroup view = (ViewGroup) inflater.inflate(R.layout.bummer, null); + BummerView bummer = (BummerView) view.findViewById(R.id.bummer); + bummer.setAnimationParams(true, + resources.getInteger(R.integer.table_drop_period), + resources.getInteger(R.integer.fast_drop)); + setContentView(view); + } setFullscreen(true); } } diff --git a/src/com/android/dreams/phototable/PhotoTableDreamSettings.java b/src/com/android/dreams/phototable/PhotoTableDreamSettings.java index 7271f3f..4340eba 100644 --- a/src/com/android/dreams/phototable/PhotoTableDreamSettings.java +++ b/src/com/android/dreams/phototable/PhotoTableDreamSettings.java @@ -48,5 +48,6 @@ public class PhotoTableDreamSettings extends ListActivity { R.layout.album, new LinkedList(mPhotoSource.findAlbums())); setListAdapter(mAdapter); + setContentView(R.layout.settingslist); } } diff --git a/src/com/android/dreams/phototable/PicasaSource.java b/src/com/android/dreams/phototable/PicasaSource.java index cd5ddcd..92adfa6 100644 --- a/src/com/android/dreams/phototable/PicasaSource.java +++ b/src/com/android/dreams/phototable/PicasaSource.java @@ -75,7 +75,6 @@ public class PicasaSource extends PhotoSource { mPostsAlbumName = mResources.getString(R.string.posts_album_name, "Posts"); mUploadsAlbumName = mResources.getString(R.string.uploads_album_name, "Instant Uploads"); mUnknownAlbumName = mResources.getString(R.string.unknown_album_name, "Unknown"); - log(TAG, "mSettings: " + mSettings); fillQueue(); } diff --git a/src/com/android/dreams/phototable/StockSource.java b/src/com/android/dreams/phototable/StockSource.java index fff7e61..1e00780 100644 --- a/src/com/android/dreams/phototable/StockSource.java +++ b/src/com/android/dreams/phototable/StockSource.java @@ -21,42 +21,30 @@ import android.util.Log; import java.io.InputStream; import java.util.Collection; -import java.util.LinkedList; +import java.util.ArrayList; /** * Picks a random image from the local store. */ -public class StockSource extends PhotoSource { +public class + +StockSource extends PhotoSource { public static final String ALBUM_ID = "com.android.dreams.phototable.StockSource"; private static final String TAG = "PhotoTable.StockSource"; - private static final int[] PHOTOS = {R.drawable.photo_044_002, - R.drawable.photo_039_002, - R.drawable.photo_059_003, - R.drawable.photo_070_004, - R.drawable.photo_072_001, - R.drawable.photo_077_002, - R.drawable.photo_098_002, - R.drawable.photo_119_003, - R.drawable.photo_119_004, - R.drawable.photo_126_001, - R.drawable.photo_147_002, - R.drawable.photo_175_004 - }; + private static final int[] PHOTOS = { R.drawable.blank_photo }; - private final LinkedList mImageList; - private final LinkedList mAlbumList; + private final ArrayList mImageList; + private final ArrayList mAlbumList; private final String mStockPhotoName; - private final String mStockThumbnail; private int mNextPosition; public StockSource(Context context, SharedPreferences settings) { - super(context, settings); + super(context, settings, null); mSourceName = TAG; mStockPhotoName = mResources.getString(R.string.stock_photo_album_name, "Default Photos"); - mStockThumbnail = mResources.getString(R.string.stock_photo_thumbnail_url); - mImageList = new LinkedList(); - mAlbumList = new LinkedList(); + mImageList = new ArrayList(PHOTOS.length); + mAlbumList = new ArrayList(1); fillQueue(); } @@ -67,8 +55,7 @@ public class StockSource extends PhotoSource { data.id = ALBUM_ID; data.account = mStockPhotoName; data.title = mStockPhotoName; - data.thumbnailUrl = mStockThumbnail; - mAlbumList.offer(data); + mAlbumList.add(data); } log(TAG, "returning a list of albums: " + mAlbumList.size()); return mAlbumList; @@ -80,7 +67,7 @@ public class StockSource extends PhotoSource { for (int i = 0; i < PHOTOS.length; i++) { ImageData data = new ImageData(); data.id = Integer.toString(PHOTOS[i]); - mImageList.offer(data); + mImageList.add(data); } } return mImageList; @@ -100,3 +87,4 @@ public class StockSource extends PhotoSource { return is; } } + -- cgit v1.2.3