summaryrefslogtreecommitdiffstats
path: root/src/com/android/dreams/phototable/PhotoTable.java
diff options
context:
space:
mode:
authorChris Wren <cwren@android.com>2013-04-04 09:17:26 -0400
committerChris Wren <cwren@android.com>2013-04-09 01:54:16 -0400
commit88d80f4471c900628e2cb6eef23029b99af48e09 (patch)
tree6829842f0dff21db530936037cd242853f43b416 /src/com/android/dreams/phototable/PhotoTable.java
parent1dc94b55d59f5c4dbf86788d0c32b7ac4449909a (diff)
downloadandroid_packages_screensavers_PhotoTable-88d80f4471c900628e2cb6eef23029b99af48e09.tar.gz
android_packages_screensavers_PhotoTable-88d80f4471c900628e2cb6eef23029b99af48e09.tar.bz2
android_packages_screensavers_PhotoTable-88d80f4471c900628e2cb6eef23029b99af48e09.zip
story mode for PhotoTable.
also some cleanup and refactoring also fix stuck alphas Bug: 8399588 Change-Id: Id236b29701ede3696c8f1f0ccc6522eb8256ff25
Diffstat (limited to 'src/com/android/dreams/phototable/PhotoTable.java')
-rw-r--r--src/com/android/dreams/phototable/PhotoTable.java456
1 files changed, 290 insertions, 166 deletions
diff --git a/src/com/android/dreams/phototable/PhotoTable.java b/src/com/android/dreams/phototable/PhotoTable.java
index 4cf278c..7d2f6b6 100644
--- a/src/com/android/dreams/phototable/PhotoTable.java
+++ b/src/com/android/dreams/phototable/PhotoTable.java
@@ -15,13 +15,10 @@
*/
package com.android.dreams.phototable;
-import android.service.dreams.DreamService;
import android.content.Context;
-import android.content.SharedPreferences;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
-import android.graphics.Color;
import android.graphics.PointF;
import android.graphics.PorterDuff;
import android.graphics.Rect;
@@ -29,6 +26,7 @@ import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.os.AsyncTask;
+import android.service.dreams.DreamService;
import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
@@ -39,8 +37,9 @@ import android.view.ViewPropertyAnimator;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.widget.FrameLayout;
-import android.widget.FrameLayout.LayoutParams;
import android.widget.ImageView;
+
+import java.util.Formatter;
import java.util.LinkedList;
import java.util.Random;
@@ -68,8 +67,8 @@ public class PhotoTable extends FrameLayout {
private static final int MAX_SELECTION_TIME = 10000;
private static final int MAX_FOCUS_TIME = 5000;
- private static final float EDGE_SWIPE_GUTTER = 0.05f;
- private static final float EDGE_SWIPE_THRESHOLD = 0.25f;
+ private static final int NEXT = 1;
+ private static final int PREV = 0;
private static Random sRNG = new Random();
private final Launcher mLauncher;
@@ -91,20 +90,23 @@ public class PhotoTable extends FrameLayout {
private final Resources mResources;
private final Interpolator mThrowInterpolator;
private final Interpolator mDropInterpolator;
- final private EdgeSwipeDetector mEdgeSwipeDetector;
- final private DragGestureDetector mDragGestureDetector;
+ private final DragGestureDetector mDragGestureDetector;
+ private final EdgeSwipeDetector mEdgeSwipeDetector;
+ private final KeyboardInterpreter mKeyboardInterpreter;
+ private final boolean mStoryModeEnabled;
private DreamService mDream;
private PhotoLaunchTask mPhotoLaunchTask;
+ private LoadNaturalSiblingTask mLoadOnDeckTasks[];
private boolean mStarted;
private boolean mIsLandscape;
private int mLongSide;
private int mShortSide;
private int mWidth;
private int mHeight;
- private View mSelected;
- private long mSelectedTime;
- private View mFocused;
- private long mFocusedTime;
+ private View mSelection;
+ private View mOnDeck[];
+ private long mSelectionTime;
+ private View mFocus;
private int mHighlightColor;
public PhotoTable(Context context, AttributeSet as) {
@@ -122,6 +124,7 @@ public class PhotoTable extends FrameLayout {
mTableCapacity = mResources.getInteger(R.integer.table_capacity);
mRedealCount = mResources.getInteger(R.integer.redeal_count);
mTapToExit = mResources.getBoolean(R.bool.enable_tap_to_exit);
+ mStoryModeEnabled = mResources.getBoolean(R.bool.enable_story_mode);
mHighlightColor = mResources.getColor(R.color.highlight_color);
mThrowInterpolator = new SoftLandingInterpolator(
mResources.getInteger(R.integer.soft_landing_time) / 1000000f,
@@ -133,8 +136,11 @@ public class PhotoTable extends FrameLayout {
getContext().getSharedPreferences(PhotoTableDreamSettings.PREFS_NAME, 0));
mLauncher = new Launcher();
mFocusReaper = new FocusReaper();
- mEdgeSwipeDetector = new EdgeSwipeDetector(context, this);
mDragGestureDetector = new DragGestureDetector(context, this);
+ mEdgeSwipeDetector = new EdgeSwipeDetector(context, this);
+ mKeyboardInterpreter = new KeyboardInterpreter(this);
+ mLoadOnDeckTasks = new LoadNaturalSiblingTask[2];
+ mOnDeck = new View[2];
mStarted = false;
}
@@ -144,49 +150,107 @@ public class PhotoTable extends FrameLayout {
}
public boolean hasSelection() {
- return mSelected != null;
+ return mSelection != null;
}
- public View getSelected() {
- return mSelected;
+ public View getSelection() {
+ return mSelection;
}
public void clearSelection() {
if (hasSelection()) {
- dropOnTable(getSelected());
+ dropOnTable(getSelection());
+ }
+ for (int slot = 0; slot < mOnDeck.length; slot++) {
+ if (mOnDeck[slot] != null) {
+ fadeAway(mOnDeck[slot], false);
+ mOnDeck[slot] = null;
+ }
}
- mSelected = null;
+ mSelection = null;
}
public void setSelection(View selected) {
- assert(selected != null);
- clearSelection();
- mSelected = selected;
- mSelectedTime = System.currentTimeMillis();
- moveToTopOfPile(selected);
- pickUp(selected);
+ if (selected != null) {
+ clearSelection();
+ mSelection = selected;
+ promoteSelection();
+ }
+ }
+
+ public void selectNext() {
+ if (mStoryModeEnabled) {
+ log("selectNext");
+ if (hasSelection() && mOnDeck[NEXT] != null) {
+ placeOnDeck(mSelection, PREV);
+ mSelection = mOnDeck[NEXT];
+ mOnDeck[NEXT] = null;
+ promoteSelection();
+ }
+ } else {
+ clearSelection();
+ }
+ }
+
+ public void selectPrevious() {
+ if (mStoryModeEnabled) {
+ log("selectPrevious");
+ if (hasSelection() && mOnDeck[PREV] != null) {
+ placeOnDeck(mSelection, NEXT);
+ mSelection = mOnDeck[PREV];
+ mOnDeck[PREV] = null;
+ promoteSelection();
+ }
+ } else {
+ clearSelection();
+ }
+ }
+
+ private void promoteSelection() {
+ if (hasSelection()) {
+ mSelectionTime = System.currentTimeMillis();
+ mSelection.animate().cancel();
+ mSelection.setAlpha(1f);
+ moveToTopOfPile(mSelection);
+ pickUp(mSelection);
+ if (mStoryModeEnabled) {
+ for (int slot = 0; slot < mOnDeck.length; slot++) {
+ if (mLoadOnDeckTasks[slot] != null &&
+ mLoadOnDeckTasks[slot].getStatus() != AsyncTask.Status.FINISHED) {
+ mLoadOnDeckTasks[slot].cancel(true);
+ }
+ if (mOnDeck[slot] == null) {
+ mLoadOnDeckTasks[slot] = new LoadNaturalSiblingTask(slot);
+ mLoadOnDeckTasks[slot].execute(mSelection);
+ }
+ }
+ }
+ }
}
public boolean hasFocus() {
- return mFocused != null;
+ return mFocus != null;
}
- public View getFocused() {
- return mFocused;
+ public View getFocus() {
+ return mFocus;
}
public void clearFocus() {
if (hasFocus()) {
- setHighlight(getFocused(), false);
+ setHighlight(getFocus(), false);
}
- mFocused = null;
+ mFocus = null;
+ }
+
+ public void setDefaultFocus() {
+ setFocus(mOnTable.getLast());
}
public void setFocus(View focus) {
assert(focus != null);
clearFocus();
- mFocused = focus;
- mFocusedTime = System.currentTimeMillis();
+ mFocus = focus;
moveToTopOfPile(focus);
setHighlight(focus, true);
scheduleFocusReaper(MAX_FOCUS_TIME);
@@ -214,17 +278,8 @@ public class PhotoTable extends FrameLayout {
return p;
}
- private static PointF randInCenter(float i, float j, int width, int height) {
- log("randInCenter (" + i + ", " + j + ", " + width + ", " + height + ")");
- PointF p = new PointF();
- p.x = 0.5f * width + 0.15f * width * i;
- p.y = 0.5f * height + 0.15f * height * j;
- log("randInCenter returning " + p.x + "," + p.y);
- return p;
- }
-
private static PointF randMultiDrop(int n, float i, float j, int width, int height) {
- log("randMultiDrop (" + n + "," + i + ", " + j + ", " + width + ", " + height + ")");
+ log("randMultiDrop (%d, %f, %f, %d, %d)", n, i, j, width, height);
final float[] cx = {0.3f, 0.3f, 0.5f, 0.7f, 0.7f};
final float[] cy = {0.3f, 0.7f, 0.5f, 0.3f, 0.7f};
n = Math.abs(n);
@@ -233,7 +288,7 @@ public class PhotoTable extends FrameLayout {
PointF p = new PointF();
p.x = x * width + 0.05f * width * i;
p.y = y * height + 0.05f * height * j;
- log("randInCenter returning " + p.x + "," + p.y);
+ log("randInCenter returning %f, %f", p.x, p.y);
return p;
}
@@ -241,10 +296,6 @@ public class PhotoTable extends FrameLayout {
return a[0] * b[1] - a[1] * b[0];
}
- private double dot(double[] a, double[] b) {
- return a[0] * b[0] + a[1] * b[1];
- }
-
private double norm(double[] a) {
return Math.hypot(a[0], a[1]);
}
@@ -296,74 +347,12 @@ public class PhotoTable extends FrameLayout {
setFocus(bestFocus);
}
}
- return getFocused();
+ return getFocus();
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
- final View focus = getFocused();
- boolean consumed = true;
-
- if (hasSelection()) {
- switch (keyCode) {
- case KeyEvent.KEYCODE_ENTER:
- case KeyEvent.KEYCODE_DPAD_CENTER:
- case KeyEvent.KEYCODE_ESCAPE:
- setFocus(getSelected());
- clearSelection();
- break;
- default:
- log("dropped unexpected: " + keyCode);
- consumed = false;
- break;
- }
- } else {
- switch (keyCode) {
- case KeyEvent.KEYCODE_ENTER:
- case KeyEvent.KEYCODE_DPAD_CENTER:
- if (hasFocus()) {
- setSelection(getFocused());
- clearFocus();
- } else {
- setFocus(mOnTable.getLast());
- }
- break;
-
- case KeyEvent.KEYCODE_DEL:
- case KeyEvent.KEYCODE_X:
- if (hasFocus()) {
- fling(getFocused());
- }
- break;
-
- case KeyEvent.KEYCODE_DPAD_UP:
- case KeyEvent.KEYCODE_K:
- moveFocus(focus, 0f);
- break;
-
- case KeyEvent.KEYCODE_DPAD_RIGHT:
- case KeyEvent.KEYCODE_L:
- moveFocus(focus, 90f);
- break;
-
- case KeyEvent.KEYCODE_DPAD_DOWN:
- case KeyEvent.KEYCODE_J:
- moveFocus(focus, 180f);
- break;
-
- case KeyEvent.KEYCODE_DPAD_LEFT:
- case KeyEvent.KEYCODE_H:
- moveFocus(focus, 270f);
- break;
-
- default:
- log("dropped unexpected: " + keyCode);
- consumed = false;
- break;
- }
- }
-
- return consumed;
+ return mKeyboardInterpreter.onKeyDown(keyCode, event);
}
@Override
@@ -389,7 +378,7 @@ public class PhotoTable extends FrameLayout {
@Override
public void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
- log("onLayout (" + left + ", " + top + ", " + right + ", " + bottom + ")");
+ log("onLayout (%d, %d, %d, %d)", left, top, right, bottom);
mHeight = bottom - top;
mWidth = right - left;
@@ -400,12 +389,18 @@ public class PhotoTable extends FrameLayout {
boolean isLandscape = mWidth > mHeight;
if (mIsLandscape != isLandscape) {
for (View photo: mOnTable) {
- if (photo == getSelected()) {
- pickUp(photo);
- } else {
+ if (photo != getSelection()) {
dropOnTable(photo);
}
}
+ if (hasSelection()) {
+ pickUp(getSelection());
+ for (int slot = 0; slot < mOnDeck.length; slot++) {
+ if (mOnDeck[slot] != null) {
+ placeOnDeck(mOnDeck[slot], slot);
+ }
+ }
+ }
mIsLandscape = isLandscape;
}
start();
@@ -416,47 +411,101 @@ public class PhotoTable extends FrameLayout {
return true;
}
- private class PhotoLaunchTask extends AsyncTask<Void, Void, View> {
+ /** Put a nice border on the bitmap. */
+ private static View applyFrame(final PhotoTable table, final BitmapFactory.Options options,
+ final Bitmap decodedPhoto) {
+ LayoutInflater inflater = (LayoutInflater) table.getContext()
+ .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ View photo = inflater.inflate(R.layout.photo, null);
+ ImageView image = (ImageView) photo;
+ Drawable[] layers = new Drawable[2];
+ int photoWidth = options.outWidth;
+ int photoHeight = options.outHeight;
+ if (decodedPhoto == null || options.outWidth <= 0 || options.outHeight <= 0) {
+ photo = null;
+ } else {
+ decodedPhoto.setHasMipMap(true);
+ layers[0] = new BitmapDrawable(table.mResources, decodedPhoto);
+ layers[1] = table.mResources.getDrawable(R.drawable.frame);
+ LayerDrawable layerList = new LayerDrawable(layers);
+ layerList.setLayerInset(0, table.mInset, table.mInset,
+ table.mInset, table.mInset);
+ image.setImageDrawable(layerList);
+
+ photo.setTag(R.id.photo_width, Integer.valueOf(photoWidth));
+ photo.setTag(R.id.photo_height, Integer.valueOf(photoHeight));
+
+ photo.setOnTouchListener(new PhotoTouchListener(table.getContext(),
+ table));
+ }
+ return photo;
+ }
+
+ private class LoadNaturalSiblingTask extends AsyncTask<View, Void, View> {
private final BitmapFactory.Options mOptions;
+ private final int mSlot;
- public PhotoLaunchTask () {
+ public LoadNaturalSiblingTask (int slot) {
mOptions = new BitmapFactory.Options();
mOptions.inTempStorage = new byte[32768];
+ mSlot = slot;
}
@Override
- public View doInBackground(Void... unused) {
- log("load a new photo");
+ public View doInBackground(View... views) {
+ log("load natural %s", (mSlot == NEXT ? "next" : "previous"));
final PhotoTable table = PhotoTable.this;
+ final Bitmap current = getBitmap(views[0]);
+ Bitmap decodedPhoto;
+ if (mSlot == NEXT) {
+ decodedPhoto = table.mPhotoSource.naturalNext(current,
+ mOptions, table.mLongSide, table.mShortSide);
+ } else {
+ decodedPhoto = table.mPhotoSource.naturalPrevious(current,
+ mOptions, table.mLongSide, table.mShortSide);
+ }
+ return applyFrame(PhotoTable.this, mOptions, decodedPhoto);
+ }
- LayoutInflater inflater = (LayoutInflater) table.getContext()
- .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- View photo = inflater.inflate(R.layout.photo, null);
- ImageView image = (ImageView) photo;
- Drawable[] layers = new Drawable[2];
- Bitmap decodedPhoto = table.mPhotoSource.next(mOptions,
- table.mLongSide, table.mShortSide);
- int photoWidth = mOptions.outWidth;
- int photoHeight = mOptions.outHeight;
- if (decodedPhoto == null || mOptions.outWidth <= 0 || mOptions.outHeight <= 0) {
- photo = null;
+ @Override
+ public void onPostExecute(View photo) {
+ if (photo != null) {
+ log("natural %s being rendered", (mSlot == NEXT ? "next" : "previous"));
+ PhotoTable.this.addView(photo, new LayoutParams(LayoutParams.WRAP_CONTENT,
+ LayoutParams.WRAP_CONTENT));
+ float width = (float) ((Integer) photo.getTag(R.id.photo_width)).intValue();
+ float height = (float) ((Integer) photo.getTag(R.id.photo_height)).intValue();
+ photo.setX(mSlot == PREV ? -2 * width : mWidth + 2 * width);
+ photo.setY((mHeight - height) / 2);
+ photo.addOnLayoutChangeListener(new OnLayoutChangeListener() {
+ @Override
+ public void onLayoutChange(View v, int left, int top, int right, int bottom,
+ int oldLeft, int oldTop, int oldRight, int oldBottom) {
+ PhotoTable.this.placeOnDeck(v, mSlot);
+ v.removeOnLayoutChangeListener(this);
+ }
+ });
} else {
- decodedPhoto.setHasMipMap(true);
- layers[0] = new BitmapDrawable(table.mResources, decodedPhoto);
- layers[1] = table.mResources.getDrawable(R.drawable.frame);
- LayerDrawable layerList = new LayerDrawable(layers);
- layerList.setLayerInset(0, table.mInset, table.mInset,
- table.mInset, table.mInset);
- image.setImageDrawable(layerList);
-
- photo.setTag(R.id.photo_width, new Integer(photoWidth));
- photo.setTag(R.id.photo_height, new Integer(photoHeight));
-
- photo.setOnTouchListener(new PhotoTouchListener(table.getContext(),
- table));
+ log("natural, %s was null!", (mSlot == NEXT ? "next" : "previous"));
}
+ }
+ };
+
+ private class PhotoLaunchTask extends AsyncTask<Void, Void, View> {
+ private final BitmapFactory.Options mOptions;
- return photo;
+ public PhotoLaunchTask () {
+ mOptions = new BitmapFactory.Options();
+ mOptions.inTempStorage = new byte[32768];
+ }
+
+ @Override
+ public View doInBackground(Void... unused) {
+ log("load a new photo");
+ final PhotoTable table = PhotoTable.this;
+ return applyFrame(PhotoTable.this, mOptions,
+ table.mPhotoSource.next(mOptions,
+ table.mLongSide, table.mShortSide));
}
@Override
@@ -465,12 +514,15 @@ public class PhotoTable extends FrameLayout {
final PhotoTable table = PhotoTable.this;
table.addView(photo, new LayoutParams(LayoutParams.WRAP_CONTENT,
- LayoutParams.WRAP_CONTENT));
+ LayoutParams.WRAP_CONTENT));
if (table.hasSelection()) {
- table.moveToTopOfPile(table.getSelected());
+ for (int slot = 0; slot < mOnDeck.length; slot++) {
+ if (mOnDeck[slot] != null) {
+ table.moveToTopOfPile(mOnDeck[slot]);
+ }
+ }
+ table.moveToTopOfPile(table.getSelection());
}
- int width = ((Integer) photo.getTag(R.id.photo_width)).intValue();
- int height = ((Integer) photo.getTag(R.id.photo_height)).intValue();
log("drop it");
table.throwOnTable(photo);
@@ -489,11 +541,12 @@ public class PhotoTable extends FrameLayout {
}
};
+ /** Bring a new photo onto the table. */
public void launch() {
log("launching");
- setSystemUiVisibility(View.STATUS_BAR_HIDDEN);
+ setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE);
if (hasSelection() &&
- (System.currentTimeMillis() - mSelectedTime) > MAX_SELECTION_TIME) {
+ (System.currentTimeMillis() - mSelectionTime) > MAX_SELECTION_TIME) {
clearSelection();
} else {
log("inflate it");
@@ -504,12 +557,11 @@ public class PhotoTable extends FrameLayout {
}
}
}
+
+ /** Dispose of the photo gracefully, in case we can see some of it. */
public void fadeAway(final View photo, final boolean replace) {
// fade out of view
mOnTable.remove(photo);
- if (photo == getFocused()) {
- clearFocus();
- }
photo.animate().cancel();
photo.animate()
.withLayer()
@@ -518,7 +570,9 @@ public class PhotoTable extends FrameLayout {
.withEndAction(new Runnable() {
@Override
public void run() {
- removeView(photo);
+ if (photo == getFocus()) {
+ clearFocus();
+ }
recycle(photo);
if (replace) {
scheduleNext(mNowDropDelay);
@@ -527,6 +581,7 @@ public class PhotoTable extends FrameLayout {
});
}
+ /** Visually on top, and also freshest, for the purposes of timeouts. */
public void moveToTopOfPile(View photo) {
// make this photo the last to be removed.
bringChildToFront(photo);
@@ -535,11 +590,53 @@ public class PhotoTable extends FrameLayout {
mOnTable.offer(photo);
}
+ /** On deck is to the left or right of the selected photo. */
+ private void placeOnDeck(final View photo, final int slot ) {
+ if (slot < mOnDeck.length) {
+ if (mOnDeck[slot] != null && mOnDeck[slot] != photo) {
+ fadeAway(mOnDeck[slot], false);
+ }
+ mOnDeck[slot] = photo;
+ float photoWidth = photo.getWidth();
+ float photoHeight = photo.getHeight();
+ float scale = Math.min(getHeight() / photoHeight, getWidth() / photoWidth);
+
+ float x = (getWidth() - photoWidth) / 2f;
+ float y = (getHeight() - photoHeight) / 2f;
+
+ View selected = getSelection();
+ float selectedWidth = selected.getWidth();
+ float selectedHeight = selected.getHeight();
+ float selectedScale = Math.min(getHeight() / photoHeight, getWidth() / photoWidth);
+
+ float offset = (((float) mWidth + scale * (photoWidth - 2f * mInset)) / 2f);
+ x += (slot == NEXT? 1f : -1f) * offset;
+
+ photo.animate()
+ .rotation(0f)
+ .rotationY(0f)
+ .scaleX(scale)
+ .scaleY(scale)
+ .x(x)
+ .y(y)
+ .setDuration(1000)
+ .setInterpolator(new DecelerateInterpolator(2f));
+ }
+ }
+
+ /** Move in response to touch. */
+ public void move(final View photo, float x, float y, float a) {
+ photo.animate().cancel();
+ photo.setAlpha(1f);
+ photo.setX((int) x);
+ photo.setY((int) y);
+ photo.setRotation((int) a);
+ }
+
+ /** Wind up off screen, so we can animate in. */
private void throwOnTable(final View photo) {
mOnTable.offer(photo);
log("start offscreen");
- int width = ((Integer) photo.getTag(R.id.photo_width));
- int height = ((Integer) photo.getTag(R.id.photo_height));
photo.setRotation(mThrowRotation);
photo.setX(-mLongSide);
photo.setY(-mLongSide);
@@ -560,6 +657,7 @@ public class PhotoTable extends FrameLayout {
}
}
+ /** Fling with no touch hints, then land off screen. */
public void fling(final View photo) {
final float[] o = { mWidth + mLongSide / 2f,
mHeight + mLongSide / 2f };
@@ -580,8 +678,9 @@ public class PhotoTable extends FrameLayout {
fling(photo, delta[0], delta[1], duration, true);
}
+ /** Continue dynamically after a fling gesture, possibly off the screen. */
public void fling(final View photo, float dx, float dy, int duration, boolean spin) {
- if (photo == getFocused()) {
+ if (photo == getFocus()) {
if (moveFocus(photo, 0f) == null) {
moveFocus(photo, 180f);
}
@@ -618,10 +717,12 @@ public class PhotoTable extends FrameLayout {
hit.right < 0f || hit.left > getWidth());
}
+ /** Animate to a random place and orientation, down on the table (visually small). */
public void dropOnTable(final View photo) {
dropOnTable(photo, mDropInterpolator);
}
+ /** Animate to a random place and orientation, down on the table (visually small). */
public void dropOnTable(final View photo, final Interpolator interpolator) {
float angle = randfrange(-mImageRotationLimit, mImageRotationLimit);
PointF p = randMultiDrop(sRNG.nextInt(),
@@ -630,16 +731,14 @@ public class PhotoTable extends FrameLayout {
float x = p.x;
float y = p.y;
- log("drop it at " + x + ", " + y);
+ log("drop it at %f, %f", x, y);
float x0 = photo.getX();
float y0 = photo.getY();
- float width = (float) ((Integer) photo.getTag(R.id.photo_width)).intValue();
- float height = (float) ((Integer) photo.getTag(R.id.photo_height)).intValue();
x -= mLongSide / 2f;
y -= mShortSide / 2f;
- log("fixed offset is " + x + ", " + y);
+ log("fixed offset is %f, %f ", x, y);
float dx = x - x0;
float dy = y - y0;
@@ -668,12 +767,14 @@ public class PhotoTable extends FrameLayout {
return result;
}
+ /** Animate the selected photo to the foregound: zooming in to bring it foreward. */
private void pickUp(final View photo) {
float photoWidth = photo.getWidth();
float photoHeight = photo.getHeight();
float scale = Math.min(getHeight() / photoHeight, getWidth() / photoWidth);
+ log("scale is %f", scale);
log("target it");
float x = (getWidth() - photoWidth) / 2f;
float y = (getHeight() - photoHeight) / 2f;
@@ -690,9 +791,10 @@ public class PhotoTable extends FrameLayout {
photo.setRotation(wrapAngle(photo.getRotation()));
log("animate it");
- // toss onto table
+ // lift up to the glass for a good look
photo.animate()
.rotation(0f)
+ .rotationY(0f)
.scaleX(scale)
.scaleY(scale)
.x(x)
@@ -702,16 +804,35 @@ public class PhotoTable extends FrameLayout {
.withEndAction(new Runnable() {
@Override
public void run() {
- log("endtimes: " + photo.getX());
+ log("endtimes: %f", photo.getX());
}
});
}
- private void recycle(View photo) {
+ private Bitmap getBitmap(View photo) {
+ if (photo == null) {
+ return null;
+ }
ImageView image = (ImageView) photo;
LayerDrawable layers = (LayerDrawable) image.getDrawable();
+ if (layers == null) {
+ return null;
+ }
BitmapDrawable bitmap = (BitmapDrawable) layers.getDrawable(0);
- bitmap.getBitmap().recycle();
+ if (bitmap == null) {
+ return null;
+ }
+ return bitmap.getBitmap();
+ }
+
+ private void recycle(View photo) {
+ if (photo != null) {
+ removeView(photo);
+ Bitmap bitmap = getBitmap(photo);
+ if (bitmap != null) {
+ bitmap.recycle();
+ }
+ }
}
public void setHighlight(View photo, boolean highlighted) {
@@ -724,6 +845,7 @@ public class PhotoTable extends FrameLayout {
}
}
+ /** Schedule the first launch. Idempotent. */
public void start() {
if (!mStarted) {
log("kick it");
@@ -747,9 +869,11 @@ public class PhotoTable extends FrameLayout {
postDelayed(mLauncher, delay);
}
- private static void log(String message) {
+ private static void log(String message, Object... args) {
if (DEBUG) {
- Log.i(TAG, message);
+ Formatter formatter = new Formatter();
+ formatter.format(message, args);
+ Log.i(TAG, formatter.toString());
}
}
}