Reconcile with jb-mr1-factory-release jb-mr1-release - do not merge

Change-Id: I6a2777a25426e69caf568c39823597c86aaa1c61
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 9ae31d7..adb6ef3 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -99,15 +99,6 @@
                 android:resource="@xml/wallpaper_picker_preview" />
         </activity>
 
-        <activity android:name="com.android.launcher2.RocketLauncher"
-            android:label="@string/dream_name"
-            android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen">
-            <intent-filter>
-                <action android:name="android.service.dreams.DreamService" />
-                <category android:name="android.intent.category.DEFAULT" />
-            </intent-filter>
-        </activity>
-
         <!-- Intent received used to prepopulate the default workspace. -->
         <receiver
             android:name="com.android.launcher2.PreloadReceiver"
diff --git a/res/drawable-xhdpi/wallpaper_01.jpg b/res/drawable-xhdpi/wallpaper_01.jpg
index 5b8d1d5..da9fa91 100644
--- a/res/drawable-xhdpi/wallpaper_01.jpg
+++ b/res/drawable-xhdpi/wallpaper_01.jpg
Binary files differ
diff --git a/res/drawable-xhdpi/wallpaper_02.jpg b/res/drawable-xhdpi/wallpaper_02.jpg
index 29cba13..ee949aa 100644
--- a/res/drawable-xhdpi/wallpaper_02.jpg
+++ b/res/drawable-xhdpi/wallpaper_02.jpg
Binary files differ
diff --git a/res/drawable-xhdpi/wallpaper_03.jpg b/res/drawable-xhdpi/wallpaper_03.jpg
index 5c165cf..9931ca2 100644
--- a/res/drawable-xhdpi/wallpaper_03.jpg
+++ b/res/drawable-xhdpi/wallpaper_03.jpg
Binary files differ
diff --git a/res/drawable-xhdpi/wallpaper_04.jpg b/res/drawable-xhdpi/wallpaper_04.jpg
index 2f0da9d..306c8cd 100644
--- a/res/drawable-xhdpi/wallpaper_04.jpg
+++ b/res/drawable-xhdpi/wallpaper_04.jpg
Binary files differ
diff --git a/res/drawable-xhdpi/wallpaper_05.jpg b/res/drawable-xhdpi/wallpaper_05.jpg
index 4ae7bb9..0735f5f 100644
--- a/res/drawable-xhdpi/wallpaper_05.jpg
+++ b/res/drawable-xhdpi/wallpaper_05.jpg
Binary files differ
diff --git a/res/drawable-xhdpi/wallpaper_08.jpg b/res/drawable-xhdpi/wallpaper_08.jpg
index d091cb7..3fa6811 100644
--- a/res/drawable-xhdpi/wallpaper_08.jpg
+++ b/res/drawable-xhdpi/wallpaper_08.jpg
Binary files differ
diff --git a/res/drawable-xhdpi/wallpaper_09.jpg b/res/drawable-xhdpi/wallpaper_09.jpg
index 7990d4c..cd062a6 100644
--- a/res/drawable-xhdpi/wallpaper_09.jpg
+++ b/res/drawable-xhdpi/wallpaper_09.jpg
Binary files differ
diff --git a/res/drawable-xhdpi/wallpaper_10.jpg b/res/drawable-xhdpi/wallpaper_10.jpg
index 1fd1388..02b441e 100644
--- a/res/drawable-xhdpi/wallpaper_10.jpg
+++ b/res/drawable-xhdpi/wallpaper_10.jpg
Binary files differ
diff --git a/res/drawable-xhdpi/wallpaper_11.jpg b/res/drawable-xhdpi/wallpaper_11.jpg
index b1609b9..39490ac 100644
--- a/res/drawable-xhdpi/wallpaper_11.jpg
+++ b/res/drawable-xhdpi/wallpaper_11.jpg
Binary files differ
diff --git a/res/drawable-xhdpi/wallpaper_12.jpg b/res/drawable-xhdpi/wallpaper_12.jpg
index ed7fa0f..d1ca450 100644
--- a/res/drawable-xhdpi/wallpaper_12.jpg
+++ b/res/drawable-xhdpi/wallpaper_12.jpg
Binary files differ
diff --git a/res/layout-land/workspace_cling.xml b/res/layout-land/workspace_cling.xml
index b66f1bd..b035aa1 100644
--- a/res/layout-land/workspace_cling.xml
+++ b/res/layout-land/workspace_cling.xml
@@ -16,6 +16,8 @@
 <com.android.launcher2.Cling
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
     launcher:drawIdentifier="workspace_landscape">
     <FrameLayout
         android:layout_width="match_parent"
