1c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren/* 2c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren * Copyright (C) 2012 The Android Open Source Project 3c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren * 4c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren * Licensed under the Apache License, Version 2.0 (the "License"); 5c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren * you may not use this file except in compliance with the License. 6c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren * You may obtain a copy of the License at 7c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren * 8c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren * http://www.apache.org/licenses/LICENSE-2.0 9c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren * 10c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren * Unless required by applicable law or agreed to in writing, software 11c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren * distributed under the License is distributed on an "AS IS" BASIS, 12c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren * See the License for the specific language governing permissions and 14c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren * limitations under the License. 15c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren */ 16c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wrenpackage com.android.dreams.phototable; 17c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren 181c1faec579b96aeac7416a80a7ee7155a813fffeDianne Hackbornimport android.service.dreams.DreamService; 19d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wrenimport android.content.Context; 20d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wrenimport android.content.SharedPreferences; 21d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wrenimport android.content.res.Resources; 22d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wrenimport android.graphics.Bitmap; 23d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wrenimport android.graphics.BitmapFactory; 24d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wrenimport android.graphics.PointF; 25d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wrenimport android.graphics.drawable.BitmapDrawable; 26d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wrenimport android.graphics.drawable.Drawable; 27d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wrenimport android.graphics.drawable.LayerDrawable; 28d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wrenimport android.os.AsyncTask; 29d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wrenimport android.util.AttributeSet; 30d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wrenimport android.util.Log; 31d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wrenimport android.view.LayoutInflater; 32d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wrenimport android.view.MotionEvent; 33d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wrenimport android.view.View; 34d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wrenimport android.view.animation.DecelerateInterpolator; 3576086400f8e68b810bf1b3db0dc4f7133c8644aeChris Wrenimport android.view.animation.Interpolator; 36d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wrenimport android.widget.FrameLayout; 37d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wrenimport android.widget.FrameLayout.LayoutParams; 38d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wrenimport android.widget.ImageView; 39d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 40d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wrenimport java.util.LinkedList; 41d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wrenimport java.util.Random; 42c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren 43c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren/** 44d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren * A surface where photos sit. 45c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren */ 46d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wrenpublic class PhotoTable extends FrameLayout { 47c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren private static final String TAG = "PhotoTable"; 48d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren private static final boolean DEBUG = false; 49d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 50d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren class Launcher implements Runnable { 51d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren private final PhotoTable mTable; 52d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren public Launcher(PhotoTable table) { 53d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren mTable = table; 54d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } 55d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 56d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren @Override 57d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren public void run() { 58d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren mTable.scheduleNext(mDropPeriod); 59d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren mTable.launch(); 60d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } 61d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } 62d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 63d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren private static final long MAX_SELECTION_TIME = 10000L; 64d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren private static Random sRNG = new Random(); 65d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 66d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren private final Launcher mLauncher; 67d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren private final LinkedList<View> mOnTable; 68d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren private final int mDropPeriod; 69d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren private final int mFastDropPeriod; 70d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren private final int mNowDropDelay; 71d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren private final float mImageRatio; 72d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren private final float mTableRatio; 73d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren private final float mImageRotationLimit; 7476086400f8e68b810bf1b3db0dc4f7133c8644aeChris Wren private final float mThrowRotation; 7576086400f8e68b810bf1b3db0dc4f7133c8644aeChris Wren private final float mThrowSpeed; 76d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren private final boolean mTapToExit; 77d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren private final int mTableCapacity; 78f98687b22f4091083287ab7de7a0f3102bd9c1baChris Wren private final int mRedealCount; 79d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren private final int mInset; 80d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren private final PhotoSourcePlexor mPhotoSource; 81d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren private final Resources mResources; 8276086400f8e68b810bf1b3db0dc4f7133c8644aeChris Wren private final Interpolator mThrowInterpolator; 8376086400f8e68b810bf1b3db0dc4f7133c8644aeChris Wren private final Interpolator mDropInterpolator; 841c1faec579b96aeac7416a80a7ee7155a813fffeDianne Hackborn private DreamService mDream; 85d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren private PhotoLaunchTask mPhotoLaunchTask; 86d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren private boolean mStarted; 87d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren private boolean mIsLandscape; 88d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren private int mLongSide; 89d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren private int mShortSide; 90d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren private int mWidth; 91d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren private int mHeight; 92d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren private View mSelected; 93d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren private long mSelectedTime; 94d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 95651ee92128e1899957758abeeb1c2c669f240093Chris Wren public PhotoTable(Context context, AttributeSet as) { 96651ee92128e1899957758abeeb1c2c669f240093Chris Wren super(context, as); 97d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren mResources = getResources(); 98d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren mInset = mResources.getDimensionPixelSize(R.dimen.photo_inset); 9970ef3e7da59212c3c4baedf92f418eb9012a4db3Chris Wren mDropPeriod = mResources.getInteger(R.integer.table_drop_period); 100d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren mFastDropPeriod = mResources.getInteger(R.integer.fast_drop); 101d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren mNowDropDelay = mResources.getInteger(R.integer.now_drop); 102d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren mImageRatio = mResources.getInteger(R.integer.image_ratio) / 1000000f; 103d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren mTableRatio = mResources.getInteger(R.integer.table_ratio) / 1000000f; 104d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren mImageRotationLimit = (float) mResources.getInteger(R.integer.max_image_rotation); 10576086400f8e68b810bf1b3db0dc4f7133c8644aeChris Wren mThrowSpeed = mResources.getDimension(R.dimen.image_throw_speed); 10676086400f8e68b810bf1b3db0dc4f7133c8644aeChris Wren mThrowRotation = (float) mResources.getInteger(R.integer.image_throw_rotatioan); 107d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren mTableCapacity = mResources.getInteger(R.integer.table_capacity); 108f98687b22f4091083287ab7de7a0f3102bd9c1baChris Wren mRedealCount = mResources.getInteger(R.integer.redeal_count); 109d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren mTapToExit = mResources.getBoolean(R.bool.enable_tap_to_exit); 11076086400f8e68b810bf1b3db0dc4f7133c8644aeChris Wren mThrowInterpolator = new SoftLandingInterpolator( 11176086400f8e68b810bf1b3db0dc4f7133c8644aeChris Wren mResources.getInteger(R.integer.soft_landing_time) / 1000000f, 11276086400f8e68b810bf1b3db0dc4f7133c8644aeChris Wren mResources.getInteger(R.integer.soft_landing_distance) / 1000000f); 11376086400f8e68b810bf1b3db0dc4f7133c8644aeChris Wren mDropInterpolator = new DecelerateInterpolator( 11476086400f8e68b810bf1b3db0dc4f7133c8644aeChris Wren (float) mResources.getInteger(R.integer.drop_deceleration_exponent)); 115d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren mOnTable = new LinkedList<View>(); 116d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren mPhotoSource = new PhotoSourcePlexor(getContext(), 117d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren getContext().getSharedPreferences(PhotoTableDreamSettings.PREFS_NAME, 0)); 118d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren mLauncher = new Launcher(this); 119d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren mStarted = false; 120d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } 121d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 122651ee92128e1899957758abeeb1c2c669f240093Chris Wren 1231c1faec579b96aeac7416a80a7ee7155a813fffeDianne Hackborn public void setDream(DreamService dream) { 124651ee92128e1899957758abeeb1c2c669f240093Chris Wren mDream = dream; 125651ee92128e1899957758abeeb1c2c669f240093Chris Wren } 126651ee92128e1899957758abeeb1c2c669f240093Chris Wren 127d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren public boolean hasSelection() { 128d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren return mSelected != null; 129d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } 130d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 131d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren public View getSelected() { 132d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren return mSelected; 133d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } 134d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 135d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren public void clearSelection() { 136d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren mSelected = null; 137d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } 138d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 139d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren public void setSelection(View selected) { 140d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren assert(selected != null); 141d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren if (mSelected != null) { 142d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren dropOnTable(mSelected); 143d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } 144d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren mSelected = selected; 145d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren mSelectedTime = System.currentTimeMillis(); 146d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren bringChildToFront(selected); 147d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren pickUp(selected); 148d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } 149d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 150d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren static float lerp(float a, float b, float f) { 151d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren return (b-a)*f + a; 152d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } 153d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 154d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren static float randfrange(float a, float b) { 155d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren return lerp(a, b, sRNG.nextFloat()); 156d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } 157d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 158d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren static PointF randFromCurve(float t, PointF[] v) { 159d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren PointF p = new PointF(); 160d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren if (v.length == 4 && t >= 0f && t <= 1f) { 161d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren float a = (float) Math.pow(1f-t, 3f); 162d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren float b = (float) Math.pow(1f-t, 2f) * t; 163d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren float c = (1f-t) * (float) Math.pow(t, 2f); 164d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren float d = (float) Math.pow(t, 3f); 165d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 166d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren p.x = a * v[0].x + 3 * b * v[1].x + 3 * c * v[2].x + d * v[3].x; 167d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren p.y = a * v[0].y + 3 * b * v[1].y + 3 * c * v[2].y + d * v[3].y; 168d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } 169d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren return p; 170d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } 171d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 172d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren private static PointF randInCenter(float i, float j, int width, int height) { 173d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren log("randInCenter (" + i + ", " + j + ", " + width + ", " + height + ")"); 174d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren PointF p = new PointF(); 175d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren p.x = 0.5f * width + 0.15f * width * i; 176d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren p.y = 0.5f * height + 0.15f * height * j; 177d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren log("randInCenter returning " + p.x + "," + p.y); 178d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren return p; 179d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } 180d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 181f40bfb6272ceec0f3ec471495a8e1b739c5b9d4fChris Wren private static PointF randMultiDrop(int n, float i, float j, int width, int height) { 182f40bfb6272ceec0f3ec471495a8e1b739c5b9d4fChris Wren log("randMultiDrop (" + n + "," + i + ", " + j + ", " + width + ", " + height + ")"); 183f40bfb6272ceec0f3ec471495a8e1b739c5b9d4fChris Wren final float[] cx = {0.3f, 0.3f, 0.5f, 0.7f, 0.7f}; 184f40bfb6272ceec0f3ec471495a8e1b739c5b9d4fChris Wren final float[] cy = {0.3f, 0.7f, 0.5f, 0.3f, 0.7f}; 185f40bfb6272ceec0f3ec471495a8e1b739c5b9d4fChris Wren n = Math.abs(n); 186f40bfb6272ceec0f3ec471495a8e1b739c5b9d4fChris Wren float x = cx[n % cx.length]; 187f40bfb6272ceec0f3ec471495a8e1b739c5b9d4fChris Wren float y = cy[n % cx.length]; 188f40bfb6272ceec0f3ec471495a8e1b739c5b9d4fChris Wren PointF p = new PointF(); 189f40bfb6272ceec0f3ec471495a8e1b739c5b9d4fChris Wren p.x = x * width + 0.05f * width * i; 190f40bfb6272ceec0f3ec471495a8e1b739c5b9d4fChris Wren p.y = y * height + 0.05f * height * j; 191f40bfb6272ceec0f3ec471495a8e1b739c5b9d4fChris Wren log("randInCenter returning " + p.x + "," + p.y); 192f40bfb6272ceec0f3ec471495a8e1b739c5b9d4fChris Wren return p; 193f40bfb6272ceec0f3ec471495a8e1b739c5b9d4fChris Wren } 194f40bfb6272ceec0f3ec471495a8e1b739c5b9d4fChris Wren 195d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren @Override 196d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren public boolean onTouchEvent(MotionEvent event) { 197d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { 198d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren if (hasSelection()) { 199d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren dropOnTable(getSelected()); 200d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren clearSelection(); 201d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } else { 202651ee92128e1899957758abeeb1c2c669f240093Chris Wren if (mTapToExit && mDream != null) { 203d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren mDream.finish(); 204d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } 205d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } 206d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren return true; 207d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } 208d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren return false; 209d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } 210c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren 211c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren @Override 212d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren public void onLayout(boolean changed, int left, int top, int right, int bottom) { 213d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren super.onLayout(changed, left, top, right, bottom); 214d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren log("onLayout (" + left + ", " + top + ", " + right + ", " + bottom + ")"); 215d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 216d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren mHeight = bottom - top; 217d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren mWidth = right - left; 218d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 219d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren mLongSide = (int) (mImageRatio * Math.max(mWidth, mHeight)); 220d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren mShortSide = (int) (mImageRatio * Math.min(mWidth, mHeight)); 221d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 222d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren boolean isLandscape = mWidth > mHeight; 223d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren if (mIsLandscape != isLandscape) { 224d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren for (View photo: mOnTable) { 225d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren if (photo == getSelected()) { 226d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren pickUp(photo); 227d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } else { 228d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren dropOnTable(photo); 229d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } 230d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } 231d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren mIsLandscape = isLandscape; 232d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } 233d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren start(); 234c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren } 235c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren 236c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren @Override 237d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren public boolean isOpaque() { 238d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren return true; 239d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } 240d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 241d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren private class PhotoLaunchTask extends AsyncTask<Void, Void, View> { 242b6c75a5e1a9dfc7753a451e97607510d37264374Chris Wren private final BitmapFactory.Options mOptions; 243b6c75a5e1a9dfc7753a451e97607510d37264374Chris Wren 244b6c75a5e1a9dfc7753a451e97607510d37264374Chris Wren public PhotoLaunchTask () { 245b6c75a5e1a9dfc7753a451e97607510d37264374Chris Wren mOptions = new BitmapFactory.Options(); 246b6c75a5e1a9dfc7753a451e97607510d37264374Chris Wren mOptions.inTempStorage = new byte[32768]; 247b6c75a5e1a9dfc7753a451e97607510d37264374Chris Wren } 248b6c75a5e1a9dfc7753a451e97607510d37264374Chris Wren 249d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren @Override 250d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren public View doInBackground(Void... unused) { 251d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren log("load a new photo"); 252d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren final PhotoTable table = PhotoTable.this; 253d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 254d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren LayoutInflater inflater = (LayoutInflater) table.getContext() 255d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren .getSystemService(Context.LAYOUT_INFLATER_SERVICE); 256d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren View photo = inflater.inflate(R.layout.photo, null); 257d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren ImageView image = (ImageView) photo; 258d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren Drawable[] layers = new Drawable[2]; 259b6c75a5e1a9dfc7753a451e97607510d37264374Chris Wren Bitmap decodedPhoto = table.mPhotoSource.next(mOptions, 260d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren table.mLongSide, table.mShortSide); 261b6c75a5e1a9dfc7753a451e97607510d37264374Chris Wren int photoWidth = mOptions.outWidth; 262b6c75a5e1a9dfc7753a451e97607510d37264374Chris Wren int photoHeight = mOptions.outHeight; 263b6c75a5e1a9dfc7753a451e97607510d37264374Chris Wren if (mOptions.outWidth <= 0 || mOptions.outHeight <= 0) { 264d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren photo = null; 265d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } else { 266f64bb8f6838663783d55d07cee20f96b93aa5b42Romain Guy decodedPhoto.setHasMipMap(true); 267d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren layers[0] = new BitmapDrawable(table.mResources, decodedPhoto); 268d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren layers[1] = table.mResources.getDrawable(R.drawable.frame); 269d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren LayerDrawable layerList = new LayerDrawable(layers); 270d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren layerList.setLayerInset(0, table.mInset, table.mInset, 271d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren table.mInset, table.mInset); 272d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren image.setImageDrawable(layerList); 273d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 274d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren photo.setTag(R.id.photo_width, new Integer(photoWidth)); 275d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren photo.setTag(R.id.photo_height, new Integer(photoHeight)); 276d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 277d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren photo.setOnTouchListener(new PhotoTouchListener(table.getContext(), 278d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren table)); 279d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } 280d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 281d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren return photo; 282d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } 283d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 284d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren @Override 285d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren public void onPostExecute(View photo) { 286d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren if (photo != null) { 287d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren final PhotoTable table = PhotoTable.this; 288d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 289d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren table.addView(photo, new LayoutParams(LayoutParams.WRAP_CONTENT, 290d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren LayoutParams.WRAP_CONTENT)); 291d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren if (table.hasSelection()) { 292d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren table.bringChildToFront(table.getSelected()); 293d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } 294d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren int width = ((Integer) photo.getTag(R.id.photo_width)).intValue(); 295d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren int height = ((Integer) photo.getTag(R.id.photo_height)).intValue(); 296d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 297d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren log("drop it"); 298d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren table.throwOnTable(photo); 299d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 300d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren if(table.mOnTable.size() < table.mTableCapacity) { 301d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren table.scheduleNext(table.mFastDropPeriod); 302d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } 303d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } 304d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } 305d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren }; 306d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 307d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren public void launch() { 308d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren log("launching"); 309d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren setSystemUiVisibility(View.STATUS_BAR_HIDDEN); 310d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren if (hasSelection() && 311d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren (System.currentTimeMillis() - mSelectedTime) > MAX_SELECTION_TIME) { 312d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren dropOnTable(getSelected()); 313d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren clearSelection(); 314d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } else { 315d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren log("inflate it"); 316d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren if (mPhotoLaunchTask == null || 317d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren mPhotoLaunchTask.getStatus() == AsyncTask.Status.FINISHED) { 318d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren mPhotoLaunchTask = new PhotoLaunchTask(); 319d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren mPhotoLaunchTask.execute(); 320d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } 321d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } 322d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } 323d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren public void fadeAway(final View photo, final boolean replace) { 324d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren // fade out of view 325d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren mOnTable.remove(photo); 326d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren photo.animate().cancel(); 327d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren photo.animate() 328d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren .withLayer() 329d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren .alpha(0f) 330d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren .setDuration(1000) 331d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren .withEndAction(new Runnable() { 332d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren @Override 333d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren public void run() { 334d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren removeView(photo); 335d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren recycle(photo); 336d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren if (replace) { 337d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren scheduleNext(mNowDropDelay); 338d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } 339d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } 340d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren }); 341d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } 342d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 343d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren public void moveToBackOfQueue(View photo) { 344d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren // make this photo the last to be removed. 345d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren bringChildToFront(photo); 346d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren invalidate(); 347d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren mOnTable.remove(photo); 348d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren mOnTable.offer(photo); 349d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } 350d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 351d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren private void throwOnTable(final View photo) { 352d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren mOnTable.offer(photo); 353d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren log("start offscreen"); 354d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren int width = ((Integer) photo.getTag(R.id.photo_width)); 355d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren int height = ((Integer) photo.getTag(R.id.photo_height)); 35676086400f8e68b810bf1b3db0dc4f7133c8644aeChris Wren photo.setRotation(mThrowRotation); 357d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren photo.setX(-mLongSide); 358d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren photo.setY(-mLongSide); 35976086400f8e68b810bf1b3db0dc4f7133c8644aeChris Wren 36076086400f8e68b810bf1b3db0dc4f7133c8644aeChris Wren dropOnTable(photo, mThrowInterpolator); 361d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } 362d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 363d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren public void dropOnTable(final View photo) { 36476086400f8e68b810bf1b3db0dc4f7133c8644aeChris Wren dropOnTable(photo, mDropInterpolator); 36576086400f8e68b810bf1b3db0dc4f7133c8644aeChris Wren } 36676086400f8e68b810bf1b3db0dc4f7133c8644aeChris Wren 36776086400f8e68b810bf1b3db0dc4f7133c8644aeChris Wren public void dropOnTable(final View photo, final Interpolator interpolator) { 368d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren float angle = randfrange(-mImageRotationLimit, mImageRotationLimit); 369f40bfb6272ceec0f3ec471495a8e1b739c5b9d4fChris Wren PointF p = randMultiDrop(sRNG.nextInt(), 370f40bfb6272ceec0f3ec471495a8e1b739c5b9d4fChris Wren (float) sRNG.nextGaussian(), (float) sRNG.nextGaussian(), 371f40bfb6272ceec0f3ec471495a8e1b739c5b9d4fChris Wren mWidth, mHeight); 372d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren float x = p.x; 373d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren float y = p.y; 374d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 375d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren log("drop it at " + x + ", " + y); 376d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 377d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren float x0 = photo.getX(); 378d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren float y0 = photo.getY(); 379d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren float width = (float) ((Integer) photo.getTag(R.id.photo_width)).intValue(); 380d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren float height = (float) ((Integer) photo.getTag(R.id.photo_height)).intValue(); 381d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 382f40bfb6272ceec0f3ec471495a8e1b739c5b9d4fChris Wren x -= mLongSide / 2f; 383f40bfb6272ceec0f3ec471495a8e1b739c5b9d4fChris Wren y -= mShortSide / 2f; 384d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren log("fixed offset is " + x + ", " + y); 385d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 386d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren float dx = x - x0; 387d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren float dy = y - y0; 388d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 389d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren float dist = (float) (Math.sqrt(dx * dx + dy * dy)); 39076086400f8e68b810bf1b3db0dc4f7133c8644aeChris Wren int duration = (int) (1000f * dist / mThrowSpeed); 391d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren duration = Math.max(duration, 1000); 392d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 393d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren log("animate it"); 394d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren // toss onto table 395d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren photo.animate() 396d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren .scaleX(mTableRatio / mImageRatio) 397d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren .scaleY(mTableRatio / mImageRatio) 398d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren .rotation(angle) 399d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren .x(x) 400d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren .y(y) 401d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren .setDuration(duration) 40276086400f8e68b810bf1b3db0dc4f7133c8644aeChris Wren .setInterpolator(interpolator) 403d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren .withEndAction(new Runnable() { 404d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren @Override 405d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren public void run() { 406f98687b22f4091083287ab7de7a0f3102bd9c1baChris Wren if (mOnTable.size() > mTableCapacity) { 407f98687b22f4091083287ab7de7a0f3102bd9c1baChris Wren while (mOnTable.size() > (mTableCapacity - mRedealCount)) { 408f98687b22f4091083287ab7de7a0f3102bd9c1baChris Wren fadeAway(mOnTable.poll(), false); 409f98687b22f4091083287ab7de7a0f3102bd9c1baChris Wren } 410f98687b22f4091083287ab7de7a0f3102bd9c1baChris Wren // zero delay because we already waited duration ms 411f98687b22f4091083287ab7de7a0f3102bd9c1baChris Wren scheduleNext(0); 412d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } 413d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } 414d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren }); 415d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } 416d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 417d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren /** wrap all orientations to the interval [-180, 180). */ 418d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren private float wrapAngle(float angle) { 419d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren float result = angle + 180; 420d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren result = ((result % 360) + 360) % 360; // catch negative numbers 421d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren result -= 180; 422d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren return result; 423d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } 424d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 425d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren private void pickUp(final View photo) { 426d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren float photoWidth = photo.getWidth(); 427d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren float photoHeight = photo.getHeight(); 428d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 429d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren float scale = Math.min(getHeight() / photoHeight, getWidth() / photoWidth); 430d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 431d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren log("target it"); 432d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren float x = (getWidth() - photoWidth) / 2f; 433d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren float y = (getHeight() - photoHeight) / 2f; 434d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 435d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren float x0 = photo.getX(); 436d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren float y0 = photo.getY(); 437d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren float dx = x - x0; 438d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren float dy = y - y0; 439d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 440d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren float dist = (float) (Math.sqrt(dx * dx + dy * dy)); 44176086400f8e68b810bf1b3db0dc4f7133c8644aeChris Wren int duration = (int) (1000f * dist / 600f); 442d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren duration = Math.max(duration, 500); 443d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 444d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren photo.setRotation(wrapAngle(photo.getRotation())); 445d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 446d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren log("animate it"); 447d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren // toss onto table 448d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren photo.animate() 449d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren .rotation(0f) 450d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren .scaleX(scale) 451d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren .scaleY(scale) 452d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren .x(x) 453d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren .y(y) 454d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren .setDuration(duration) 455d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren .setInterpolator(new DecelerateInterpolator(2f)) 456d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren .withEndAction(new Runnable() { 457d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren @Override 458d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren public void run() { 459d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren log("endtimes: " + photo.getX()); 460d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } 461d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren }); 462d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } 463d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 464d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren private void recycle(View photo) { 465d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren ImageView image = (ImageView) photo; 466d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren LayerDrawable layers = (LayerDrawable) image.getDrawable(); 467d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren BitmapDrawable bitmap = (BitmapDrawable) layers.getDrawable(0); 468d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren bitmap.getBitmap().recycle(); 469d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } 470d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 471d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren public void start() { 472d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren if (!mStarted) { 473d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren log("kick it"); 474d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren mStarted = true; 475d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren scheduleNext(mDropPeriod); 476d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren launch(); 477d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } 478d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } 479d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 480d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren public void scheduleNext(int delay) { 481d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren removeCallbacks(mLauncher); 482d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren postDelayed(mLauncher, delay); 483d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } 484d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren 485d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren private static void log(String message) { 486d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren if (DEBUG) { 487d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren Log.i(TAG, message); 488d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren } 489c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren } 490c8ca07eb52a54efe327d024dc542e0a7f8849bfbChris Wren} 491