Updating clings, removing ununsed clings

issue: 16127412

Change-Id: I1d18515765100ff10d33439b3ac39ebfc5da35c7
diff --git a/src/com/android/launcher3/AppsCustomizePagedView.java b/src/com/android/launcher3/AppsCustomizePagedView.java
index 9f9c34b..03e1e56 100644
--- a/src/com/android/launcher3/AppsCustomizePagedView.java
+++ b/src/com/android/launcher3/AppsCustomizePagedView.java
@@ -170,11 +170,6 @@
     private ArrayList<AppInfo> mApps;
     private ArrayList<Object> mWidgets;
 
-    // Cling
-    private boolean mHasShownAllAppsCling;
-    private int mClingFocusedX;
-    private int mClingFocusedY;
-
     // Caching
     private IconCache mIconCache;
 
@@ -229,8 +224,6 @@
         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AppsCustomizePagedView, 0, 0);
         mWidgetCountX = a.getInt(R.styleable.AppsCustomizePagedView_widgetCountX, 2);
         mWidgetCountY = a.getInt(R.styleable.AppsCustomizePagedView_widgetCountY, 2);
-        mClingFocusedX = a.getInt(R.styleable.AppsCustomizePagedView_clingFocusedX, 0);
-        mClingFocusedY = a.getInt(R.styleable.AppsCustomizePagedView_clingFocusedY, 0);
         a.recycle();
         mWidgetSpacingLayout = new PagedViewCellLayout(getContext());
 