@@ -28,6 +30,8 @@
             android:orientation="vertical">
             <TextView
                 style="@style/ClingTitleText"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
                 android:text="@string/workspace_cling_title" />
             <TextView
                 style="@style/ClingText"
@@ -46,6 +50,8 @@
         android:text="@string/workspace_cling_open_all_apps" />
     <Button
         style="@style/ClingButton"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
         android:layout_marginBottom="15dp"
         android:layout_marginRight="10dp"
         android:layout_gravity="bottom|right"
diff --git a/res/layout-port/workspace_cling.xml b/res/layout-port/workspace_cling.xml
index 10e6976..738e2c5 100644
--- a/res/layout-port/workspace_cling.xml
+++ b/res/layout-port/workspace_cling.xml
@@ -16,6 +16,8 @@
 <com.android.launcher2.Cling
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
     launcher:drawIdentifier="workspace_portrait">
     <FrameLayout
         android:layout_width="match_parent"
@@ -29,6 +31,8 @@
             android:orientation="vertical">
             <TextView
                 style="@style/ClingTitleText"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
                 android:text="@string/workspace_cling_title" />
             <TextView
                 style="@style/ClingText"
@@ -49,6 +53,8 @@
         android:text="@string/workspace_cling_open_all_apps" />
     <Button
         style="@style/ClingButton"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
         android:layout_marginBottom="15dp"
         android:layout_marginRight="10dp"
         android:layout_gravity="bottom|right"
diff --git a/res/layout-sw720dp/workspace_cling.xml b/res/layout-sw720dp/workspace_cling.xml
index 10e6976..738e2c5 100644
--- a/res/layout-sw720dp/workspace_cling.xml
+++ b/res/layout-sw720dp/workspace_cling.xml
@@ -16,6 +16,8 @@
 <com.android.launcher2.Cling
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
     launcher:drawIdentifier="workspace_portrait">
     <FrameLayout
         android:layout_width="match_parent"
@@ -29,6 +31,8 @@
             android:orientation="vertical">
             <TextView
                 style="@style/ClingTitleText"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
                 android:text="@string/workspace_cling_title" />
             <TextView
                 style="@style/ClingText"
@@ -49,6 +53,8 @@
         android:text="@string/workspace_cling_open_all_apps" />
     <Button
         style="@style/ClingButton"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
         android:layout_marginBottom="15dp"
         android:layout_marginRight="10dp"
         android:layout_gravity="bottom|right"
diff --git a/res/layout/custom_workspace_cling.xml b/res/layout/custom_workspace_cling.xml
index 5bdc587..0fdb575 100644
--- a/res/layout/custom_workspace_cling.xml
+++ b/res/layout/custom_workspace_cling.xml
@@ -17,6 +17,8 @@
 <com.android.launcher2.Cling
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
     launcher:drawIdentifier="workspace_custom">
     <TextView
         android:layout_width="wrap_content"
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index 5dd726a..7e49aef 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -20,7 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="8424725141379931883">"Покретач"</string>
-    <string name="home" msgid="5921706419368316758">"Кућни"</string>
+    <string name="home" msgid="5921706419368316758">"Почетна"</string>
     <string name="uid_name" msgid="3371120195364560632">"Основне Android апликације"</string>
     <string name="folder_name" msgid="8551881338202938211"></string>
     <string name="chooser_wallpaper" msgid="6063168087625352235">"Избор позадине из"</string>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 04e45ae..0ea12c4 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -266,12 +266,12 @@
 
     <!-- Clings -->
     <!-- Dummy string [CHAR_LIMIT=40] -->
-    <add-resource type="string" name="custom_workspace_cling_title_1"/>
+    <string name="custom_workspace_cling_title_1"></string>
     <!-- Dummy string [CHAR_LIMIT=60] -->
