18475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler/*
28475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler * Copyright (C) 2013 The Android Open Source Project
38475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler *
48475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler * Licensed under the Apache License, Version 2.0 (the "License");
58475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler * you may not use this file except in compliance with the License.
68475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler * You may obtain a copy of the License at
78475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler *
88475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler *      http://www.apache.org/licenses/LICENSE-2.0
98475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler *
108475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler * Unless required by applicable law or agreed to in writing, software
118475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler * distributed under the License is distributed on an "AS IS" BASIS,
128475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
138475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler * See the License for the specific language governing permissions and
148475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler * limitations under the License.
158475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler */
168475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
178475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandlerpackage com.android.systemui;
188475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
198475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandlerimport android.animation.Animator;
209279d45b8d26c88c69fa917816ea396142627020Daniel Sandlerimport android.animation.AnimatorListenerAdapter;
218475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandlerimport android.animation.AnimatorSet;
228475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandlerimport android.animation.ObjectAnimator;
238475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandlerimport android.content.Context;
248475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandlerimport android.content.res.Resources;
258475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandlerimport android.graphics.*;
268475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandlerimport android.graphics.drawable.BitmapDrawable;
278475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandlerimport android.graphics.drawable.Drawable;
288475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandlerimport android.os.Handler;
298475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandlerimport android.util.AttributeSet;
308475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandlerimport android.util.Log;
318475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandlerimport android.util.SparseArray;
328475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandlerimport android.view.View;
338475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandlerimport android.view.animation.AccelerateInterpolator;
348475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandlerimport android.view.animation.AnticipateOvershootInterpolator;
358475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandlerimport android.view.animation.DecelerateInterpolator;
368475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandlerimport android.widget.FrameLayout;
378475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandlerimport android.widget.ImageView;
388475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
398475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandlerimport java.util.HashSet;
408475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandlerimport java.util.Set;
418475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
428475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandlerpublic class DessertCaseView extends FrameLayout {
438475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    private static final String TAG = DessertCaseView.class.getSimpleName();
448475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
458475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    private static final boolean DEBUG = false;
468475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
478475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    static final int START_DELAY = 5000;
488475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    static final int DELAY = 2000;
498475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    static final int DURATION = 500;
508475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
518475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    private static final int TAG_POS = 0x2000001;
528475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    private static final int TAG_SPAN = 0x2000002;
538475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
548475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    private static final int[] PASTRIES = {
558475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            R.drawable.dessert_kitkat,      // used with permission
568475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            R.drawable.dessert_android,     // thx irina
578475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    };
588475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
598475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    private static final int[] RARE_PASTRIES = {
608475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            R.drawable.dessert_cupcake,     // 2009
618475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            R.drawable.dessert_donut,       // 2009
628475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            R.drawable.dessert_eclair,      // 2009
638475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            R.drawable.dessert_froyo,       // 2010
648475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            R.drawable.dessert_gingerbread, // 2010
658475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            R.drawable.dessert_honeycomb,   // 2011
668475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            R.drawable.dessert_ics,         // 2011
678475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            R.drawable.dessert_jellybean,   // 2012
688475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    };
698475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
708475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    private static final int[] XRARE_PASTRIES = {
718475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            R.drawable.dessert_petitfour,   // the original and still delicious
728475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
738475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            R.drawable.dessert_donutburger, // remember kids, this was long before cronuts
748475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
758475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            R.drawable.dessert_flan,        //     sholes final approach
768475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                                            //     landing gear punted to flan
778475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                                            //     runway foam glistens
788475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                                            //         -- mcleron
798475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
808475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            R.drawable.dessert_keylimepie,  // from an alternative timeline
818475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    };
828475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    private static final int[] XXRARE_PASTRIES = {
838475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            R.drawable.dessert_zombiegingerbread, // thx hackbod
848475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            R.drawable.dessert_dandroid,    // thx morrildl
858475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            R.drawable.dessert_jandycane,   // thx nes
868475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    };
878475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
888475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    private static final int NUM_PASTRIES = PASTRIES.length + RARE_PASTRIES.length
898475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            + XRARE_PASTRIES.length + XXRARE_PASTRIES.length;
908475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
918475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    private SparseArray<Drawable> mDrawables = new SparseArray<Drawable>(NUM_PASTRIES);
928475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
938475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    private static final float[] MASK = {
948475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            0f,  0f,  0f,  0f, 255f,
958475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            0f,  0f,  0f,  0f, 255f,
968475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            0f,  0f,  0f,  0f, 255f,
978475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            1f,  0f,  0f,  0f, 0f
988475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    };
998475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
100f9f63355e3f05186a3652c0ef3f0039ed97db918Daniel Sandler    private static final float[] ALPHA_MASK = {
101f9f63355e3f05186a3652c0ef3f0039ed97db918Daniel Sandler            0f,  0f,  0f,  0f, 255f,
102f9f63355e3f05186a3652c0ef3f0039ed97db918Daniel Sandler            0f,  0f,  0f,  0f, 255f,
103f9f63355e3f05186a3652c0ef3f0039ed97db918Daniel Sandler            0f,  0f,  0f,  0f, 255f,
104f9f63355e3f05186a3652c0ef3f0039ed97db918Daniel Sandler            0f,  0f,  0f,  1f, 0f
105f9f63355e3f05186a3652c0ef3f0039ed97db918Daniel Sandler    };
106f9f63355e3f05186a3652c0ef3f0039ed97db918Daniel Sandler
1078475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    private static final float[] WHITE_MASK = {
1088475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            0f,  0f,  0f,  0f, 255f,
1098475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            0f,  0f,  0f,  0f, 255f,
1108475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            0f,  0f,  0f,  0f, 255f,
1118475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            -1f,  0f,  0f,  0f, 255f
1128475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    };
1138475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
1148475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    public static final float SCALE = 0.25f; // natural display size will be SCALE*mCellSize
1158475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
1168475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    private static final float PROB_2X = 0.33f;
1178475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    private static final float PROB_3X = 0.1f;
1188475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    private static final float PROB_4X = 0.01f;
1198475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
1208475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    private boolean mStarted;
1218475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
1228475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    private int mCellSize;
1238475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    private int mWidth, mHeight;
1248475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    private int mRows, mColumns;
1258475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    private View[] mCells;
1268475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
1278475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    private final Set<Point> mFreeList = new HashSet<Point>();
1288475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
1298475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    private final Handler mHandler = new Handler();
1308475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
1318475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    private final Runnable mJuggle = new Runnable() {
1328475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        @Override
1338475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        public void run() {
1348475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            final int N = getChildCount();
1358475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
1368475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            final int K = 1; //irand(1,3);
1378475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            for (int i=0; i<K; i++) {
1388475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                final View child = getChildAt((int) (Math.random() * N));
1398475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                place(child, true);
1408475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            }
1418475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
1428475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            fillFreeList();
1438475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
1448475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            if (mStarted) {
1458475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                mHandler.postDelayed(mJuggle, DELAY);
1468475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            }
1478475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        }
1488475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    };
1498475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
1508475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    public DessertCaseView(Context context) {
1518475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        this(context, null);
1528475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    }
1538475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
1548475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    public DessertCaseView(Context context, AttributeSet attrs) {
1558475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        this(context, attrs, 0);
1568475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    }
1578475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
1588475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    public DessertCaseView(Context context, AttributeSet attrs, int defStyle) {
1598475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        super(context, attrs, defStyle);
1608475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
1618475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        final Resources res = getResources();
1628475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
1638475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        mStarted = false;
1648475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
1658475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        mCellSize = res.getDimensionPixelSize(R.dimen.dessert_case_cell_size);
1668475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        final BitmapFactory.Options opts = new BitmapFactory.Options();
1678475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        if (mCellSize < 512) { // assuming 512x512 images
1688475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            opts.inSampleSize = 2;
1698475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        }
1709279d45b8d26c88c69fa917816ea396142627020Daniel Sandler        opts.inMutable = true;
1719279d45b8d26c88c69fa917816ea396142627020Daniel Sandler        Bitmap loaded = null;
1728475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        for (int[] list : new int[][] { PASTRIES, RARE_PASTRIES, XRARE_PASTRIES, XXRARE_PASTRIES }) {
1738475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            for (int resid : list) {
1749279d45b8d26c88c69fa917816ea396142627020Daniel Sandler                opts.inBitmap = loaded;
1759279d45b8d26c88c69fa917816ea396142627020Daniel Sandler                loaded = BitmapFactory.decodeResource(res, resid, opts);
1769279d45b8d26c88c69fa917816ea396142627020Daniel Sandler                final BitmapDrawable d = new BitmapDrawable(res, convertToAlphaMask(loaded));
177f9f63355e3f05186a3652c0ef3f0039ed97db918Daniel Sandler                d.setColorFilter(new ColorMatrixColorFilter(ALPHA_MASK));
1788475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                d.setBounds(0, 0, mCellSize, mCellSize);
1798475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                mDrawables.append(resid, d);
1808475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            }
1818475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        }
1829279d45b8d26c88c69fa917816ea396142627020Daniel Sandler        loaded = null;
1838475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        if (DEBUG) setWillNotDraw(false);
1848475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    }
1858475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
186f9f63355e3f05186a3652c0ef3f0039ed97db918Daniel Sandler    private static Bitmap convertToAlphaMask(Bitmap b) {
187f9f63355e3f05186a3652c0ef3f0039ed97db918Daniel Sandler        Bitmap a = Bitmap.createBitmap(b.getWidth(), b.getHeight(), Bitmap.Config.ALPHA_8);
188f9f63355e3f05186a3652c0ef3f0039ed97db918Daniel Sandler        Canvas c = new Canvas(a);
189f9f63355e3f05186a3652c0ef3f0039ed97db918Daniel Sandler        Paint pt = new Paint();
190f9f63355e3f05186a3652c0ef3f0039ed97db918Daniel Sandler        pt.setColorFilter(new ColorMatrixColorFilter(MASK));
191f9f63355e3f05186a3652c0ef3f0039ed97db918Daniel Sandler        c.drawBitmap(b, 0.0f, 0.0f, pt);
192f9f63355e3f05186a3652c0ef3f0039ed97db918Daniel Sandler        return a;
193f9f63355e3f05186a3652c0ef3f0039ed97db918Daniel Sandler    }
194f9f63355e3f05186a3652c0ef3f0039ed97db918Daniel Sandler
1958475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    public void start() {
1968475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        if (!mStarted) {
1978475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            mStarted = true;
1988475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            fillFreeList(DURATION * 4);
1998475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        }
2008475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        mHandler.postDelayed(mJuggle, START_DELAY);
2018475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    }
2028475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
2038475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    public void stop() {
2048475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        mStarted = false;
2058475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        mHandler.removeCallbacks(mJuggle);
2068475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    }
2078475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
2088475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    int pick(int[] a) {
2098475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        return a[(int)(Math.random()*a.length)];
2108475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    }
2118475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
2128475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    <T> T pick(T[] a) {
2138475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        return a[(int)(Math.random()*a.length)];
2148475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    }
2158475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
2168475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    <T> T pick(SparseArray<T> sa) {
2178475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        return sa.valueAt((int)(Math.random()*sa.size()));
2188475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    }
2198475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
2208475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    float[] hsv = new float[] { 0, 1f, .85f };
2218475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    int random_color() {
2228475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler//        return 0xFF000000 | (int) (Math.random() * (float) 0xFFFFFF); // totally random
2238475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        final int COLORS = 12;
2248475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        hsv[0] = irand(0,COLORS) * (360f/COLORS);
2258475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        return Color.HSVToColor(hsv);
2268475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    }
2278475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
2288475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    @Override
2298475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    protected synchronized void onSizeChanged (int w, int h, int oldw, int oldh) {
2308475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        super.onSizeChanged(w, h, oldw, oldh);
2318475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        if (mWidth == w && mHeight == h) return;
2328475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
2338475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        final boolean wasStarted = mStarted;
2348475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        if (wasStarted) {
2358475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            stop();
2368475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        }
2378475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
2388475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        mWidth = w;
2398475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        mHeight = h;
2408475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
2418475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        mCells = null;
2428475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        removeAllViewsInLayout();
2438475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        mFreeList.clear();
2448475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
2458475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        mRows = mHeight / mCellSize;
2468475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        mColumns = mWidth / mCellSize;
2478475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
2488475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        mCells = new View[mRows * mColumns];
2498475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
2508475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        if (DEBUG) Log.v(TAG, String.format("New dimensions: %dx%d", mColumns, mRows));
2518475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
2528475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        setScaleX(SCALE);
2538475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        setScaleY(SCALE);
2548475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        setTranslationX(0.5f * (mWidth - mCellSize * mColumns) * SCALE);
2558475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        setTranslationY(0.5f * (mHeight - mCellSize * mRows) * SCALE);
2568475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
2578475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        for (int j=0; j<mRows; j++) {
2588475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            for (int i=0; i<mColumns; i++) {
2598475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                mFreeList.add(new Point(i,j));
2608475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            }
2618475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        }
2628475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
2638475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        if (wasStarted) {
2648475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            start();
2658475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        }
2668475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    }
2678475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
2688475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    public void fillFreeList() {
2698475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        fillFreeList(DURATION);
2708475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    }
2718475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
2728475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    public synchronized void fillFreeList(int animationLen) {
2738475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        final Context ctx = getContext();
2748475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        final FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(mCellSize, mCellSize);
2758475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
2768475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        while (! mFreeList.isEmpty()) {
2778475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            Point pt = mFreeList.iterator().next();
2788475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            mFreeList.remove(pt);
2798475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            final int i=pt.x;
2808475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            final int j=pt.y;
2818475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
2828475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            if (mCells[j*mColumns+i] != null) continue;
2838475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            final ImageView v = new ImageView(ctx);
2848475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            v.setOnClickListener(new OnClickListener() {
2858475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                @Override
2868475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                public void onClick(View view) {
2878475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                    place(v, true);
2888475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                    postDelayed(new Runnable() { public void run() { fillFreeList(); } }, DURATION/2);
2898475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                }
2908475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            });
2918475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
2928475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            final int c = random_color();
2938475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            v.setBackgroundColor(c);
2948475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
2958475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            final float which = frand();
2968475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            final Drawable d;
297f9f63355e3f05186a3652c0ef3f0039ed97db918Daniel Sandler            if (which < 0.0005f) {
2988475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                d = mDrawables.get(pick(XXRARE_PASTRIES));
299f9f63355e3f05186a3652c0ef3f0039ed97db918Daniel Sandler            } else if (which < 0.005f) {
3008475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                d = mDrawables.get(pick(XRARE_PASTRIES));
3018475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            } else if (which < 0.5f) {
3028475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                d = mDrawables.get(pick(RARE_PASTRIES));
3038475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            } else if (which < 0.7f) {
3048475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                d = mDrawables.get(pick(PASTRIES));
3058475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            } else {
3068475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                d = null;
3078475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            }
3088475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            if (d != null) {
3098475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                v.getOverlay().add(d);
3108475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            }
3118475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
3128475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            lp.width = lp.height = mCellSize;
3138475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            addView(v, lp);
3148475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            place(v, pt, false);
3158475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            if (animationLen > 0) {
3168475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                final float s = (Integer) v.getTag(TAG_SPAN);
3178475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                v.setScaleX(0.5f * s);
3188475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                v.setScaleY(0.5f * s);
3198475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                v.setAlpha(0f);
3209279d45b8d26c88c69fa917816ea396142627020Daniel Sandler                v.animate().withLayer().scaleX(s).scaleY(s).alpha(1f).setDuration(animationLen);
3218475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            }
3228475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        }
3238475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    }
3248475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
3258475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    public void place(View v, boolean animate) {
3268475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        place(v, new Point(irand(0, mColumns), irand(0, mRows)), animate);
3278475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    }
3288475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
3299279d45b8d26c88c69fa917816ea396142627020Daniel Sandler    // we don't have .withLayer() on general Animators
3309279d45b8d26c88c69fa917816ea396142627020Daniel Sandler    private final Animator.AnimatorListener makeHardwareLayerListener(final View v) {
3319279d45b8d26c88c69fa917816ea396142627020Daniel Sandler        return new AnimatorListenerAdapter() {
3329279d45b8d26c88c69fa917816ea396142627020Daniel Sandler            @Override
3339279d45b8d26c88c69fa917816ea396142627020Daniel Sandler            public void onAnimationStart(Animator animator) {
3349279d45b8d26c88c69fa917816ea396142627020Daniel Sandler                v.setLayerType(View.LAYER_TYPE_HARDWARE, null);
3359279d45b8d26c88c69fa917816ea396142627020Daniel Sandler                v.buildLayer();
3369279d45b8d26c88c69fa917816ea396142627020Daniel Sandler            }
3379279d45b8d26c88c69fa917816ea396142627020Daniel Sandler            @Override
3389279d45b8d26c88c69fa917816ea396142627020Daniel Sandler            public void onAnimationEnd(Animator animator) {
3399279d45b8d26c88c69fa917816ea396142627020Daniel Sandler                v.setLayerType(View.LAYER_TYPE_NONE, null);
3409279d45b8d26c88c69fa917816ea396142627020Daniel Sandler            }
3419279d45b8d26c88c69fa917816ea396142627020Daniel Sandler        };
3429279d45b8d26c88c69fa917816ea396142627020Daniel Sandler    }
3439279d45b8d26c88c69fa917816ea396142627020Daniel Sandler
3448475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    private final HashSet<View> tmpSet = new HashSet<View>();
3458475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    public synchronized void place(View v, Point pt, boolean animate) {
3468475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        final int i = pt.x;
3478475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        final int j = pt.y;
3488475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        final float rnd = frand();
3498475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        if (v.getTag(TAG_POS) != null) {
3508475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            for (final Point oc : getOccupied(v)) {
3518475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                mFreeList.add(oc);
3528475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                mCells[oc.y*mColumns + oc.x] = null;
3538475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            }
3548475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        }
3558475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        int scale = 1;
3568475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        if (rnd < PROB_4X) {
3578475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            if (!(i >= mColumns-3 || j >= mRows-3)) {
3588475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                scale = 4;
3598475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            }
3608475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        } else if (rnd < PROB_3X) {
3618475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            if (!(i >= mColumns-2 || j >= mRows-2)) {
3628475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                scale = 3;
3638475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            }
3648475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        } else if (rnd < PROB_2X) {
3658475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            if (!(i == mColumns-1 || j == mRows-1)) {
3668475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                scale = 2;
3678475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            }
3688475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        }
3698475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
3708475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        v.setTag(TAG_POS, pt);
3718475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        v.setTag(TAG_SPAN, scale);
3728475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
3738475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        tmpSet.clear();
3748475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
3758475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        final Point[] occupied = getOccupied(v);
3768475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        for (final Point oc : occupied) {
3778475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            final View squatter = mCells[oc.y*mColumns + oc.x];
3788475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            if (squatter != null) {
3798475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                tmpSet.add(squatter);
3808475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            }
3818475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        }
3828475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
3838475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        for (final View squatter : tmpSet) {
3848475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            for (final Point sq : getOccupied(squatter)) {
3858475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                mFreeList.add(sq);
3868475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                mCells[sq.y*mColumns + sq.x] = null;
3878475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            }
3888475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            if (squatter != v) {
3898475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                squatter.setTag(TAG_POS, null);
3908475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                if (animate) {
3919279d45b8d26c88c69fa917816ea396142627020Daniel Sandler                    squatter.animate().withLayer()
3929279d45b8d26c88c69fa917816ea396142627020Daniel Sandler                            .scaleX(0.5f).scaleY(0.5f).alpha(0)
3938475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                            .setDuration(DURATION)
3948475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                            .setInterpolator(new AccelerateInterpolator())
3958475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                            .setListener(new Animator.AnimatorListener() {
3968475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                                public void onAnimationStart(Animator animator) { }
3978475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                                public void onAnimationEnd(Animator animator) {
3988475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                                    removeView(squatter);
3998475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                                }
4008475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                                public void onAnimationCancel(Animator animator) { }
4018475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                                public void onAnimationRepeat(Animator animator) { }
4028475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                            })
4038475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                            .start();
4048475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                } else {
4058475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                    removeView(squatter);
4068475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                }
4078475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            }
4088475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        }
4098475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
4108475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        for (final Point oc : occupied) {
4118475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            mCells[oc.y*mColumns + oc.x] = v;
4128475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            mFreeList.remove(oc);
4138475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        }
4148475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
4158475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        final float rot = (float)irand(0, 4) * 90f;
4168475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
4178475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        if (animate) {
4188475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            v.bringToFront();
4199279d45b8d26c88c69fa917816ea396142627020Daniel Sandler
4208475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            AnimatorSet set1 = new AnimatorSet();
4218475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            set1.playTogether(
4228475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                    ObjectAnimator.ofFloat(v, View.SCALE_X, (float) scale),
4238475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                    ObjectAnimator.ofFloat(v, View.SCALE_Y, (float) scale)
4248475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            );
4258475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            set1.setInterpolator(new AnticipateOvershootInterpolator());
4268475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            set1.setDuration(DURATION);
4278475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
4288475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            AnimatorSet set2 = new AnimatorSet();
4298475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            set2.playTogether(
4308475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                    ObjectAnimator.ofFloat(v, View.ROTATION, rot),
4318475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                    ObjectAnimator.ofFloat(v, View.X, i* mCellSize + (scale-1) * mCellSize /2),
4328475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                    ObjectAnimator.ofFloat(v, View.Y, j* mCellSize + (scale-1) * mCellSize /2)
4338475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            );
4348475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            set2.setInterpolator(new DecelerateInterpolator());
4358475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            set2.setDuration(DURATION);
4369279d45b8d26c88c69fa917816ea396142627020Daniel Sandler
4379279d45b8d26c88c69fa917816ea396142627020Daniel Sandler            set1.addListener(makeHardwareLayerListener(v));
4389279d45b8d26c88c69fa917816ea396142627020Daniel Sandler
4399279d45b8d26c88c69fa917816ea396142627020Daniel Sandler            set1.start();
4408475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            set2.start();
4418475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        } else {
4428475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            v.setX(i * mCellSize + (scale-1) * mCellSize /2);
4438475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            v.setY(j * mCellSize + (scale-1) * mCellSize /2);
4448475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            v.setScaleX((float) scale);
4458475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            v.setScaleY((float) scale);
4468475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            v.setRotation(rot);
4478475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        }
4488475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    }
4498475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
4508475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    private Point[] getOccupied(View v) {
4518475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        final int scale = (Integer) v.getTag(TAG_SPAN);
4528475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        final Point pt = (Point)v.getTag(TAG_POS);
4538475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        if (pt == null || scale == 0) return new Point[0];
4548475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
4558475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        final Point[] result = new Point[scale * scale];
4568475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        int p=0;
4578475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        for (int i=0; i<scale; i++) {
4588475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            for (int j=0; j<scale; j++) {
4598475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                result[p++] = new Point(pt.x + i, pt.y + j);
4608475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            }
4618475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        }
4628475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        return result;
4638475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    }
4648475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
4658475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    static float frand() {
4668475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        return (float)(Math.random());
4678475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    }
4688475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
4698475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    static float frand(float a, float b) {
4708475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        return (frand() * (b-a) + a);
4718475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    }
4728475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
4738475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    static int irand(int a, int b) {
4748475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        return (int)(frand(a, b));
4758475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    }
4768475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
4778475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    @Override
4788475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    public void onDraw(Canvas c) {
4798475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        super.onDraw(c);
4808475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        if (!DEBUG) return;
4818475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
4828475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        Paint pt = new Paint();
4838475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        pt.setStyle(Paint.Style.STROKE);
4848475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        pt.setColor(0xFFCCCCCC);
4858475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        pt.setStrokeWidth(2.0f);
4868475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
4878475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        final Rect check = new Rect();
4888475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        final int N = getChildCount();
4898475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        for (int i = 0; i < N; i++) {
4908475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            View stone = getChildAt(i);
4918475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
4928475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            stone.getHitRect(check);
4938475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
4948475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            c.drawRect(check, pt);
4958475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        }
4968475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    }
4978475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
4988475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    public static class RescalingContainer extends FrameLayout {
4998475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        private DessertCaseView mView;
5008475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        private float mDarkness;
5018475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
5028475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        public RescalingContainer(Context context) {
5038475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            super(context);
5048475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
5058475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            setSystemUiVisibility(0
5068475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                    | View.SYSTEM_UI_FLAG_FULLSCREEN
5078475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                    | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
5088475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                    | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
5098475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler                    | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
5105c6a781eaf5eafd5f3bba46f1cfd7e53cd0428daDaniel Sandler                    | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
5118475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            );
5128475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        }
5138475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
5148475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        public void setView(DessertCaseView v) {
5158475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            addView(v);
5168475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            mView = v;
5178475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        }
5188475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
5198475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        @Override
5208475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        protected void onLayout (boolean changed, int left, int top, int right, int bottom) {
5218475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            final float w = right-left;
5228475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            final float h = bottom-top;
5238475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            final int w2 = (int) (w / mView.SCALE / 2);
5248475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            final int h2 = (int) (h / mView.SCALE / 2);
5258475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            final int cx = (int) (left + w * 0.5f);
5268475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            final int cy = (int) (top + h * 0.5f);
5278475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            mView.layout(cx - w2, cy - h2, cx + w2, cy + h2);
5288475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        }
5298475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
5308475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        public void setDarkness(float p) {
5318475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            mDarkness = p;
5328475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            getDarkness();
5338475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            final int x = (int) (p * 0xff);
5348475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            setBackgroundColor(x << 24 & 0xFF000000);
5358475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        }
5368475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler
5378475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        public float getDarkness() {
5388475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler            return mDarkness;
5398475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler        }
5408475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler    }
5418475a74bdd9d6e1520fe66cdffb7b07c19c736e0Daniel Sandler}
542