diff --git a/src/com/android/launcher3/ClearCircleLayout.java b/src/com/android/launcher3/ClearCircleLayout.java
new file mode 100644
index 0000000..e48c84e
--- /dev/null
+++ b/src/com/android/launcher3/ClearCircleLayout.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2014 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.launcher3;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Point;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.view.View;
+
+public class ClearCircleLayout extends View {
+
+    private static final String HOLE_LOCATION_PAGE_INDICATOR = "page_indicator";
+    private static final String HOLE_LOCATION_CENTER_SCREEN = "center_screen";
+
+    private static final int BACKGROUND_COLOR = 0x80000000;
+    private static float MIGRATION_WORKSPACE_INNER_CIRCLE_RADIUS_DPS = 42;
+    private static float MIGRATION_WORKSPACE_OUTER_CIRCLE_RADIUS_DPS = 46;
+
+    private final String mHoleLocation;
+    private final Paint mErasePaint;
+    private final Paint mBorderPaint;
+
+    private Launcher mLauncher;
+    private Point mHoleCenter;
+    private DisplayMetrics mMetrics;
+
+    public ClearCircleLayout(Context context, AttributeSet attrs) {
+        super(context, attrs);
+
+        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ClearCircleLayout);
+        mHoleLocation = a.getString(R.styleable.ClearCircleLayout_holeLocation);
+        a.recycle();
+
+        mErasePaint = new Paint();
+        mErasePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));
+        mErasePaint.setColor(0xFFFFFF);
+        mErasePaint.setAlpha(0);
+        mErasePaint.setAntiAlias(true);
+
+        mBorderPaint = new Paint();
+        mBorderPaint.setColor(0xFFFFFFFF);
+        mBorderPaint.setAntiAlias(true);
+    }
+
+    void initHole(Launcher launcher) {
+        mLauncher = launcher;
+        mMetrics = new DisplayMetrics();
+        launcher.getWindowManager().getDefaultDisplay().getMetrics(mMetrics);
+
+        if (mHoleLocation.endsWith(HOLE_LOCATION_PAGE_INDICATOR)) {
+            LauncherAppState app = LauncherAppState.getInstance();
+            DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
+
+            Rect indicator = grid.getWorkspacePageIndicatorBounds(new Rect());
+            mHoleCenter = new Point(indicator.centerX(), indicator.centerY());
+        } else if (mHoleLocation.endsWith(HOLE_LOCATION_CENTER_SCREEN)) {
+            mHoleCenter = new Point(mMetrics.widthPixels / 2, mMetrics.heightPixels / 2);
+        }
+    }
+
+    @Override
+    protected void dispatchDraw(Canvas canvas) {
+        if (mHoleCenter == null) {
+            canvas.drawColor(BACKGROUND_COLOR);
+        } else {
+            drawHole(canvas);
+        }
+
+        super.dispatchDraw(canvas);
+    }
+
+    private void drawHole(Canvas canvas) {
+        // Initialize the draw buffer (to allow punching through)
+        Bitmap eraseBg = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(),
+                Bitmap.Config.ARGB_8888);
+        Canvas eraseCanvas = new Canvas(eraseBg);
+        eraseCanvas.drawColor(BACKGROUND_COLOR);
+
+        Rect insets = mLauncher.getDragLayer().getInsets();
+        float x = mHoleCenter.x - insets.left;
+        float y = mHoleCenter.y - insets.top;
+        // Draw the outer circle
+        eraseCanvas.drawCircle(x, y,
+                DynamicGrid.pxFromDp(MIGRATION_WORKSPACE_OUTER_CIRCLE_RADIUS_DPS, mMetrics),
+                mBorderPaint);
+
+        // Draw the inner circle
+        eraseCanvas.drawCircle(x, y,
+                DynamicGrid.pxFromDp(MIGRATION_WORKSPACE_INNER_CIRCLE_RADIUS_DPS, mMetrics),
+                mErasePaint);
+
+        canvas.drawBitmap(eraseBg, 0, 0, null);
+        eraseCanvas.setBitmap(null);
+        eraseBg.recycle();
+    }
+}
diff --git a/src/com/android/launcher3/Cling.java b/src/com/android/launcher3/Cling.java
deleted file mode 100644
index a6139cc..0000000
--- a/src/com/android/launcher3/Cling.java
+++ /dev/null
@@ -1,571 +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.
- */
-
-package com.android.launcher3;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.graphics.*;
-import android.graphics.drawable.Drawable;
-import android.util.AttributeSet;
-import android.util.DisplayMetrics;
-import android.view.FocusFinder;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.animation.AccelerateInterpolator;
-import android.widget.FrameLayout;
-import android.widget.TextView;
-
-public class Cling extends FrameLayout implements Insettable, View.OnClickListener,
-        View.OnLongClickListener, View.OnTouchListener {
-
-    private static String FIRST_RUN_PORTRAIT = "first_run_portrait";
-    private static String FIRST_RUN_LANDSCAPE = "first_run_landscape";
-
-    private static String WORKSPACE_PORTRAIT = "workspace_portrait";
-    private static String WORKSPACE_LANDSCAPE = "workspace_landscape";
-    private static String WORKSPACE_LARGE = "workspace_large";
-    private static String WORKSPACE_CUSTOM = "workspace_custom";
-
-    private static String MIGRATION_PORTRAIT = "migration_portrait";
-    private static String MIGRATION_LANDSCAPE = "migration_landscape";
-
-    private static String MIGRATION_WORKSPACE_PORTRAIT = "migration_workspace_portrait";
-    private static String MIGRATION_WORKSPACE_LARGE_PORTRAIT = "migration_workspace_large_portrait";
-    private static String MIGRATION_WORKSPACE_LANDSCAPE = "migration_workspace_landscape";
-
-    private static String FOLDER_PORTRAIT = "folder_portrait";
-    private static String FOLDER_LANDSCAPE = "folder_landscape";
-    private static String FOLDER_LARGE = "folder_large";
-
-    private static float FIRST_RUN_CIRCLE_BUFFER_DPS = 60;
-    private static float FIRST_RUN_MAX_CIRCLE_RADIUS_DPS = 180;
-    private static float WORKSPACE_INNER_CIRCLE_RADIUS_DPS = 50;
-    private static float WORKSPACE_OUTER_CIRCLE_RADIUS_DPS = 60;
-    private static float WORKSPACE_CIRCLE_Y_OFFSET_DPS = 30;
-    private static float MIGRATION_WORKSPACE_INNER_CIRCLE_RADIUS_DPS = 42;
-    private static float MIGRATION_WORKSPACE_OUTER_CIRCLE_RADIUS_DPS = 46;
-
-    private Launcher mLauncher;
-    private boolean mIsInitialized;
-    private String mDrawIdentifier;
-    private Drawable mBackground;
-
-    private int[] mTouchDownPt = new int[2];
-
-    private Drawable mFocusedHotseatApp;
-    private ComponentName mFocusedHotseatAppComponent;
-    private Rect mFocusedHotseatAppBounds;
-
-    private Paint mErasePaint;
-    private Paint mBorderPaint;
-    private Paint mBubblePaint;
-    private Paint mDotPaint;
-
-    private View mScrimView;
-    private int mBackgroundColor;
-
-    private final Rect mInsets = new Rect();
-
-    public Cling(Context context) {
-        this(context, null, 0);
-    }
-
-    public Cling(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public Cling(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-
-        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Cling, defStyle, 0);
-        mDrawIdentifier = a.getString(R.styleable.Cling_drawIdentifier);
-        a.recycle();
-
-        setClickable(true);
-
-    }
-
-    void init(Launcher l, View scrim) {
-        if (!mIsInitialized) {
-            mLauncher = l;
-            mScrimView = scrim;
-            mBackgroundColor = 0xcc000000;
-            setOnLongClickListener(this);
-            setOnClickListener(this);
-            setOnTouchListener(this);
-
-            mErasePaint = new Paint();
-            mErasePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));
-            mErasePaint.setColor(0xFFFFFF);
-            mErasePaint.setAlpha(0);
-            mErasePaint.setAntiAlias(true);
-
-            mBorderPaint = new Paint();
-            mBorderPaint.setColor(0xFFFFFFFF);
-            mBorderPaint.setAntiAlias(true);
-
-            int circleColor = getResources().getColor(
-                    R.color.first_run_cling_circle_background_color);
-            mBubblePaint = new Paint();
-            mBubblePaint.setColor(circleColor);
-            mBubblePaint.setAntiAlias(true);
-
-            mDotPaint = new Paint();
-            mDotPaint.setColor(0x72BBED);
-            mDotPaint.setAntiAlias(true);
-
-            mIsInitialized = true;
-        }
-    }
-
-    void setFocusedHotseatApp(int drawableId, int appRank, ComponentName cn, String title,
-                              String description) {
-        // Get the app to draw
-        Resources r = getResources();
-        int appIconId = drawableId;
-        Hotseat hotseat = mLauncher.getHotseat();
-        // Skip the focused app in the large layouts
-        if (!mDrawIdentifier.equals(WORKSPACE_LARGE) &&
-                hotseat != null && appIconId > -1 && appRank > -1 && !title.isEmpty() &&
-                !description.isEmpty()) {
-            // Set the app bounds
-            int x = hotseat.getCellXFromOrder(appRank);
-            int y = hotseat.getCellYFromOrder(appRank);
-            Rect pos = hotseat.getCellCoordinates(x, y);
-            LauncherAppState app = LauncherAppState.getInstance();
-            DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
-            mFocusedHotseatApp = getResources().getDrawable(appIconId);
-            mFocusedHotseatAppComponent = cn;
-            mFocusedHotseatAppBounds = new Rect(pos.left, pos.top,
-                    pos.left + Utilities.sIconTextureWidth,
-                    pos.top + Utilities.sIconTextureHeight);
-            Utilities.scaleRectAboutCenter(mFocusedHotseatAppBounds,
-                    ((float) grid.hotseatIconSizePx / grid.iconSizePx));
-
-            // Set the title
-            TextView v = (TextView) findViewById(R.id.focused_hotseat_app_title);
-            if (v != null) {
-                v.setText(title);
-            }
-
-            // Set the description
-            v = (TextView) findViewById(R.id.focused_hotseat_app_description);
-            if (v != null) {
-                v.setText(description);
-            }
-
-            // Show the bubble
-            View bubble = findViewById(R.id.focused_hotseat_app_bubble);
-            bubble.setVisibility(View.VISIBLE);
-        }
-    }
-
-    void setOpenFolderRect(Rect r) {
-        if (mDrawIdentifier.equals(FOLDER_LANDSCAPE) ||
-            mDrawIdentifier.equals(FOLDER_LARGE)) {
-            ViewGroup vg = (ViewGroup) findViewById(R.id.folder_bubble);
-            ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) vg.getLayoutParams();
-            lp.topMargin = r.top - mInsets.bottom;
-            lp.leftMargin = r.right;
-            vg.setLayoutDirection(View.LAYOUT_DIRECTION_LTR);
-            vg.requestLayout();
-        }
-    }
-
-    void updateMigrationWorkspaceBubblePosition() {
-        DisplayMetrics metrics = new DisplayMetrics();
-        mLauncher.getWindowManager().getDefaultDisplay().getMetrics(metrics);
-
-        // Get the page indicator bounds
-        LauncherAppState app = LauncherAppState.getInstance();
-        DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
-        Rect pageIndicatorBounds = grid.getWorkspacePageIndicatorBounds(mInsets);
-
-        if (mDrawIdentifier.equals(MIGRATION_WORKSPACE_PORTRAIT)) {
-            View bubble = findViewById(R.id.migration_workspace_cling_bubble);
-            ViewGroup.MarginLayoutParams lp =
-                    (ViewGroup.MarginLayoutParams) bubble.getLayoutParams();
-            lp.bottomMargin = grid.heightPx - pageIndicatorBounds.top;
-            bubble.requestLayout();
-        } else if (mDrawIdentifier.equals(MIGRATION_WORKSPACE_LARGE_PORTRAIT)) {
-            View bubble = findViewById(R.id.content);
-            ViewGroup.MarginLayoutParams lp =
-                    (ViewGroup.MarginLayoutParams) bubble.getLayoutParams();
-            lp.bottomMargin = grid.heightPx - pageIndicatorBounds.top;
-            bubble.requestLayout();
-        } else if (mDrawIdentifier.equals(MIGRATION_WORKSPACE_LANDSCAPE)) {
-            View bubble = findViewById(R.id.content);
-            ViewGroup.MarginLayoutParams lp =
-                    (ViewGroup.MarginLayoutParams) bubble.getLayoutParams();
-            if (grid.isLayoutRtl) {
-                lp.leftMargin = pageIndicatorBounds.right;
-            } else {
-                lp.rightMargin = (grid.widthPx - pageIndicatorBounds.left);
-            }
-            bubble.requestLayout();
-        }
-    }
-
-    void updateWorkspaceBubblePosition() {
-        DisplayMetrics metrics = new DisplayMetrics();
-        mLauncher.getWindowManager().getDefaultDisplay().getMetrics(metrics);
-
-        // Get the cut-out bounds
-        LauncherAppState app = LauncherAppState.getInstance();
-        DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
-        Rect cutOutBounds = getWorkspaceCutOutBounds(metrics);
-
-        if (mDrawIdentifier.equals(WORKSPACE_LARGE)) {
-            View bubble = findViewById(R.id.workspace_cling_bubble);
-            ViewGroup.MarginLayoutParams lp =
-                    (ViewGroup.MarginLayoutParams) bubble.getLayoutParams();
-            lp.bottomMargin = grid.heightPx - cutOutBounds.top - mInsets.bottom;
-            bubble.requestLayout();
-        }
-    }
-
-    private Rect getWorkspaceCutOutBounds(DisplayMetrics metrics) {
-        int halfWidth = metrics.widthPixels / 2;
-        int halfHeight = metrics.heightPixels / 2;
-        int yOffset = DynamicGrid.pxFromDp(WORKSPACE_CIRCLE_Y_OFFSET_DPS, metrics);
-        if (mDrawIdentifier.equals(WORKSPACE_LARGE)) {
-            yOffset = 0;
-        }
-        int radius = DynamicGrid.pxFromDp(WORKSPACE_OUTER_CIRCLE_RADIUS_DPS, metrics);
-        return new Rect(halfWidth - radius, halfHeight - yOffset - radius, halfWidth + radius,
-                halfHeight - yOffset + radius);
-    }
-
-    void show(boolean animate, int duration) {
-        setVisibility(View.VISIBLE);
-        setLayerType(View.LAYER_TYPE_HARDWARE, null);
-        if (mDrawIdentifier.equals(WORKSPACE_PORTRAIT) ||
-                mDrawIdentifier.equals(WORKSPACE_LANDSCAPE) ||
-                mDrawIdentifier.equals(WORKSPACE_LARGE) ||
-                mDrawIdentifier.equals(WORKSPACE_CUSTOM) ||
-                mDrawIdentifier.equals(MIGRATION_WORKSPACE_PORTRAIT) ||
-                mDrawIdentifier.equals(MIGRATION_WORKSPACE_LARGE_PORTRAIT) ||
-                mDrawIdentifier.equals(MIGRATION_WORKSPACE_LANDSCAPE)) {
-            View content = getContent();
-            content.setAlpha(0f);
-            content.animate()
-                    .alpha(1f)
-                    .setDuration(duration)
-                    .setListener(null)
-                    .start();
-            setAlpha(1f);
-        } else {
-            if (animate) {
-                buildLayer();
-                setAlpha(0f);
-                animate()
-                    .alpha(1f)
-                    .setInterpolator(new AccelerateInterpolator())
-                    .setDuration(duration)
-                    .setListener(null)
-                    .start();
-            } else {
-                setAlpha(1f);
-            }
-        }
-
-        // Show the scrim if necessary
-        if (mScrimView != null) {
-            mScrimView.setVisibility(View.VISIBLE);
-            mScrimView.setAlpha(0f);
-            mScrimView.animate()
-                    .alpha(1f)
-                    .setDuration(duration)
-                    .setListener(null)
-                    .start();
-        }
-
-        setFocusableInTouchMode(true);
-        post(new Runnable() {
-            public void run() {
-                setFocusable(true);
-                requestFocus();
-            }
-        });
-    }
-
-    void hide(final int duration, final Runnable postCb) {
-        if (mDrawIdentifier.equals(FIRST_RUN_PORTRAIT) ||
-                mDrawIdentifier.equals(FIRST_RUN_LANDSCAPE) ||
-                mDrawIdentifier.equals(MIGRATION_PORTRAIT) ||
-                mDrawIdentifier.equals(MIGRATION_LANDSCAPE)) {
-            View content = getContent();
-            content.animate()
-                .alpha(0f)
-                .setDuration(duration)
-                .setListener(new AnimatorListenerAdapter() {
-                    public void onAnimationEnd(Animator animation) {
-                        // We are about to trigger the workspace cling, so don't do anything else
-                        setVisibility(View.GONE);
-                        postCb.run();
-                    };
-                })
-                .start();
-        } else {
-            animate()
-                .alpha(0f)
-                .setDuration(duration)
-                .setListener(new AnimatorListenerAdapter() {
-                    public void onAnimationEnd(Animator animation) {
-                        // We are about to trigger the workspace cling, so don't do anything else
-                        setVisibility(View.GONE);
-                        postCb.run();
-                    };
-                })
-                .start();
-        }
-
-        // Show the scrim if necessary
-        if (mScrimView != null) {
-            mScrimView.animate()
-                .alpha(0f)
-                .setDuration(duration)
-                .setListener(new AnimatorListenerAdapter() {
-                    public void onAnimationEnd(Animator animation) {
-                        mScrimView.setVisibility(View.GONE);
-                    };
-                })
-                .start();
-        }
-    }
-
-    void cleanup() {
-        mBackground = null;
-        mIsInitialized = false;
-    }
-
-    void bringScrimToFront() {
-        if (mScrimView != null) {
-            mScrimView.bringToFront();
-        }
-    }
-
-    @Override
-    public void setInsets(Rect insets) {
-        mInsets.set(insets);
-        setPadding(insets.left, insets.top, insets.right, insets.bottom);
-    }
-
-    View getContent() {
-        return findViewById(R.id.content);
-    }
-
-    String getDrawIdentifier() {
-        return mDrawIdentifier;
-    }
-
-    @Override
-    public View focusSearch(int direction) {
-        return this.focusSearch(this, direction);
-    }
-
-    @Override
-    public View focusSearch(View focused, int direction) {
-        return FocusFinder.getInstance().findNextFocus(this, focused, direction);
-    }
-
-    @Override
-    public boolean onHoverEvent(MotionEvent event) {
-        return (mDrawIdentifier.equals(WORKSPACE_PORTRAIT)
-                || mDrawIdentifier.equals(WORKSPACE_LANDSCAPE)
-                || mDrawIdentifier.equals(WORKSPACE_LARGE)
-                || mDrawIdentifier.equals(WORKSPACE_CUSTOM));
-    }
-
-    @Override
-    public boolean onTouchEvent(android.view.MotionEvent event) {
-        if (mDrawIdentifier.equals(FOLDER_PORTRAIT) ||
-                   mDrawIdentifier.equals(FOLDER_LANDSCAPE) ||
-                   mDrawIdentifier.equals(FOLDER_LARGE)) {
-            Folder f = mLauncher.getWorkspace().getOpenFolder();
-            if (f != null) {
-                Rect r = new Rect();
-                f.getHitRect(r);
-                if (r.contains((int) event.getX(), (int) event.getY())) {
-                    return false;
-                }
-            }
-        }
-        return super.onTouchEvent(event);
-    };
-
-    @Override
-    public boolean onTouch(View v, MotionEvent ev) {
-        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
-            mTouchDownPt[0] = (int) ev.getX();
-            mTouchDownPt[1] = (int) ev.getY();
-        }
-        return false;
-    }
-
-    @Override
-    public void onClick(View v) {
-        if (mDrawIdentifier.equals(WORKSPACE_PORTRAIT) ||
-                mDrawIdentifier.equals(WORKSPACE_LANDSCAPE) ||
-                mDrawIdentifier.equals(WORKSPACE_LARGE)) {
-            if (mFocusedHotseatAppBounds != null &&
-                mFocusedHotseatAppBounds.contains(mTouchDownPt[0], mTouchDownPt[1])) {
-                // Launch the activity that is being highlighted
-                Intent intent = new Intent(Intent.ACTION_MAIN);
-                intent.setComponent(mFocusedHotseatAppComponent);
-                intent.addCategory(Intent.CATEGORY_LAUNCHER);
-                mLauncher.startActivity(intent, null);
-                mLauncher.getLauncherClings().dismissWorkspaceCling(this);
-            }
-        }
-    }
-
-    @Override
-    public boolean onLongClick(View v) {
-        if (mDrawIdentifier.equals(WORKSPACE_PORTRAIT) ||
-                mDrawIdentifier.equals(WORKSPACE_LANDSCAPE) ||
-                mDrawIdentifier.equals(WORKSPACE_LARGE)) {
-            mLauncher.getLauncherClings().dismissWorkspaceCling(null);
-            return true;
-        } else if (mDrawIdentifier.equals(MIGRATION_WORKSPACE_PORTRAIT) ||
-                mDrawIdentifier.equals(MIGRATION_WORKSPACE_LARGE_PORTRAIT) ||
-                mDrawIdentifier.equals(MIGRATION_WORKSPACE_LANDSCAPE)) {
-            mLauncher.getLauncherClings().dismissMigrationWorkspaceCling(null);
-            return true;
-        }
-        return false;
-    }
-
-    @Override
-    protected void dispatchDraw(Canvas canvas) {
-        if (mIsInitialized) {
-            canvas.save();
-
-            // Get the page indicator bounds
-            LauncherAppState app = LauncherAppState.getInstance();
-            DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
-            Rect pageIndicatorBounds = grid.getWorkspacePageIndicatorBounds(mInsets);
-
-            // Get the background override if there is one
-            if (mBackground == null) {
-                if (mDrawIdentifier.equals(WORKSPACE_CUSTOM)) {
-                    mBackground = getResources().getDrawable(R.drawable.bg_cling5);
-                }
-            }
-            // Draw the background
-            Bitmap eraseBg = null;
-            Canvas eraseCanvas = null;
-            if (mScrimView != null) {
-                // Skip drawing the background
-                mScrimView.setBackgroundColor(mBackgroundColor);
-            } else if (mBackground != null) {
-                mBackground.setBounds(0, 0, getMeasuredWidth(), getMeasuredHeight());
-                mBackground.draw(canvas);
-            } else if (mDrawIdentifier.equals(WORKSPACE_PORTRAIT) ||
-                    mDrawIdentifier.equals(WORKSPACE_LANDSCAPE) ||
-                    mDrawIdentifier.equals(WORKSPACE_LARGE) ||
-                    mDrawIdentifier.equals(MIGRATION_WORKSPACE_PORTRAIT) ||
-                    mDrawIdentifier.equals(MIGRATION_WORKSPACE_LARGE_PORTRAIT) ||
-                    mDrawIdentifier.equals(MIGRATION_WORKSPACE_LANDSCAPE)) {
-                // Initialize the draw buffer (to allow punching through)
-                eraseBg = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(),
-                        Bitmap.Config.ARGB_8888);
-                eraseCanvas = new Canvas(eraseBg);
-                eraseCanvas.drawColor(mBackgroundColor);
-            } else {
-                canvas.drawColor(mBackgroundColor);
-            }
-
-            // Draw everything else
-            DisplayMetrics metrics = new DisplayMetrics();
-            mLauncher.getWindowManager().getDefaultDisplay().getMetrics(metrics);
-            float alpha = getAlpha();
-            View content = getContent();
-            if (content != null) {
-                alpha *= content.getAlpha();
-            }
-            if (mDrawIdentifier.equals(FIRST_RUN_PORTRAIT) ||
-                    mDrawIdentifier.equals(FIRST_RUN_LANDSCAPE)) {
-                // Draw the circle
-                View bubbleContent = findViewById(R.id.bubble_content);
-                Rect bubbleRect = new Rect();
-                bubbleContent.getGlobalVisibleRect(bubbleRect);
-                mBubblePaint.setAlpha((int) (255 * alpha));
-                float buffer = DynamicGrid.pxFromDp(FIRST_RUN_CIRCLE_BUFFER_DPS, metrics);
-                float maxRadius = DynamicGrid.pxFromDp(FIRST_RUN_MAX_CIRCLE_RADIUS_DPS, metrics);
-                float radius = Math.min(maxRadius, (bubbleContent.getMeasuredWidth() + buffer) / 2);
-                canvas.drawCircle(metrics.widthPixels / 2,
-                        bubbleRect.centerY(), radius,
-                        mBubblePaint);
-            } else if (mDrawIdentifier.equals(WORKSPACE_PORTRAIT) ||
-                    mDrawIdentifier.equals(WORKSPACE_LANDSCAPE) ||
-                    mDrawIdentifier.equals(WORKSPACE_LARGE)) {
-                Rect cutOutBounds = getWorkspaceCutOutBounds(metrics);
-                // Draw the outer circle
-                mErasePaint.setAlpha(128);
-                eraseCanvas.drawCircle(cutOutBounds.centerX(), cutOutBounds.centerY(),
-                        DynamicGrid.pxFromDp(WORKSPACE_OUTER_CIRCLE_RADIUS_DPS, metrics),
-                        mErasePaint);
-                // Draw the inner circle
-                mErasePaint.setAlpha(0);
-                eraseCanvas.drawCircle(cutOutBounds.centerX(), cutOutBounds.centerY(),
-                        DynamicGrid.pxFromDp(WORKSPACE_INNER_CIRCLE_RADIUS_DPS, metrics),
-                        mErasePaint);
-                canvas.drawBitmap(eraseBg, 0, 0, null);
-                eraseCanvas.setBitmap(null);
-                eraseBg = null;
-
-                // Draw the focused hotseat app icon
-                if (mFocusedHotseatAppBounds != null && mFocusedHotseatApp != null) {
-                    mFocusedHotseatApp.setBounds(mFocusedHotseatAppBounds.left,
-                            mFocusedHotseatAppBounds.top, mFocusedHotseatAppBounds.right,
-                            mFocusedHotseatAppBounds.bottom);
-                    mFocusedHotseatApp.setAlpha((int) (255 * alpha));
-                    mFocusedHotseatApp.draw(canvas);
-                }
-            } else if (mDrawIdentifier.equals(MIGRATION_WORKSPACE_PORTRAIT) ||
-                    mDrawIdentifier.equals(MIGRATION_WORKSPACE_LARGE_PORTRAIT) ||
-                    mDrawIdentifier.equals(MIGRATION_WORKSPACE_LANDSCAPE)) {
-                int offset = DynamicGrid.pxFromDp(WORKSPACE_CIRCLE_Y_OFFSET_DPS, metrics);
-                // Draw the outer circle
-                eraseCanvas.drawCircle(pageIndicatorBounds.centerX(),
-                        pageIndicatorBounds.centerY(),
-                        DynamicGrid.pxFromDp(MIGRATION_WORKSPACE_OUTER_CIRCLE_RADIUS_DPS, metrics),
-                        mBorderPaint);
-                // Draw the inner circle
-                mErasePaint.setAlpha(0);
-                eraseCanvas.drawCircle(pageIndicatorBounds.centerX(),
-                        pageIndicatorBounds.centerY(),
-                        DynamicGrid.pxFromDp(MIGRATION_WORKSPACE_INNER_CIRCLE_RADIUS_DPS, metrics),
-                        mErasePaint);
-                canvas.drawBitmap(eraseBg, 0, 0, null);
-                eraseCanvas.setBitmap(null);
-                eraseBg = null;
-            }
-            canvas.restore();
-        }
-
-        // Draw the rest of the cling
-        super.dispatchDraw(canvas);
-    };
-}
diff --git a/src/com/android/launcher3/DragLayer.java b/src/com/android/launcher3/DragLayer.java
index 79cb1f9..a8a61ea 100644
--- a/src/com/android/launcher3/DragLayer.java
+++ b/src/com/android/launcher3/DragLayer.java
@@ -132,6 +132,10 @@
         return true; // I'll take it from here
     }
 