-    <add-resource type="string" name="custom_workspace_cling_description_1"/>
+    <string name="custom_workspace_cling_description_1"></string>
     <!-- Dummy string [CHAR_LIMIT=40] -->
-    <add-resource type="string" name="custom_workspace_cling_title_2"/>
+    <string name="custom_workspace_cling_title_2"></string>
     <!-- Dummy string [CHAR_LIMIT=60] -->
-    <add-resource type="string" name="custom_workspace_cling_description_2"/>
+    <string name="custom_workspace_cling_description_2"></string>
 
 </resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 0960269..c3fe7ef 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -46,6 +46,8 @@
         <item name="android:shadowRadius">2.0</item>
     </style>
     <style name="ClingText">
+        <item name="android:layout_width">wrap_content</item>
+        <item name="android:layout_height">wrap_content</item>
         <item name="android:textSize">15sp</item>
         <item name="android:textColor">#FFFFFF</item>
         <item name="android:shadowColor">#000000</item>
diff --git a/src/com/android/launcher2/AppsCustomizeTabHost.java b/src/com/android/launcher2/AppsCustomizeTabHost.java
index 5b33c31..96ec33e 100644
--- a/src/com/android/launcher2/AppsCustomizeTabHost.java
+++ b/src/com/android/launcher2/AppsCustomizeTabHost.java
@@ -352,11 +352,6 @@
             // force building the layer, so you don't get a blip early in an animation
             // when the layer is created layer
             buildLayer();
-
-            // Let the GC system know that now is a good time to do any garbage
-            // collection; makes it less likely we'll get a GC during the all apps
-            // to workspace animation
-            System.gc();
         }
     }
 
