diff options
author | Daniel Sandler <dsandler@android.com> | 2013-09-27 03:10:37 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2013-09-27 03:10:38 +0000 |
commit | a9cf1de470db5910a38f733f4cd089a44d3162c5 (patch) | |
tree | 47185669eac5f349c9abf2b0d9d71c379bcffbf2 /packages/SystemUI/src | |
parent | 10d655927c5c10af0561ecc0961f9a9fcbad89f0 (diff) | |
parent | 8475a74bdd9d6e1520fe66cdffb7b07c19c736e0 (diff) | |
download | frameworks_base-a9cf1de470db5910a38f733f4cd089a44d3162c5.zip frameworks_base-a9cf1de470db5910a38f733f4cd089a44d3162c5.tar.gz frameworks_base-a9cf1de470db5910a38f733f4cd089a44d3162c5.tar.bz2 |
Merge "Would you like a dessert?" into klp-dev
Diffstat (limited to 'packages/SystemUI/src')
3 files changed, 555 insertions, 6 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/DessertCase.java b/packages/SystemUI/src/com/android/systemui/DessertCase.java index b6424af0..dd4c018 100644 --- a/packages/SystemUI/src/com/android/systemui/DessertCase.java +++ b/packages/SystemUI/src/com/android/systemui/DessertCase.java @@ -16,22 +16,51 @@ package com.android.systemui; +import android.animation.ObjectAnimator; import android.app.Activity; import android.content.ComponentName; import android.content.pm.PackageManager; +import android.os.Handler; import android.util.Slog; +import android.view.animation.DecelerateInterpolator; public class DessertCase extends Activity { + DessertCaseView mView; @Override public void onStart() { super.onStart(); - Slog.v("DessertCase", "ACHIEVEMENT UNLOCKED"); PackageManager pm = getPackageManager(); - pm.setComponentEnabledSetting(new ComponentName(this, DessertCaseDream.class), - PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0); + final ComponentName cn = new ComponentName(this, DessertCaseDream.class); + if (pm.getComponentEnabledSetting(cn) != PackageManager.COMPONENT_ENABLED_STATE_ENABLED) { + Slog.v("DessertCase", "ACHIEVEMENT UNLOCKED"); + pm.setComponentEnabledSetting(cn, + PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0); + } - finish(); + mView = new DessertCaseView(this); + + DessertCaseView.RescalingContainer container = new DessertCaseView.RescalingContainer(this); + + container.setView(mView); + + setContentView(container); + } + + @Override + public void onResume() { + super.onResume(); + mView.postDelayed(new Runnable() { + public void run() { + mView.start(); + } + }, 1000); + } + + @Override + public void onPause() { + super.onPause(); + mView.stop(); } } diff --git a/packages/SystemUI/src/com/android/systemui/DessertCaseDream.java b/packages/SystemUI/src/com/android/systemui/DessertCaseDream.java index 022e4d8..a627cf6 100644 --- a/packages/SystemUI/src/com/android/systemui/DessertCaseDream.java +++ b/packages/SystemUI/src/com/android/systemui/DessertCaseDream.java @@ -19,21 +19,36 @@ package com.android.systemui; import android.service.dreams.DreamService; public class DessertCaseDream extends DreamService { + private DessertCaseView mView; + private DessertCaseView.RescalingContainer mContainer; @Override public void onAttachedToWindow() { super.onAttachedToWindow(); - setInteractive(true); - setFullscreen(true); + setInteractive(false); + + mView = new DessertCaseView(this); + + mContainer = new DessertCaseView.RescalingContainer(this); + + mContainer.setView(mView); + + setContentView(mContainer); } @Override public void onDreamingStarted() { super.onDreamingStarted(); + mView.postDelayed(new Runnable() { + public void run() { + mView.start(); + } + }, 1000); } @Override public void onDreamingStopped() { super.onDreamingStopped(); + mView.stop(); } } diff --git a/packages/SystemUI/src/com/android/systemui/DessertCaseView.java b/packages/SystemUI/src/com/android/systemui/DessertCaseView.java new file mode 100644 index 0000000..99c59d5 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/DessertCaseView.java @@ -0,0 +1,505 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui; + +import android.animation.Animator; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; +import android.content.Context; +import android.content.res.Resources; +import android.graphics.*; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.os.Handler; +import android.util.AttributeSet; +import android.util.Log; +import android.util.SparseArray; +import android.view.View; +import android.view.animation.AccelerateInterpolator; +import android.view.animation.AnticipateOvershootInterpolator; +import android.view.animation.DecelerateInterpolator; +import android.widget.FrameLayout; +import android.widget.ImageView; + +import java.util.HashSet; +import java.util.Set; + +public class DessertCaseView extends FrameLayout { + private static final String TAG = DessertCaseView.class.getSimpleName(); + + private static final boolean DEBUG = false; + + static final int START_DELAY = 5000; + static final int DELAY = 2000; + static final int DURATION = 500; + + private static final int TAG_POS = 0x2000001; + private static final int TAG_SPAN = 0x2000002; + + private static final int[] PASTRIES = { + R.drawable.dessert_kitkat, // used with permission + R.drawable.dessert_android, // thx irina + }; + + private static final int[] RARE_PASTRIES = { + R.drawable.dessert_cupcake, // 2009 + R.drawable.dessert_donut, // 2009 + R.drawable.dessert_eclair, // 2009 + R.drawable.dessert_froyo, // 2010 + R.drawable.dessert_gingerbread, // 2010 + R.drawable.dessert_honeycomb, // 2011 + R.drawable.dessert_ics, // 2011 + R.drawable.dessert_jellybean, // 2012 + }; + + private static final int[] XRARE_PASTRIES = { + R.drawable.dessert_petitfour, // the original and still delicious + + R.drawable.dessert_donutburger, // remember kids, this was long before cronuts + + R.drawable.dessert_flan, // sholes final approach + // landing gear punted to flan + // runway foam glistens + // -- mcleron + + R.drawable.dessert_keylimepie, // from an alternative timeline + }; + private static final int[] XXRARE_PASTRIES = { + R.drawable.dessert_zombiegingerbread, // thx hackbod + R.drawable.dessert_dandroid, // thx morrildl + R.drawable.dessert_jandycane, // thx nes + }; + + private static final int NUM_PASTRIES = PASTRIES.length + RARE_PASTRIES.length + + XRARE_PASTRIES.length + XXRARE_PASTRIES.length; + + private SparseArray<Drawable> mDrawables = new SparseArray<Drawable>(NUM_PASTRIES); + + private static final float[] MASK = { + 0f, 0f, 0f, 0f, 255f, + 0f, 0f, 0f, 0f, 255f, + 0f, 0f, 0f, 0f, 255f, + 1f, 0f, 0f, 0f, 0f + }; + + private static final float[] WHITE_MASK = { + 0f, 0f, 0f, 0f, 255f, + 0f, 0f, 0f, 0f, 255f, + 0f, 0f, 0f, 0f, 255f, + -1f, 0f, 0f, 0f, 255f + }; + + public static final float SCALE = 0.25f; // natural display size will be SCALE*mCellSize + + private static final float PROB_2X = 0.33f; + private static final float PROB_3X = 0.1f; + private static final float PROB_4X = 0.01f; + + private boolean mStarted; + + private int mCellSize; + private int mWidth, mHeight; + private int mRows, mColumns; + private View[] mCells; + + private final Set<Point> mFreeList = new HashSet<Point>(); + + private final Handler mHandler = new Handler(); + + private final Runnable mJuggle = new Runnable() { + @Override + public void run() { + final int N = getChildCount(); + + final int K = 1; //irand(1,3); + for (int i=0; i<K; i++) { + final View child = getChildAt((int) (Math.random() * N)); + place(child, true); + } + + fillFreeList(); + + if (mStarted) { + mHandler.postDelayed(mJuggle, DELAY); + } + } + }; + + public DessertCaseView(Context context) { + this(context, null); + } + + public DessertCaseView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public DessertCaseView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + + final Resources res = getResources(); + + mStarted = false; + + mCellSize = res.getDimensionPixelSize(R.dimen.dessert_case_cell_size); + final BitmapFactory.Options opts = new BitmapFactory.Options(); + if (mCellSize < 512) { // assuming 512x512 images + opts.inSampleSize = 2; + } + for (int[] list : new int[][] { PASTRIES, RARE_PASTRIES, XRARE_PASTRIES, XXRARE_PASTRIES }) { + for (int resid : list) { + final BitmapDrawable d = new BitmapDrawable(res, + BitmapFactory.decodeResource(res, resid, opts)); + d.setColorFilter(new ColorMatrixColorFilter(MASK)); + d.setBounds(0, 0, mCellSize, mCellSize); + mDrawables.append(resid, d); + } + } + if (DEBUG) setWillNotDraw(false); + } + + public void start() { + if (!mStarted) { + mStarted = true; + fillFreeList(DURATION * 4); + } + mHandler.postDelayed(mJuggle, START_DELAY); + } + + public void stop() { + mStarted = false; + mHandler.removeCallbacks(mJuggle); + } + + int pick(int[] a) { + return a[(int)(Math.random()*a.length)]; + } + + <T> T pick(T[] a) { + return a[(int)(Math.random()*a.length)]; + } + + <T> T pick(SparseArray<T> sa) { + return sa.valueAt((int)(Math.random()*sa.size())); + } + + float[] hsv = new float[] { 0, 1f, .85f }; + int random_color() { +// return 0xFF000000 | (int) (Math.random() * (float) 0xFFFFFF); // totally random + final int COLORS = 12; + hsv[0] = irand(0,COLORS) * (360f/COLORS); + return Color.HSVToColor(hsv); + } + + @Override + protected synchronized void onSizeChanged (int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + if (mWidth == w && mHeight == h) return; + + final boolean wasStarted = mStarted; + if (wasStarted) { + stop(); + } + + mWidth = w; + mHeight = h; + + mCells = null; + removeAllViewsInLayout(); + mFreeList.clear(); + + mRows = mHeight / mCellSize; + mColumns = mWidth / mCellSize; + + mCells = new View[mRows * mColumns]; + + if (DEBUG) Log.v(TAG, String.format("New dimensions: %dx%d", mColumns, mRows)); + + setScaleX(SCALE); + setScaleY(SCALE); + setTranslationX(0.5f * (mWidth - mCellSize * mColumns) * SCALE); + setTranslationY(0.5f * (mHeight - mCellSize * mRows) * SCALE); + + for (int j=0; j<mRows; j++) { + for (int i=0; i<mColumns; i++) { + mFreeList.add(new Point(i,j)); + } + } + + if (wasStarted) { + start(); + } + } + + public void fillFreeList() { + fillFreeList(DURATION); + } + + public synchronized void fillFreeList(int animationLen) { + final Context ctx = getContext(); + final FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(mCellSize, mCellSize); + + while (! mFreeList.isEmpty()) { + Point pt = mFreeList.iterator().next(); + mFreeList.remove(pt); + final int i=pt.x; + final int j=pt.y; + + if (mCells[j*mColumns+i] != null) continue; + final ImageView v = new ImageView(ctx); + v.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View view) { + place(v, true); + postDelayed(new Runnable() { public void run() { fillFreeList(); } }, DURATION/2); + } + }); + + final int c = random_color(); + v.setBackgroundColor(c); + + final float which = frand(); + final Drawable d; + if (which < 0.001f) { + d = mDrawables.get(pick(XXRARE_PASTRIES)); + } else if (which < 0.01f) { + d = mDrawables.get(pick(XRARE_PASTRIES)); + } else if (which < 0.5f) { + d = mDrawables.get(pick(RARE_PASTRIES)); + } else if (which < 0.7f) { + d = mDrawables.get(pick(PASTRIES)); + } else { + d = null; + } + if (d != null) { + v.getOverlay().add(d); + } + + final Paint paint = new Paint(); + v.setLayerType(View.LAYER_TYPE_HARDWARE, paint); + + lp.width = lp.height = mCellSize; + addView(v, lp); + place(v, pt, false); + if (animationLen > 0) { + final float s = (Integer) v.getTag(TAG_SPAN); + v.setScaleX(0.5f * s); + v.setScaleY(0.5f * s); + v.setAlpha(0f); + v.animate().scaleX(s).scaleY(s).alpha(1f).setDuration(animationLen); + } + } + } + + public void place(View v, boolean animate) { + place(v, new Point(irand(0, mColumns), irand(0, mRows)), animate); + } + + private final HashSet<View> tmpSet = new HashSet<View>(); + public synchronized void place(View v, Point pt, boolean animate) { + final int i = pt.x; + final int j = pt.y; + final float rnd = frand(); + if (v.getTag(TAG_POS) != null) { + for (final Point oc : getOccupied(v)) { + mFreeList.add(oc); + mCells[oc.y*mColumns + oc.x] = null; + } + } + int scale = 1; + if (rnd < PROB_4X) { + if (!(i >= mColumns-3 || j >= mRows-3)) { + scale = 4; + } + } else if (rnd < PROB_3X) { + if (!(i >= mColumns-2 || j >= mRows-2)) { + scale = 3; + } + } else if (rnd < PROB_2X) { + if (!(i == mColumns-1 || j == mRows-1)) { + scale = 2; + } + } + + v.setTag(TAG_POS, pt); + v.setTag(TAG_SPAN, scale); + + tmpSet.clear(); + + final Point[] occupied = getOccupied(v); + for (final Point oc : occupied) { + final View squatter = mCells[oc.y*mColumns + oc.x]; + if (squatter != null) { + tmpSet.add(squatter); + } + } + + for (final View squatter : tmpSet) { + for (final Point sq : getOccupied(squatter)) { + mFreeList.add(sq); + mCells[sq.y*mColumns + sq.x] = null; + } + if (squatter != v) { + squatter.setTag(TAG_POS, null); + if (animate) { + squatter.animate().scaleX(0.5f).scaleY(0.5f).alpha(0) + .setDuration(DURATION) + .setInterpolator(new AccelerateInterpolator()) + .setListener(new Animator.AnimatorListener() { + public void onAnimationStart(Animator animator) { } + public void onAnimationEnd(Animator animator) { + removeView(squatter); + } + public void onAnimationCancel(Animator animator) { } + public void onAnimationRepeat(Animator animator) { } + }) + .start(); + } else { + removeView(squatter); + } + } + } + + for (final Point oc : occupied) { + mCells[oc.y*mColumns + oc.x] = v; + mFreeList.remove(oc); + } + + final float rot = (float)irand(0, 4) * 90f; + + if (animate) { + v.bringToFront(); + AnimatorSet set1 = new AnimatorSet(); + set1.playTogether( + ObjectAnimator.ofFloat(v, View.SCALE_X, (float) scale), + ObjectAnimator.ofFloat(v, View.SCALE_Y, (float) scale) + ); + set1.setInterpolator(new AnticipateOvershootInterpolator()); + set1.setDuration(DURATION); + set1.start(); + + AnimatorSet set2 = new AnimatorSet(); + set2.playTogether( + ObjectAnimator.ofFloat(v, View.ROTATION, rot), + ObjectAnimator.ofFloat(v, View.X, i* mCellSize + (scale-1) * mCellSize /2), + ObjectAnimator.ofFloat(v, View.Y, j* mCellSize + (scale-1) * mCellSize /2) + ); + set2.setInterpolator(new DecelerateInterpolator()); + set2.setDuration(DURATION); + set2.start(); + } else { + v.setX(i * mCellSize + (scale-1) * mCellSize /2); + v.setY(j * mCellSize + (scale-1) * mCellSize /2); + v.setScaleX((float) scale); + v.setScaleY((float) scale); + v.setRotation(rot); + } + } + + private Point[] getOccupied(View v) { + final int scale = (Integer) v.getTag(TAG_SPAN); + final Point pt = (Point)v.getTag(TAG_POS); + if (pt == null || scale == 0) return new Point[0]; + + final Point[] result = new Point[scale * scale]; + int p=0; + for (int i=0; i<scale; i++) { + for (int j=0; j<scale; j++) { + result[p++] = new Point(pt.x + i, pt.y + j); + } + } + return result; + } + + static float frand() { + return (float)(Math.random()); + } + + static float frand(float a, float b) { + return (frand() * (b-a) + a); + } + + static int irand(int a, int b) { + return (int)(frand(a, b)); + } + + @Override + public void onDraw(Canvas c) { + super.onDraw(c); + if (!DEBUG) return; + + Paint pt = new Paint(); + pt.setStyle(Paint.Style.STROKE); + pt.setColor(0xFFCCCCCC); + pt.setStrokeWidth(2.0f); + + final Rect check = new Rect(); + final int N = getChildCount(); + for (int i = 0; i < N; i++) { + View stone = getChildAt(i); + + stone.getHitRect(check); + + c.drawRect(check, pt); + } + } + + public static class RescalingContainer extends FrameLayout { + private static final int SYSTEM_UI_MODE_800 = 0x00000800; + private DessertCaseView mView; + private float mDarkness; + + public RescalingContainer(Context context) { + super(context); + + setSystemUiVisibility(0 + | View.SYSTEM_UI_FLAG_FULLSCREEN + | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + | SYSTEM_UI_MODE_800 + ); + } + + public void setView(DessertCaseView v) { + addView(v); + mView = v; + } + + @Override + protected void onLayout (boolean changed, int left, int top, int right, int bottom) { + final float w = right-left; + final float h = bottom-top; + final int w2 = (int) (w / mView.SCALE / 2); + final int h2 = (int) (h / mView.SCALE / 2); + final int cx = (int) (left + w * 0.5f); + final int cy = (int) (top + h * 0.5f); + mView.layout(cx - w2, cy - h2, cx + w2, cy + h2); + } + + public void setDarkness(float p) { + mDarkness = p; + getDarkness(); + final int x = (int) (p * 0xff); + setBackgroundColor(x << 24 & 0xFF000000); + } + + public float getDarkness() { + return mDarkness; + } + } +} |