+    Rect getInsets() {
+        return mInsets;
+    }
+
     @Override
     public void addView(View child, int index, android.view.ViewGroup.LayoutParams params) {
         super.addView(child, index, params);
@@ -200,8 +204,7 @@
         }
 
         Folder currentFolder = mLauncher.getWorkspace().getOpenFolder();
-        if (currentFolder != null && !mLauncher.getLauncherClings().isFolderClingVisible() &&
-                intercept) {
+        if (currentFolder != null && intercept) {
             if (currentFolder.isEditingName()) {
                 if (!isEventOverFolderTextRegion(currentFolder, ev)) {
                     currentFolder.dismissEditingName();
diff --git a/src/com/android/launcher3/Folder.java b/src/com/android/launcher3/Folder.java
index f26f87c..6bd4e0e 100644
--- a/src/com/android/launcher3/Folder.java
+++ b/src/com/android/launcher3/Folder.java
@@ -248,8 +248,6 @@
                 return false;
             }
 
-            mLauncher.getLauncherClings().dismissFolderCling(null);
-
             mLauncher.getWorkspace().beginDragShared(v, this);
 
             mCurrentDragInfo = item;
@@ -553,15 +551,6 @@
                     onCompleteRunnable.run();
                 }
 
-                // Only show cling if we are not in the middle of a drag - this would be quite jarring.
-                if (!mDragController.isDragging()) {
-                    Cling cling = mLauncher.getLauncherClings().showFoldersCling();
-                    if (cling != null) {
-                        cling.bringScrimToFront();
-                        bringToFront();
-                        cling.bringToFront();
-                    }
-                }
                 setFocusOnFirstChild();
             }
         });