diff --git a/src/com/android/launcher2/DragLayer.java b/src/com/android/launcher2/DragLayer.java
index fed0ad9..e870d0a 100644
--- a/src/com/android/launcher2/DragLayer.java
+++ b/src/com/android/launcher2/DragLayer.java
@@ -167,6 +167,9 @@
 
     @Override
     public boolean onInterceptHoverEvent(MotionEvent ev) {
+        if (mLauncher == null || mLauncher.getWorkspace() == null) {
+            return false;
+        }
         Folder currentFolder = mLauncher.getWorkspace().getOpenFolder();
         if (currentFolder == null) {
             return false;
diff --git a/src/com/android/launcher2/Launcher.java b/src/com/android/launcher2/Launcher.java
index 6fcda8a..c221815 100644
--- a/src/com/android/launcher2/Launcher.java
+++ b/src/com/android/launcher2/Launcher.java
@@ -1384,39 +1384,54 @@
             // also will cancel mWaitingForResult.
             closeSystemDialogs();
 
-            boolean alreadyOnHome = ((intent.getFlags() & Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT)
+            final boolean alreadyOnHome =
+                    ((intent.getFlags() & Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT)
                         != Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
 
-            Folder openFolder = mWorkspace.getOpenFolder();
-            // In all these cases, only animate if we're already on home
-            mWorkspace.exitWidgetResizeMode();
-            if (alreadyOnHome && mState == State.WORKSPACE && !mWorkspace.isTouchActive() &&
-                    openFolder == null) {
-                mWorkspace.moveToDefaultScreen(true);
-            }
+            Runnable processIntent = new Runnable() {
+                public void run() {
+                    Folder openFolder = mWorkspace.getOpenFolder();
+                    // In all these cases, only animate if we're already on home
+                    mWorkspace.exitWidgetResizeMode();
+                    if (alreadyOnHome && mState == State.WORKSPACE && !mWorkspace.isTouchActive() &&
+                            openFolder == null) {
+                        mWorkspace.moveToDefaultScreen(true);
+                    }
 
-            closeFolder();
-            exitSpringLoadedDragMode();
+                    closeFolder();
+                    exitSpringLoadedDragMode();
 
-            // If we are already on home, then just animate back to the workspace, otherwise, just
-            // wait until onResume to set the state back to Workspace
-            if (alreadyOnHome) {
-                showWorkspace(true);
+                    // If we are already on home, then just animate back to the workspace,
+                    // otherwise, just wait until onResume to set the state back to Workspace
+                    if (alreadyOnHome) {
+                        showWorkspace(true);
+                    } else {
+                        mOnResumeState = State.WORKSPACE;
+                    }
+
+                    final View v = getWindow().peekDecorView();
+                    if (v != null && v.getWindowToken() != null) {
+                        InputMethodManager imm = (InputMethodManager)getSystemService(
+                                INPUT_METHOD_SERVICE);
+                        imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
+                    }
+
+                    // Reset AllApps to its initial state
+                    if (!alreadyOnHome && mAppsCustomizeTabHost != null) {
+                        mAppsCustomizeTabHost.reset();
+                    }
+                }
+            };
+
+            if (alreadyOnHome && !mWorkspace.hasWindowFocus()) {
+                // Delay processing of the intent to allow the status bar animation to finish
+                // first in order to avoid janky animations.
+                mWorkspace.postDelayed(processIntent, 350);
             } else {
-                mOnResumeState = State.WORKSPACE;
+                // Process the intent immediately.
+                processIntent.run();
             }
 
-            final View v = getWindow().peekDecorView();
-            if (v != null && v.getWindowToken() != null) {
-                InputMethodManager imm = (InputMethodManager)getSystemService(
-                        INPUT_METHOD_SERVICE);
-                imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
-            }
-
-            // Reset AllApps to its initial state
-            if (!alreadyOnHome && mAppsCustomizeTabHost != null) {
-                mAppsCustomizeTabHost.reset();
-            }
         }
     }
 
@@ -2682,6 +2697,7 @@
 
             dispatchOnLauncherTransitionPrepare(fromView, animated, true);
             dispatchOnLauncherTransitionPrepare(toView, animated, true);
+            mAppsCustomizeContent.pauseScrolling();
 
             mStateAnimation.addListener(new AnimatorListenerAdapter() {
                 @Override
@@ -2696,6 +2712,8 @@
                     if (onCompleteRunnable != null) {
                         onCompleteRunnable.run();
                     }
+                    mAppsCustomizeContent.updateCurrentPageScroll();
+                    mAppsCustomizeContent.resumeScrolling();
                 }
             });
 
@@ -2784,8 +2802,9 @@
         mUserPresent = true;
         updateRunning();
 
-        // send an accessibility event to announce the context change
-        getWindow().getDecorView().sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
+        // Send an accessibility event to announce the context change
+        getWindow().getDecorView()
+                .sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
     }
 
     void showAllApps(boolean animated) {
@@ -2803,7 +2822,8 @@
         closeFolder();
 
         // Send an accessibility event to announce the context change
-        getWindow().getDecorView().sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
+        getWindow().getDecorView()
+                .sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
     }
 
     void enterSpringLoadedDragMode() {
@@ -3177,10 +3197,15 @@
 
     @Override
     public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
-        boolean result = super.dispatchPopulateAccessibilityEvent(event);
+        final boolean result = super.dispatchPopulateAccessibilityEvent(event);
         final List<CharSequence> text = event.getText();
         text.clear();
-        text.add(getString(R.string.home));
+        // Populate event with a fake title based on the current state.
+        if (mState == State.APPS_CUSTOMIZE) {
+            text.add(getString(R.string.all_apps_button_label));
+        } else {
+            text.add(getString(R.string.all_apps_home_button_label));
+        }
         return result;
     }
 
@@ -3482,7 +3507,9 @@
             anim.addListener(new AnimatorListenerAdapter() {
                 @Override
                 public void onAnimationEnd(Animator animation) {
-                    mWorkspace.postDelayed(mBuildLayersRunnable, 500);
+                    if (mWorkspace != null) {
+                        mWorkspace.postDelayed(mBuildLayersRunnable, 500);
+                    }
                 }
             });
             anim.start();
diff --git a/src/com/android/launcher2/PagedView.java b/src/com/android/launcher2/PagedView.java
index 9b97384..2cb943d 100644
--- a/src/com/android/launcher2/PagedView.java
+++ b/src/com/android/launcher2/PagedView.java
@@ -59,6 +59,7 @@
     private static final int MIN_LENGTH_FOR_FLING = 25;
 
     protected static final int PAGE_SNAP_ANIMATION_DURATION = 550;
+    protected static final int MAX_PAGE_SNAP_DURATION = 750;
     protected static final int SLOW_PAGE_SNAP_ANIMATION_DURATION = 950;
     protected static final float NANOTIME_DIV = 1000000000.0f;
 
@@ -181,6 +182,7 @@
     protected static final int sScrollIndicatorFadeInDuration = 150;
     protected static final int sScrollIndicatorFadeOutDuration = 650;
     protected static final int sScrollIndicatorFlashDuration = 650;
+    private boolean mScrollingPaused = false;
 
     // If set, will defer loading associated pages until the scrolling settles
     private boolean mDeferLoadAssociatedPagesUntilScrollCompletes;
@@ -304,6 +306,24 @@
     }
 
     /**
+     * Called during AllApps/Home transitions to avoid unnecessary work. When that other animation
+     * ends, {@link #resumeScrolling()} should be called, along with
+     * {@link #updateCurrentPageScroll()} to correctly set the final state and re-enable scrolling.
+     */
+    void pauseScrolling() {
+        mScroller.forceFinished(true);
+        cancelScrollingIndicatorAnimations();
+        mScrollingPaused = true;
+    }
+
+    /**
+     * Enables scrolling again.
+     * @see #pauseScrolling()
+     */
+    void resumeScrolling() {
+        mScrollingPaused = false;
+    }
+    /**
      * Sets the current page.
      */
     void setCurrentPage(int currentPage) {
@@ -1473,6 +1493,7 @@
         // user flings, so we scale the duration by a value near to the derivative of the scroll
         // interpolator at zero, ie. 5. We use 4 to make it a little slower.
         duration = 4 * Math.round(1000 * Math.abs(distance / velocity));
+        duration = Math.min(duration, MAX_PAGE_SNAP_DURATION);
 
         snapToPage(whichPage, delta, duration);
     }