diff --git a/src/com/android/launcher3/HideFromAccessibilityHelper.java b/src/com/android/launcher3/HideFromAccessibilityHelper.java
deleted file mode 100644
index 75cbb1b..0000000
--- a/src/com/android/launcher3/HideFromAccessibilityHelper.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2012 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.launcher3;
-
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewGroup.OnHierarchyChangeListener;
-
-import java.util.HashMap;
-
-public class HideFromAccessibilityHelper implements OnHierarchyChangeListener {
-    private HashMap<View, Integer> mPreviousValues;
-    boolean mHide;
-    boolean mOnlyAllApps;
-
-    public HideFromAccessibilityHelper() {
-        mPreviousValues = new HashMap<View, Integer>();
-        mHide = false;
-    }
-
-    public void setImportantForAccessibilityToNo(View v, boolean onlyAllApps) {
-        mOnlyAllApps = onlyAllApps;
-        setImportantForAccessibilityToNoHelper(v);
-        mHide = true;
-    }
-
-    private void setImportantForAccessibilityToNoHelper(View v) {
-        mPreviousValues.put(v, v.getImportantForAccessibility());
-        v.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
-
-        // Call method on children recursively
-        if (v instanceof ViewGroup) {
-            ViewGroup vg = (ViewGroup) v;
-            vg.setOnHierarchyChangeListener(this);
-            for (int i = 0; i < vg.getChildCount(); i++) {
-                View child = vg.getChildAt(i);
-
-                if (includeView(child)) {
-                    setImportantForAccessibilityToNoHelper(child);
-                }
-            }
-        }
-    }
-
-    public void restoreImportantForAccessibility(View v) {
-        if (mHide) {
-            restoreImportantForAccessibilityHelper(v);
-        }
-        mHide = false;
-    }
-
-    private void restoreImportantForAccessibilityHelper(View v) {
-        Integer important = mPreviousValues.get(v);
-        v.setImportantForAccessibility(important);
-        mPreviousValues.remove(v);
-
-        // Call method on children recursively
-        if (v instanceof ViewGroup) {
-            ViewGroup vg = (ViewGroup) v;
-
-            // We assume if a class implements OnHierarchyChangeListener, it listens
-            // to changes to any of its children (happens to be the case in Launcher)
-            if (vg instanceof OnHierarchyChangeListener) {
-                vg.setOnHierarchyChangeListener((OnHierarchyChangeListener) vg);
-            } else {
-                vg.setOnHierarchyChangeListener(null);
-            }
-            for (int i = 0; i < vg.getChildCount(); i++) {
-                View child = vg.getChildAt(i);
-                if (includeView(child)) {
-                    restoreImportantForAccessibilityHelper(child);
-                }
-            }
-        }
-    }
-
-    public void onChildViewAdded(View parent, View child) {
-        if (mHide && includeView(child)) {
-            setImportantForAccessibilityToNoHelper(child);
-        }
-    }
-
-    public void onChildViewRemoved(View parent, View child) {
-        if (mHide && includeView(child)) {
-            restoreImportantForAccessibilityHelper(child);
-        }
-    }
-
-    private boolean includeView(View v) {
-        return !hasAncestorOfType(v, Cling.class) &&
-                (!mOnlyAllApps || hasAncestorOfType(v, AppsCustomizeTabHost.class));
-    }
-
-    private boolean hasAncestorOfType(View v, Class c) {
-        return v != null &&
-                (v.getClass().equals(c) ||
-                 (v.getParent() instanceof ViewGroup &&
-                  hasAncestorOfType((ViewGroup) v.getParent(), c)));
-    }
-}
\ No newline at end of file
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 8a3ce25..e134d1b 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -126,7 +126,6 @@
 import java.util.List;
 import java.util.concurrent.atomic.AtomicInteger;
 
-
 /**
  * Default launcher application.
  */
@@ -256,7 +255,6 @@
     private DragLayer mDragLayer;
     private DragController mDragController;
     private View mWeightWatcher;
-    private LauncherClings mLauncherClings;
 
     private AppWidgetManagerCompat mAppWidgetManager;
     private LauncherAppWidgetHost mAppWidgetHost;
@@ -434,7 +432,6 @@
         mIconCache = app.getIconCache();
         mIconCache.flushInvalidIcons(grid);
         mDragController = new DragController(this);
-        mLauncherClings = new LauncherClings(this);
         mInflater = getLayoutInflater();
 
         mStats = new Stats(this);
@@ -504,14 +501,13 @@
         // The two first run cling paths are mutually exclusive, if the launcher is preinstalled
         // on the device, then we always show the first run cling experience (or if there is no
         // launcher2). Otherwise, we prompt the user upon started for migration
-        if (mLauncherClings.shouldShowFirstRunOrMigrationClings()) {
+        LauncherClings launcherClings = new LauncherClings(this);
+        if (launcherClings.shouldShowFirstRunOrMigrationClings()) {
             if (mModel.canMigrateFromOldLauncherDb(this)) {
-                mLauncherClings.showMigrationCling();
+                launcherClings.showMigrationCling();
             } else {
-                mLauncherClings.showFirstRunCling();
+                launcherClings.showLongPressCling(true);
             }
-        } else {
-            mLauncherClings.removeFirstRunAndMigrationClings();
         }
     }
 
@@ -1849,10 +1845,6 @@
         return mModel;
     }
 
-    public LauncherClings getLauncherClings() {
-        return mLauncherClings;
-    }
-
     protected SharedPreferences getSharedPrefs() {
         return mSharedPrefs;
     }
@@ -2977,9 +2969,6 @@
                 folder.dismissEditingName();
             }
             closeFolder(folder);
-
-            // Dismiss the folder cling
-            mLauncherClings.dismissFolderCling(null);
         }
     }
 
@@ -4757,7 +4746,7 @@
      * @param hint the hint to be displayed in the search bar.
      */
     protected void onSearchBarHintChanged(String hint) {
-        mLauncherClings.updateSearchBarHint(hint);
+
     }
 
     protected boolean isLauncherPreinstalled() {
@@ -4808,28 +4797,6 @@
         return "";
     }
 
-    public void dismissFirstRunCling(View v) {
-        mLauncherClings.dismissFirstRunCling(v);
-    }
-    public void dismissMigrationClingCopyApps(View v) {
-        mLauncherClings.dismissMigrationClingCopyApps(v);
-    }
-    public void dismissMigrationClingUseDefault(View v) {
-        mLauncherClings.dismissMigrationClingUseDefault(v);
-    }
-    public void dismissMigrationWorkspaceCling(View v) {
-        mLauncherClings.dismissMigrationWorkspaceCling(v);
-    }
-    public void dismissWorkspaceCling(View v) {
-        mLauncherClings.dismissWorkspaceCling(v);
-    }
-    public void dismissFolderCling(View v) {
-        mLauncherClings.dismissFolderCling(v);
-    }
-    public void markFolderClingDismissedIfNecessary() {
-        mLauncherClings.markFolderClingDismissedIfNecessary();
-    }
-
     /**
      * To be overridden by subclasses to indicate that there is an activity to launch
      * before showing the standard launcher experience.
diff --git a/src/com/android/launcher3/LauncherClings.java b/src/com/android/launcher3/LauncherClings.java
index 00586bd..840fb52 100644
--- a/src/com/android/launcher3/LauncherClings.java
+++ b/src/com/android/launcher3/LauncherClings.java
@@ -18,31 +18,31 @@
 
 import android.accounts.Account;
 import android.accounts.AccountManager;
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.animation.ValueAnimator;
 import android.app.ActivityManager;
-import android.content.ComponentName;
 import android.content.Context;
 import android.content.SharedPreferences;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.UserManager;
 import android.provider.Settings;
+import android.view.ContextThemeWrapper;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.View.OnLongClickListener;
 import android.view.ViewGroup;
+import android.view.ViewTreeObserver.OnGlobalLayoutListener;
 import android.view.accessibility.AccessibilityManager;
-import android.widget.TextView;
 
-class LauncherClings {
-    private static final String FIRST_RUN_CLING_DISMISSED_KEY = "cling_gel.first_run.dismissed";
+class LauncherClings implements OnClickListener {
     private static final String MIGRATION_CLING_DISMISSED_KEY = "cling_gel.migration.dismissed";
-    private static final String MIGRATION_WORKSPACE_CLING_DISMISSED_KEY =
-            "cling_gel.migration_workspace.dismissed";
     private static final String WORKSPACE_CLING_DISMISSED_KEY = "cling_gel.workspace.dismissed";
-    private static final String FOLDER_CLING_DISMISSED_KEY = "cling_gel.folder.dismissed";
+
+    private static final String ANIM_SLIDE_FROM_BOTTOM = "slide_from_bottom";
+    private static final String ANIM_SLIDE_FROM_TOP = "slide_from_top";
 
     private static final boolean DISABLE_CLINGS = false;
 
@@ -54,33 +54,169 @@
 
     private Launcher mLauncher;
     private LayoutInflater mInflater;
-    private HideFromAccessibilityHelper mHideFromAccessibilityHelper
-            = new HideFromAccessibilityHelper();
 
     /** Ctor */
     public LauncherClings(Launcher launcher) {
         mLauncher = launcher;
-        mInflater = mLauncher.getLayoutInflater();
+        mInflater = LayoutInflater.from(new
+                ContextThemeWrapper(mLauncher, android.R.style.Theme_DeviceDefault));
     }
 