@@ -1743,7 +1764,7 @@
             updateScrollingIndicatorPosition();
             mScrollIndicator.setVisibility(View.VISIBLE);
             cancelScrollingIndicatorAnimations();
-            if (immediately) {
+            if (immediately || mScrollingPaused) {
                 mScrollIndicator.setAlpha(1f);
             } else {
                 mScrollIndicatorAnimator = LauncherAnimUtils.ofFloat(mScrollIndicator, "alpha", 1f);
@@ -1768,7 +1789,7 @@
             // Fade the indicator out
             updateScrollingIndicatorPosition();
             cancelScrollingIndicatorAnimations();
-            if (immediately) {
+            if (immediately || mScrollingPaused) {
                 mScrollIndicator.setVisibility(View.INVISIBLE);
                 mScrollIndicator.setAlpha(0f);
             } else {
diff --git a/src/com/android/launcher2/RocketLauncher.java b/src/com/android/launcher2/RocketLauncher.java
deleted file mode 100644
index 6eefedd..0000000
--- a/src/com/android/launcher2/RocketLauncher.java
+++ /dev/null
@@ -1,416 +0,0 @@
-/*);
- * Copyright (C) 2011 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.
- */
-
-// TODO:
-// background stellar matter:
-//  - add some slow horizontal parallax motion, or perhaps veeeeery gradual outward drift
-
-package com.android.launcher2;
-
-import android.animation.AnimatorSet;
-import android.animation.TimeAnimator;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.Bitmap;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.os.Handler;
-import android.support.v13.dreams.BasicDream;
-import android.util.AttributeSet;
-import android.util.DisplayMetrics;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-
-import com.android.launcher.R;
-
-import java.util.HashMap;
-import java.util.Random;
-
-public class RocketLauncher extends BasicDream {
-    public static final boolean ROCKET_LAUNCHER = true;
-
-    public static class Board extends FrameLayout
-    {
-        public static final boolean FIXED_STARS = true;
-        public static final boolean FLYING_STARS = true;
-        public static final int NUM_ICONS = 20;
-
-        public static final float MANEUVERING_THRUST_SCALE = 0.1f; // tenth speed
-        private boolean mManeuveringThrusters = false;
-        private float mSpeedScale = 1.0f;
-
-        public static final int LAUNCH_ZOOM_TIME = 400; // ms
-
-        HashMap<ComponentName, Bitmap> mIcons;
-        ComponentName[] mComponentNames;
-
-        static Random sRNG = new Random();
-
-        static float lerp(float a, float b, float f) {
-            return (b-a)*f + a;
-        }
-
-        static float randfrange(float a, float b) {
-            return lerp(a, b, sRNG.nextFloat());
-        }
-
-        static int randsign() {
-            return sRNG.nextBoolean() ? 1 : -1;
-        }
-
-        static <E> E pick(E[] array) {
-            if (array.length == 0) return null;
-            return array[sRNG.nextInt(array.length)];
-        }
-
-        public class FlyingIcon extends ImageView {
-            public static final float VMAX = 1000.0f;
-            public static final float VMIN = 100.0f;
-            public static final float ANGULAR_VMAX = 45f;
-            public static final float ANGULAR_VMIN = 0f;
-            public static final float SCALE_MIN = 0.5f;
-            public static final float SCALE_MAX = 4f;
-
-            public float v, vr;
-
-            public final float[] hsv = new float[3];
-
-            public float angle, anglex, angley;
-            public float fuse;
-            public float dist;
-            public float endscale;
-            public float boardCenterX, boardCenterY;
-
-            public ComponentName component;
-
-            public FlyingIcon(Context context, AttributeSet as) {
-                super(context, as);
-                setLayerType(View.LAYER_TYPE_HARDWARE, null);
-
-                setBackgroundResource(R.drawable.flying_icon_bg);
-                //android.util.Log.d("RocketLauncher", "ctor: " + this);
-                hsv[1] = 1f;
-                hsv[2] = 1f;
-            }
-
-            @Override
-            public boolean onTouchEvent(MotionEvent event) {
-                if (!mManeuveringThrusters || component == null) {
-                    return false;
-                }
-                if (getAlpha() < 0.5f) {
-                    setPressed(false);
-                    return false;
-                }
-
-                switch (event.getAction()) {
-                    case MotionEvent.ACTION_DOWN:
-                        setPressed(true);
-                        Board.this.resetWarpTimer();
-                        break;
-                    case MotionEvent.ACTION_MOVE:
-                        final Rect hit = new Rect();
-                        final Point offset = new Point();
-                        getGlobalVisibleRect(hit, offset);
-                        final int globx = (int) event.getX() + offset.x;
-                        final int globy = (int) event.getY() + offset.y;
-                        setPressed(hit.contains(globx, globy));
-                        Board.this.resetWarpTimer();
-                        break;
-                    case MotionEvent.ACTION_UP:
-                        if (isPressed()) {
-                            setPressed(false);
-                            postDelayed(new Runnable() {
-                                public void run() {
-                                    try {
-                                        getContext().startActivity(new Intent(Intent.ACTION_MAIN)
-                                            .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
-                                            .setComponent(component));
-                                    } catch (android.content.ActivityNotFoundException e) {
-                                    } catch (SecurityException e) {
-                                    }
-                                }
-                            }, LAUNCH_ZOOM_TIME);
-                            endscale = 0;
-                            AnimatorSet s = LauncherAnimUtils.createAnimatorSet();
-                            s.playTogether(
-                                LauncherAnimUtils.ofFloat(this, "scaleX", 15f),
-                                LauncherAnimUtils.ofFloat(this, "scaleY", 15f),
-                                LauncherAnimUtils.ofFloat(this, "alpha", 0f)
-                            );
-
-                            // make sure things are still moving until the very last instant the
-                            // activity is visible
-                            s.setDuration((int)(LAUNCH_ZOOM_TIME * 1.25));
-                            s.setInterpolator(new android.view.animation.AccelerateInterpolator(3));
-                            s.start();
-                        }
-                        break;
-                }
-                return true;
-            }
-
-            public String toString() {
-                return String.format("<'%s' @ (%.1f, %.1f) v=%.1f a=%.1f dist/fuse=%.1f/%.1f>",
-                        "icon", getX(), getY(), v, angle, dist, fuse);
-            }
-
-            public void randomizeIcon() {
-                component = pick(mComponentNames);
-                setImageBitmap(mIcons.get(component));
-            }
-
-            public void randomize() {
-                v = randfrange(VMIN, VMAX);
-                angle = randfrange(0, 360f);
-                anglex = (float) Math.sin(angle / 180. * Math.PI);
-                angley = (float) Math.cos(angle / 180. * Math.PI);
-                vr = randfrange(ANGULAR_VMIN, ANGULAR_VMAX) * randsign();
-                endscale = randfrange(SCALE_MIN, SCALE_MAX);
-
-                randomizeIcon();
-            }
-            public void reset() {
-                randomize();
-                boardCenterX = (Board.this.getWidth() - getWidth()) / 2;
-                boardCenterY = (Board.this.getHeight() - getHeight()) / 2;
-                setX(boardCenterX);
-                setY(boardCenterY);
-                fuse = (float) Math.max(boardCenterX, boardCenterY);
-                setRotation(180-angle);
-                setScaleX(0f);
-                setScaleY(0f);
-                dist = 0;
-                setAlpha(0f);
-            }
-            public void update(float dt) {
-                dist += v * dt;
-                setX(getX() + anglex * v * dt);
-                setY(getY() + angley * v * dt);
-                //setRotation(getRotation() + vr * dt);
-                if (endscale > 0) {
-                    float scale = lerp(0, endscale, (float) Math.sqrt(dist / fuse));
-                        setScaleX(scale * lerp(1f, 0.75f, (float) Math.pow((v-VMIN)/(VMAX-VMIN),3)));
-                        setScaleY(scale * lerp(1f, 1.5f, (float) Math.pow((v-VMIN)/(VMAX-VMIN),3)));
-                    final float q1 = fuse*0.15f;
-                    final float q4 = fuse*0.75f;
-                    if (dist < q1) {
-                        setAlpha((float) Math.sqrt(dist/q1));
-                    } else if (dist > q4) {
-                        setAlpha((dist >= fuse) ? 0f : (1f-(float)Math.pow((dist-q4)/(fuse-q4),2)));
-                    } else {
-                        setAlpha(1f);
-                    }
-                }
-            }
-        }
-
-        public class FlyingStar extends FlyingIcon {
-            public FlyingStar(Context context, AttributeSet as) {
-                super(context, as);
-            }
-            public void randomizeIcon() {
-                setImageResource(R.drawable.widget_resize_handle_bottom);
-            }
-            public void randomize() {
-                super.randomize();
-                v = randfrange(VMAX*0.75f, VMAX*2f); // fasticate
-                endscale = randfrange(1f, 2f); // ensmallen
-            }
-        }
-
-        TimeAnimator mAnim;
-
-        public Board(Context context, AttributeSet as) {
-            super(context, as);
-
-            setBackgroundColor(0xFF000000);
-
-            LauncherApplication app = (LauncherApplication)context.getApplicationContext();
-            mIcons = app.getIconCache().getAllIcons();
-            mComponentNames = new ComponentName[mIcons.size()];
-            mComponentNames = mIcons.keySet().toArray(mComponentNames);
-        }
-
-        private void reset() {
-            removeAllViews();
-
-            final ViewGroup.LayoutParams wrap = new ViewGroup.LayoutParams(
-                        ViewGroup.LayoutParams.WRAP_CONTENT,
-                        ViewGroup.LayoutParams.WRAP_CONTENT);
-
-            if (FIXED_STARS) {
-                for(int i=0; i<20; i++) {
-                    ImageView fixedStar = new ImageView(getContext(), null);
-                    fixedStar.setImageResource(R.drawable.widget_resize_handle_bottom);
-                    final float s = randfrange(0.25f, 0.75f);
-                    fixedStar.setScaleX(s);
-                    fixedStar.setScaleY(s);
-                    fixedStar.setAlpha(0.75f);
-                    addView(fixedStar, wrap);
-                    fixedStar.setX(randfrange(0, getWidth()));
-                    fixedStar.setY(randfrange(0, getHeight()));
-                }
-            }
-
-            for(int i=0; i<NUM_ICONS*2; i++) {
-                FlyingIcon nv = (FLYING_STARS && (i < NUM_ICONS))
-                    ? new FlyingStar(getContext(), null)
-                    : new FlyingIcon(getContext(), null);
-                addView(nv, wrap);
-                nv.reset();
-            }
-
-            mAnim = new TimeAnimator();
-            mAnim.setTimeListener(new TimeAnimator.TimeListener() {
-                public void onTimeUpdate(TimeAnimator animation, long totalTime, long deltaTime) {
-                    // setRotation(totalTime * 0.01f); // not as cool as you would think
-
-                    final int START_ZOOM_TIME = 3000;
-                    if (totalTime < START_ZOOM_TIME) {
-                        final float x = totalTime/(float)START_ZOOM_TIME;
-                        final float s = 1f-(float)Math.pow(x-1, 4);
-                        setScaleX(s); setScaleY(s);
-                    } else {
-                        setScaleX(1.0f); setScaleY(1.0f);
-                    }
-
-                    if (mManeuveringThrusters) {
-                        if (mSpeedScale > MANEUVERING_THRUST_SCALE) {
-                            mSpeedScale -= (2*deltaTime/1000f);
-                        }
-                        if (mSpeedScale < MANEUVERING_THRUST_SCALE) {
-                            mSpeedScale = MANEUVERING_THRUST_SCALE;
-                        }
-                    } else {
-                        if (mSpeedScale < 1.0f) {
-                            mSpeedScale += (deltaTime/1000f);
-                        }
-                        if (mSpeedScale > 1.0f) {
-                            mSpeedScale = 1.0f;
-                        }
-                    }
-
-                    for (int i=0; i<getChildCount(); i++) {
-                        View v = getChildAt(i);
-                        if (!(v instanceof FlyingIcon)) continue;
-                        FlyingIcon nv = (FlyingIcon) v;
-                        nv.update(deltaTime / 1000f * mSpeedScale);
-                        final float scaledWidth = nv.getWidth() * nv.getScaleX();
-                        final float scaledHeight = nv.getHeight() * nv.getScaleY();
-                        if (   nv.getX() + scaledWidth < 0
-                            || nv.getX() - scaledWidth > getWidth()
-                            || nv.getY() + scaledHeight < 0 
-                            || nv.getY() - scaledHeight > getHeight())
-                        {
-                            nv.reset();
-                        }
-                    }
-                }
-            });
-        }
-
-        @Override
-        protected void onAttachedToWindow() {
-            super.onAttachedToWindow();
-            setLayerType(View.LAYER_TYPE_HARDWARE, null);
-            setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE);
-
-            reset();
-            mAnim.start();
-        }
-
-        protected void onSizeChanged (int w, int h, int oldw, int oldh) {
-            super.onSizeChanged(w,h,oldw,oldh);
-            mAnim.cancel();
-            reset();
-            mAnim.start();
-        }
-
-
-        @Override
-        protected void onDetachedFromWindow() {
-            super.onDetachedFromWindow();
-            mAnim.cancel();
-        }
-
-        @Override
-        public boolean isOpaque() {
-            return true;
-        }
-
-        @Override
-        public boolean onInterceptTouchEvent(MotionEvent e) {
-            // we want to eat touch events ourselves if we're in warp speed
-            return (!(ROCKET_LAUNCHER && mManeuveringThrusters));
-        }
-
-        final Runnable mEngageWarp = new Runnable() {
-            @Override
-            public void run() {
-                mManeuveringThrusters = false;
-            }
-        };
-        public void resetWarpTimer() {
-            final Handler h = getHandler();
-            h.removeCallbacks(mEngageWarp);
-            h.postDelayed(mEngageWarp, 5000);
-        }
-
-        @Override
-        public boolean onTouchEvent(MotionEvent event) {
-            if (!ROCKET_LAUNCHER) {
-                return true;
-            }
-
-            if (event.getAction() == MotionEvent.ACTION_DOWN) {
-                if (!mManeuveringThrusters) {
-                    mManeuveringThrusters = true;
-                    resetWarpTimer();
-                    return true;
-                }
-            }
-
-            return false;
-        }
-    }
-
-    @Override
-    public void onStart() {
-        super.onStart();
-
-        DisplayMetrics metrics = new DisplayMetrics();
-        getWindowManager().getDefaultDisplay().getMetrics(metrics);
-        final int longside = metrics.widthPixels > metrics.heightPixels 
-            ? metrics.widthPixels : metrics.heightPixels;
-
-        Board b = new Board(this, null);
-        setContentView(b, new ViewGroup.LayoutParams(longside, longside));
-        b.setX((metrics.widthPixels - longside) / 2);
-        b.setY((metrics.heightPixels - longside) / 2);
-    }
-
-    @Override
-    public void onUserInteraction() {
-        if (!ROCKET_LAUNCHER) {
-            finish();
-        }
-    }
-}