-    /** Initializes a cling */
-    private Cling initCling(int clingId, int scrimId, boolean animate,
-                            boolean dimNavBarVisibilty) {
-        Cling cling = (Cling) mLauncher.findViewById(clingId);
-        View scrim = null;
-        if (scrimId > 0) {
-            scrim = mLauncher.findViewById(scrimId);
+    @Override
+    public void onClick(View v) {
+        int id = v.getId();
+        if (id == R.id.cling_dismiss_migration_use_default) {
+            // Disable the migration cling
+            dismissMigrationCling();
+        } else if (id == R.id.cling_dismiss_migration_copy_apps) {
+            // Copy the shortcuts from the old database
+            LauncherModel model = mLauncher.getModel();
+            model.resetLoadedState(false, true);
+            model.startLoader(false, PagedView.INVALID_RESTORE_PAGE,
+                    LauncherModel.LOADER_FLAG_CLEAR_WORKSPACE
+                            | LauncherModel.LOADER_FLAG_MIGRATE_SHORTCUTS);
+            // Set the flag to skip the folder cling
+            String spKey = LauncherAppState.getSharedPreferencesKey();
+            SharedPreferences sp = mLauncher.getSharedPreferences(spKey, Context.MODE_PRIVATE);
+            SharedPreferences.Editor editor = sp.edit();
+            editor.putBoolean(Launcher.USER_HAS_MIGRATED, true);
+            editor.apply();
+            // Disable the migration cling
+            dismissMigrationCling();
+        } else if (id == R.id.cling_dismiss_longpress_info) {
+            dismissLongPressCling();
         }
-        if (cling != null) {
-            cling.init(mLauncher, scrim);
-            cling.show(animate, SHOW_CLING_DURATION);
+    }
 
-            if (dimNavBarVisibilty) {
-                cling.setSystemUiVisibility(cling.getSystemUiVisibility() |
-                        View.SYSTEM_UI_FLAG_LOW_PROFILE);
+    /**
+     * Shows the migration cling.
+     *
+     * This flow is mutually exclusive with showFirstRunCling, and only runs if this Launcher
+     * package was not preinstalled and there exists a db to migrate from.
+     */
+    public void showMigrationCling() {
+        mLauncher.hideWorkspaceSearchAndHotseat();
+
+        ViewGroup root = (ViewGroup) mLauncher.findViewById(R.id.launcher);
+        View inflated = mInflater.inflate(R.layout.migration_cling, root);
+        inflated.findViewById(R.id.cling_dismiss_migration_copy_apps).setOnClickListener(this);
+        inflated.findViewById(R.id.cling_dismiss_migration_use_default).setOnClickListener(this);
+    }
+
+    private void dismissMigrationCling() {
+        mLauncher.showWorkspaceSearchAndHotseat();
+        Runnable dismissCb = new Runnable() {
+            public void run() {
+                Runnable cb = new Runnable() {
+                    public void run() {
+                        // Show the longpress cling next
+                        showLongPressCling(false);
+                    }
+                };
+                dismissCling(mLauncher.findViewById(R.id.migration_cling), cb,
+                        MIGRATION_CLING_DISMISSED_KEY, DISMISS_CLING_DURATION);
+            }
+        };
+        mLauncher.getWorkspace().post(dismissCb);
+    }
+
+    public void showLongPressCling(boolean showWelcome) {
+        ViewGroup root = (ViewGroup) mLauncher.findViewById(R.id.launcher);
+        View cling = mInflater.inflate(R.layout.longpress_cling, root, false);
+
+        final ClearCircleLayout hole = (ClearCircleLayout) cling.findViewById(R.id.cling_longpress_hole);
+        hole.initHole(mLauncher);
+        hole.setClickable(true);
+        hole.setOnLongClickListener(new OnLongClickListener() {
+
+            @Override
+            public boolean onLongClick(View v) {
+                mLauncher.getWorkspace().enterOverviewMode();
+                dismissLongPressCling();
+                return true;
+            }
+        });
+
+        final ViewGroup content = (ViewGroup) cling.findViewById(R.id.cling_content);
+        mInflater.inflate(showWelcome ? R.layout.longpress_cling_welcome_content
+                : R.layout.longpress_cling_content, content);
+        content.findViewById(R.id.cling_dismiss_longpress_info).setOnClickListener(this);
+
+        root.addView(cling);
+
+        if (showWelcome) {
+            // This is the first cling being shown. No need to animate.
+            return;
+        }
+
+        // Animate
+        content.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
+
+            @Override
+            public void onGlobalLayout() {
+                content.getViewTreeObserver().removeOnGlobalLayoutListener(this);
+
+                hole.setAlpha(0);
+                ValueAnimator anim1 = LauncherAnimUtils.ofFloat(hole, "alpha", 1);
+
+                ObjectAnimator anim2;
+
+                if (ANIM_SLIDE_FROM_TOP.equals(content.getTag())) {
+                    content.setTranslationY(-content.getMeasuredHeight());
+                    anim2 = LauncherAnimUtils.ofFloat(content, "translationY", 0);
+                } else if (ANIM_SLIDE_FROM_BOTTOM.equals(content.getTag())) {
+                    content.setTranslationY(content.getMeasuredHeight());
+                    anim2 = LauncherAnimUtils.ofFloat(content, "translationY", 0);
+                } else {
+                    content.setScaleX(0);
+                    content.setScaleY(0);
+                    PropertyValuesHolder scaleX = PropertyValuesHolder.ofFloat("scaleX", 1);
+                    PropertyValuesHolder scaleY = PropertyValuesHolder.ofFloat("scaleY", 1);
+                    anim2 = LauncherAnimUtils.ofPropertyValuesHolder(content, scaleX, scaleY);
+                }
+
+                AnimatorSet anim = LauncherAnimUtils.createAnimatorSet();
+                anim.setDuration(SHOW_CLING_DURATION);
+                anim.setInterpolator(new LogDecelerateInterpolator(100, 0));
+                anim.playTogether(anim1, anim2);
+                anim.start();
+            }
+        });
+    }
+
+    private void dismissLongPressCling() {
+        Runnable dismissCb = new Runnable() {
+            public void run() {
+                dismissCling(mLauncher.findViewById(R.id.longpress_cling), null,
+                        WORKSPACE_CLING_DISMISSED_KEY, DISMISS_CLING_DURATION);
+            }
+        };
+        mLauncher.getWorkspace().post(dismissCb);
+    }
+
+    /** Hides the specified Cling */
+    private void dismissCling(final View cling, final Runnable postAnimationCb,
+                              final String flag, int duration) {
+        // To catch cases where siblings of top-level views are made invisible, just check whether
+        // the cling is directly set to GONE before dismissing it.
+        if (cling != null && cling.getVisibility() != View.GONE) {
+            final Runnable cleanUpClingCb = new Runnable() {
+                public void run() {
+                    cling.setVisibility(View.GONE);
+                    mLauncher.getSharedPrefs().edit()
+                        .putBoolean(flag, true)
+                        .apply();
+                    if (postAnimationCb != null) {
+                        postAnimationCb.run();
+                    }
+                }
+            };
+            if (duration <= 0) {
+                cleanUpClingCb.run();
+            } else {
+                cling.animate().alpha(0).setDuration(duration).withEndAction(cleanUpClingCb);
             }
         }
-        return cling;
     }
 
     /** Returns whether the clings are enabled or should be shown */
@@ -118,346 +254,18 @@
         return true;
     }
 
-    /** Returns whether the folder cling is visible. */
-    public boolean isFolderClingVisible() {
-        Cling cling = (Cling) mLauncher.findViewById(R.id.folder_cling);
-        if (cling != null) {
-            return cling.getVisibility() == View.VISIBLE;
-        }
-        return false;
-    }
-
-    private boolean skipCustomClingIfNoAccounts() {
-        Cling cling = (Cling) mLauncher.findViewById(R.id.workspace_cling);
-        boolean customCling = cling.getDrawIdentifier().equals("workspace_custom");
-        if (customCling) {
-            AccountManager am = AccountManager.get(mLauncher);
-            if (am == null) return false;
-            Account[] accounts = am.getAccountsByType("com.google");
-            return accounts.length == 0;
-        }
-        return false;
-    }
-
-    /** Updates the first run cling custom content hint */
-    private void setCustomContentHintVisibility(Cling cling, String ccHintStr, boolean visible,
-                                                boolean animate) {
-        final TextView ccHint = (TextView) cling.findViewById(R.id.custom_content_hint);
-        if (ccHint != null) {
-            if (visible && !ccHintStr.isEmpty()) {
-                ccHint.setText(ccHintStr);
-                ccHint.setVisibility(View.VISIBLE);
-                if (animate) {
-                    ccHint.setAlpha(0f);
-                    ccHint.animate().alpha(1f)
-                            .setDuration(SHOW_CLING_DURATION)
-                            .start();
-                } else {
-                    ccHint.setAlpha(1f);
-                }
-            } else {
-                if (animate) {
-                    ccHint.animate().alpha(0f)
-                            .setDuration(SHOW_CLING_DURATION)
-                            .setListener(new AnimatorListenerAdapter() {
-                                @Override
-                                public void onAnimationEnd(Animator animation) {
-                                    ccHint.setVisibility(View.GONE);
-                                }
-                            })
-                            .start();
-                } else {
-                    ccHint.setAlpha(0f);
-                    ccHint.setVisibility(View.GONE);
-                }
-            }
-        }
-    }
-
-    /** Updates the first run cling custom content hint */
-    public void updateCustomContentHintVisibility() {
-        Cling cling = (Cling) mLauncher.findViewById(R.id.first_run_cling);
-        String ccHintStr = mLauncher.getFirstRunCustomContentHint();
-
-        if (mLauncher.getWorkspace().hasCustomContent()) {
-            // Show the custom content hint if ccHintStr is not empty
-            if (cling != null) {
-                setCustomContentHintVisibility(cling, ccHintStr, true, true);
-            }
-        } else {
-            // Hide the custom content hint
-            if (cling != null) {
-                setCustomContentHintVisibility(cling, ccHintStr, false, true);
-            }
-        }
-    }
-
-    /** Updates the first run cling search bar hint. */
-    public void updateSearchBarHint(String hint) {
-        Cling cling = (Cling) mLauncher.findViewById(R.id.first_run_cling);
-        if (cling != null && cling.getVisibility() == View.VISIBLE && !hint.isEmpty()) {
-            TextView sbHint = (TextView) cling.findViewById(R.id.search_bar_hint);
-            sbHint.setText(hint);
-            sbHint.setVisibility(View.VISIBLE);
-        }
-    }
-
     public boolean shouldShowFirstRunOrMigrationClings() {
         SharedPreferences sharedPrefs = mLauncher.getSharedPrefs();
         return areClingsEnabled() &&
-            !sharedPrefs.getBoolean(FIRST_RUN_CLING_DISMISSED_KEY, false) &&
+            !sharedPrefs.getBoolean(WORKSPACE_CLING_DISMISSED_KEY, false) &&
             !sharedPrefs.getBoolean(MIGRATION_CLING_DISMISSED_KEY, false);
     }
 
-    public void removeFirstRunAndMigrationClings() {
-        removeCling(R.id.first_run_cling);
-        removeCling(R.id.migration_cling);
-    }
-
-    /**
-     * Shows the first run cling.
-     *
-     * This flow is mutually exclusive with showMigrationCling, and only runs if this Launcher
-     * package was preinstalled or there is no db to migrate from.
-     */
-    public void showFirstRunCling() {
-        if (!skipCustomClingIfNoAccounts()) {
-            Cling cling = (Cling) mLauncher.findViewById(R.id.first_run_cling);
-            if (cling != null) {
-                String sbHintStr = mLauncher.getFirstRunClingSearchBarHint();
-                String ccHintStr = mLauncher.getFirstRunCustomContentHint();
-                if (!sbHintStr.isEmpty()) {
-                    TextView sbHint = (TextView) cling.findViewById(R.id.search_bar_hint);
-                    sbHint.setText(sbHintStr);
-                    sbHint.setVisibility(View.VISIBLE);
-                }
-                setCustomContentHintVisibility(cling, ccHintStr, true, false);
-            }
-            initCling(R.id.first_run_cling, 0, false, true);
-        } else {
-            removeFirstRunAndMigrationClings();
-        }
-    }
-
-    /**
-     * Shows the migration cling.
-     *
-     * This flow is mutually exclusive with showFirstRunCling, and only runs if this Launcher
-     * package was not preinstalled and there exists a db to migrate from.
-     */
-    public void showMigrationCling() {
-        mLauncher.hideWorkspaceSearchAndHotseat();
-
-        Cling c = initCling(R.id.migration_cling, 0, false, true);
-        c.bringScrimToFront();
-        c.bringToFront();
-    }
-
-    public void showMigrationWorkspaceCling() {
-        // Enable the clings only if they have not been dismissed before
-        if (areClingsEnabled() && !mLauncher.getSharedPrefs().getBoolean(
-                MIGRATION_WORKSPACE_CLING_DISMISSED_KEY, false)) {
-            Cling c = initCling(R.id.migration_workspace_cling, 0, false, true);
-            c.updateMigrationWorkspaceBubblePosition();
-            c.bringScrimToFront();
-            c.bringToFront();
-        } else {
-            removeCling(R.id.migration_workspace_cling);
-        }
-    }
-
-    public void showWorkspaceCling() {
-        // Enable the clings only if they have not been dismissed before
-        if (areClingsEnabled() && !mLauncher.getSharedPrefs().getBoolean(
-                WORKSPACE_CLING_DISMISSED_KEY, false)) {
-            Cling c = initCling(R.id.workspace_cling, 0, false, true);
-            c.updateWorkspaceBubblePosition();
-            if (mLauncher.shouldClingFocusHotseatApp()) {
-                // Set the focused hotseat app
-                c.setFocusedHotseatApp(mLauncher.getFirstRunFocusedHotseatAppDrawableId(),
-                    mLauncher.getFirstRunFocusedHotseatAppRank(),
-                    mLauncher.getFirstRunFocusedHotseatAppComponentName(),
-                    mLauncher.getFirstRunFocusedHotseatAppBubbleTitle(),
-                    mLauncher.getFirstRunFocusedHotseatAppBubbleDescription());
-            }
-        } else {
-            removeCling(R.id.workspace_cling);
-        }
-    }
-
-    public Cling showFoldersCling() {
-        SharedPreferences sharedPrefs = mLauncher.getSharedPrefs();
-        // Enable the clings only if they have not been dismissed before
-        if (areClingsEnabled() &&
-                !sharedPrefs.getBoolean(FOLDER_CLING_DISMISSED_KEY, false) &&
-                !sharedPrefs.getBoolean(Launcher.USER_HAS_MIGRATED, false)) {
-            Cling cling = initCling(R.id.folder_cling, R.id.cling_scrim,
-                    true, true);
-            Folder openFolder = mLauncher.getWorkspace().getOpenFolder();
-            if (openFolder != null) {
-                Rect openFolderRect = new Rect();
-                openFolder.getHitRect(openFolderRect);
-                cling.setOpenFolderRect(openFolderRect);
-                openFolder.bringToFront();
-            }
-            return cling;
-        } else {
-            removeCling(R.id.folder_cling);
-            return null;
-        }
-    }
-
     public static void synchonouslyMarkFirstRunClingDismissed(Context ctx) {
         SharedPreferences prefs = ctx.getSharedPreferences(
                 LauncherAppState.getSharedPreferencesKey(), Context.MODE_PRIVATE);
         SharedPreferences.Editor editor = prefs.edit();
-        editor.putBoolean(LauncherClings.FIRST_RUN_CLING_DISMISSED_KEY, true);
+        editor.putBoolean(WORKSPACE_CLING_DISMISSED_KEY, true);
         editor.commit();
     }
-
-    /** Removes the cling outright from the DragLayer */
-    private void removeCling(int id) {
-        final View cling = mLauncher.findViewById(id);
-        if (cling != null) {
-            final ViewGroup parent = (ViewGroup) cling.getParent();
-            parent.post(new Runnable() {
-                @Override
-                public void run() {
-                    parent.removeView(cling);
-                }
-            });
-            mHideFromAccessibilityHelper.restoreImportantForAccessibility(mLauncher.getDragLayer());
-        }
-    }
-
-    /** Hides the specified Cling */
-    private void dismissCling(final Cling cling, final Runnable postAnimationCb,
-                              final String flag, int duration, boolean restoreNavBarVisibilty) {
-        // To catch cases where siblings of top-level views are made invisible, just check whether
-        // the cling is directly set to GONE before dismissing it.
-        if (cling != null && cling.getVisibility() != View.GONE) {
-            final Runnable cleanUpClingCb = new Runnable() {
-                public void run() {
-                    cling.cleanup();
-                    SharedPreferences.Editor editor = mLauncher.getSharedPrefs().edit();
-                    editor.putBoolean(flag, true);
-                    editor.apply();
-                    if (postAnimationCb != null) {
-                        postAnimationCb.run();
-                    }
-                }
-            };
-            if (duration <= 0) {
-                cleanUpClingCb.run();
-            } else {
-                cling.hide(duration, cleanUpClingCb);
-            }
-            mHideFromAccessibilityHelper.restoreImportantForAccessibility(mLauncher.getDragLayer());
-
-            if (restoreNavBarVisibilty) {
-                cling.setSystemUiVisibility(cling.getSystemUiVisibility() &
-                        ~View.SYSTEM_UI_FLAG_LOW_PROFILE);
-            }
-        }
-    }
-
-    public void dismissFirstRunCling(View v) {
-        Cling cling = (Cling) mLauncher.findViewById(R.id.first_run_cling);
-        Runnable cb = new Runnable() {
-            public void run() {
-                // Show the workspace cling next
-                showWorkspaceCling();
-            }
-        };
-        dismissCling(cling, cb, FIRST_RUN_CLING_DISMISSED_KEY,
-                DISMISS_CLING_DURATION, false);
-
-        // Fade out the search bar for the workspace cling coming up
-        mLauncher.getSearchBar().hideSearchBar(true);
-    }
-
-    private void dismissMigrationCling() {
-        mLauncher.showWorkspaceSearchAndHotseat();
-        Runnable dismissCb = new Runnable() {
-            public void run() {
-                Cling cling = (Cling) mLauncher.findViewById(R.id.migration_cling);
-                Runnable cb = new Runnable() {
-                    public void run() {
-                        // Show the migration workspace cling next
-                        showMigrationWorkspaceCling();
-                    }
-                };
-                dismissCling(cling, cb, MIGRATION_CLING_DISMISSED_KEY,
-                        DISMISS_CLING_DURATION, true);
-            }
-        };
-        mLauncher.getWorkspace().post(dismissCb);
-    }
-
-    private void dismissAnyWorkspaceCling(Cling cling, String key, View v) {
-        Runnable cb = null;
-        if (v == null) {
-            cb = new Runnable() {
-                public void run() {
-                    mLauncher.getWorkspace().enterOverviewMode();
-                }
-            };
-        }
-        dismissCling(cling, cb, key, DISMISS_CLING_DURATION, true);
-
-        // Fade in the search bar
-        mLauncher.getSearchBar().showSearchBar(true);
-    }
-
-    public void markFolderClingDismissedIfNecessary() {
-        SharedPreferences prefs = mLauncher.getSharedPrefs();
-        if (!prefs.getBoolean(FOLDER_CLING_DISMISSED_KEY, false)) {
-            SharedPreferences.Editor editor = prefs.edit();
-            editor.putBoolean(FOLDER_CLING_DISMISSED_KEY, true);
-            editor.apply();
-        }
-    }
-
-    public void dismissMigrationClingCopyApps(View v) {
-        // Copy the shortcuts from the old database
-        LauncherModel model = mLauncher.getModel();
-        model.resetLoadedState(false, true);
-        model.startLoader(false, PagedView.INVALID_RESTORE_PAGE,
-                LauncherModel.LOADER_FLAG_CLEAR_WORKSPACE
-                        | LauncherModel.LOADER_FLAG_MIGRATE_SHORTCUTS);
-
-        // Set the flag to skip the folder cling
-        String spKey = LauncherAppState.getSharedPreferencesKey();
-        SharedPreferences sp = mLauncher.getSharedPreferences(spKey, Context.MODE_PRIVATE);
-        SharedPreferences.Editor editor = sp.edit();
-        editor.putBoolean(Launcher.USER_HAS_MIGRATED, true);
-        editor.apply();
-
-        // Disable the migration cling
-        dismissMigrationCling();
-    }
-
-    public void dismissMigrationClingUseDefault(View v) {
-        // Don't need to do anything special here. We've already loaded the default workspace,
-        // (which is the default loader behavior triggered from Launcher#onCreate.).
-
-        // Disable the migration cling
-        dismissMigrationCling();
-    }
-
-    public void dismissMigrationWorkspaceCling(View v) {
-        Cling cling = (Cling) mLauncher.findViewById(R.id.migration_workspace_cling);
-        dismissAnyWorkspaceCling(cling, MIGRATION_WORKSPACE_CLING_DISMISSED_KEY, v);
-    }
-
-    public void dismissWorkspaceCling(View v) {
-        Cling cling = (Cling) mLauncher.findViewById(R.id.workspace_cling);
-        dismissAnyWorkspaceCling(cling, WORKSPACE_CLING_DISMISSED_KEY, v);
-    }
-
-    public void dismissFolderCling(View v) {
-        Cling cling = (Cling) mLauncher.findViewById(R.id.folder_cling);
-        dismissCling(cling, null, FOLDER_CLING_DISMISSED_KEY,
-                DISMISS_CLING_DURATION, true);
-    }
 }
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 6d21701..8661251 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -596,7 +596,6 @@
         mDefaultPage = mOriginalDefaultPage + 1;
 
         // Update the custom content hint
-        mLauncher.getLauncherClings().updateCustomContentHintVisibility();
         if (mRestorePage != INVALID_RESTORE_PAGE) {
             mRestorePage = mRestorePage + 1;
         } else {
@@ -625,7 +624,6 @@
         mDefaultPage = mOriginalDefaultPage - 1;
 
         // Update the custom content hint
-        mLauncher.getLauncherClings().updateCustomContentHintVisibility();
         if (mRestorePage != INVALID_RESTORE_PAGE) {
             mRestorePage = mRestorePage - 1;
         } else {
@@ -2702,10 +2700,6 @@
         if (child instanceof BubbleTextView) {
             BubbleTextView icon = (BubbleTextView) child;
             icon.clearPressedBackground();
-        } else if (child instanceof FolderIcon) {
-            // The folder cling isn't flexible enough to be shown in non-default workspace positions
-            // Also if they are dragging it a folder, we assume they don't need to see the cling.
-            mLauncher.markFolderClingDismissedIfNecessary();
         }
 
         if (child.getTag() == null || !(child.getTag() instanceof ItemInfo)) {
@@ -3053,10 +3047,6 @@
                 // cell also contains a shortcut, then create a folder with the two shortcuts.
                 if (!mInScrollArea && createUserFolderIfNecessary(cell, container,
                         dropTargetLayout, mTargetCell, distance, false, d.dragView, null)) {
-                    // The folder cling isn't flexible enough to be shown in non-default workspace
-                    // positions. Also if they are creating a folder, we assume they don't need to
-                    // see the cling.
-                    mLauncher.markFolderClingDismissedIfNecessary();
                     return;
                 }
 
@@ -3965,10 +3955,6 @@
                 d.postAnimationRunnable = exitSpringLoadedRunnable;
                 if (createUserFolderIfNecessary(view, container, cellLayout, mTargetCell, distance,
                         true, d.dragView, d.postAnimationRunnable)) {
-                    // The folder cling isn't flexible enough to be shown in non-default workspace
-                    // positions. Also if they are creating a folder, we assume they don't need to
-                    // see the cling.
-                    mLauncher.markFolderClingDismissedIfNecessary();
                     return;
                 }
                 if (addToExistingFolderIfNecessary(view, cellLayout, mTargetCell, distance, d,