Merge "Initial changes for new clings. (Bug 11142616)" into jb-ub-now-indigo-rose
diff --git a/res/layout-port/workspace_cling.xml b/res/layout-port/workspace_cling.xml
index db33db0..e61340e 100644
--- a/res/layout-port/workspace_cling.xml
+++ b/res/layout-port/workspace_cling.xml
@@ -22,20 +22,15 @@
     <FrameLayout
         android:id="@+id/content"
         android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:layout_marginStart="25dp"
-        android:layout_marginEnd="25dp"
-        android:layout_marginTop="310dp">
+        android:layout_height="match_parent">
         <LinearLayout
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:layout_gravity="top"
+            android:layout_marginStart="25dp"
+            android:layout_marginEnd="25dp"
+            android:layout_marginTop="30dp"
             android:orientation="vertical">
-            <ImageView
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_gravity="center_horizontal"
-                android:src="@drawable/cling_arrow_up" />
             <LinearLayout
                 android:paddingLeft="20dp"
                 android:paddingRight="20dp"
@@ -56,14 +51,57 @@
                     android:layout_height="wrap_content"
                     android:text="@string/workspace_cling_move_item" />
             </LinearLayout>
+            <ImageView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center_horizontal"
+                android:src="@drawable/cling_arrow_down" />
+        </LinearLayout>
+
+        <LinearLayout
+            android:id="@+id/focused_hotseat_app_bubble"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="bottom|end"
+            android:layout_marginEnd="25dp"
+            android:layout_marginBottom="100dp"
+            android:orientation="vertical"
+            android:visibility="gone">
+            <LinearLayout
+                android:paddingLeft="20dp"
+                android:paddingRight="20dp"
+                android:paddingTop="20dp"
+                android:paddingBottom="20dp"
+                android:layout_width="240dp"
+                android:layout_height="wrap_content"
+                android:orientation="vertical"
+                android:background="@drawable/cling">
+                <TextView
+                    android:id="@+id/focused_hotseat_app_title"
+                    style="@style/ClingTitleText"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content" />
+                <TextView
+                    android:id="@+id/focused_hotseat_app_description"
+                    style="@style/ClingText"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content" />
+            </LinearLayout>
+            <ImageView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="end"
+                android:layout_marginEnd="80dp"
+                android:src="@drawable/cling_arrow_down" />
         </LinearLayout>
     </FrameLayout>
+
     <Button
         style="@style/ClingButton"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_marginBottom="15dp"
-        android:layout_marginEnd="20dp"
-        android:layout_gravity="bottom|end"
+        android:layout_marginStart="20dp"
+        android:layout_gravity="bottom|start"
         android:onClick="dismissWorkspaceCling" />
 </com.android.launcher3.Cling>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 7e5701b..a1d2c5c 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -61,7 +61,6 @@
         <item name="android:layout_height">wrap_content</item>
         <item name="android:textSize">24sp</item>
         <item name="android:textColor">#49C0EC</item>
-        <item name="android:fontFamily">sans-serif-condensed</item>
     </style>
     <style name="ClingText">
         <item name="android:layout_width">wrap_content</item>
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index e3312d5..dafb79f 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -169,6 +169,8 @@
     private static final int INVALID_DIRECTION = -100;
     private DropTarget.DragEnforcer mDragEnforcer;
 
+    private Rect mTempRect = new Rect();
+
     private final static PorterDuffXfermode sAddBlendMode =
             new PorterDuffXfermode(PorterDuff.Mode.ADD);
     private final static Paint sPaint = new Paint();
@@ -397,25 +399,6 @@
         }
     }
 
-    public void scaleRect(Rect r, float scale) {
-        if (scale != 1.0f) {
-            r.left = (int) (r.left * scale + 0.5f);
-            r.top = (int) (r.top * scale + 0.5f);
-            r.right = (int) (r.right * scale + 0.5f);
-            r.bottom = (int) (r.bottom * scale + 0.5f);
-        }
-    }
-
-    Rect temp = new Rect();
-    void scaleRectAboutCenter(Rect in, Rect out, float scale) {
-        int cx = in.centerX();
-        int cy = in.centerY();
-        out.set(in);
-        out.offset(-cx, -cy);
-        scaleRect(out, scale);
-        out.offset(cx, cy);
-    }
-
     @Override
     protected void onDraw(Canvas canvas) {
         // When we're large, we are either drawn in a "hover" state (ie when dragging an item to
@@ -443,10 +426,11 @@
             final float alpha = mDragOutlineAlphas[i];
             if (alpha > 0) {
                 final Rect r = mDragOutlines[i];
-                scaleRectAboutCenter(r, temp, getChildrenScale());
+                mTempRect.set(r);
+                Utilities.scaleRectAboutCenter(mTempRect, getChildrenScale());
                 final Bitmap b = (Bitmap) mDragOutlineAnims[i].getTag();
                 paint.setAlpha((int)(alpha + .5f));
-                canvas.drawBitmap(b, null, temp, paint);
+                canvas.drawBitmap(b, null, mTempRect, paint);
             }
         }
 
@@ -456,9 +440,13 @@
             final int padding = mPressedOrFocusedIcon.getPressedOrFocusedBackgroundPadding();
             final Bitmap b = mPressedOrFocusedIcon.getPressedOrFocusedBackground();
             if (b != null) {
+                int offset = getMeasuredWidth() - getPaddingLeft() - getPaddingRight() -
+                        (mCountX * mCellWidth);
+                int left = getPaddingLeft() + (int) Math.ceil(offset / 2f);
+                int top = getPaddingTop();
                 canvas.drawBitmap(b,
-                        mPressedOrFocusedIcon.getLeft() + getPaddingLeft() - padding,
-                        mPressedOrFocusedIcon.getTop() + getPaddingTop() - padding,
+                        mPressedOrFocusedIcon.getLeft() + left - padding,
+                        mPressedOrFocusedIcon.getTop() + top - padding,
                         null);
             }
         }
diff --git a/src/com/android/launcher3/Cling.java b/src/com/android/launcher3/Cling.java
index de92605..338b722 100644
--- a/src/com/android/launcher3/Cling.java
+++ b/src/com/android/launcher3/Cling.java
@@ -18,17 +18,13 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
+import android.app.ActivityOptions;
 import android.content.Context;
+import android.content.ComponentName;
+import android.content.Intent;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffXfermode;
-import android.graphics.Rect;
+import android.graphics.*;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
@@ -37,8 +33,10 @@
 import android.view.View;
 import android.view.animation.AccelerateInterpolator;
 import android.widget.FrameLayout;
+import android.widget.TextView;
 
-public class Cling extends FrameLayout implements Insettable, View.OnLongClickListener {
+public class Cling extends FrameLayout implements Insettable, View.OnClickListener,
+        View.OnLongClickListener, View.OnTouchListener {
 
     static final String FIRST_RUN_CLING_DISMISSED_KEY = "cling_gel.first_run.dismissed";
     static final String WORKSPACE_CLING_DISMISSED_KEY = "cling_gel.workspace.dismissed";
@@ -66,6 +64,12 @@
     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 mBubblePaint;
     private Paint mDotPaint;
@@ -100,6 +104,8 @@
             mScrimView = scrim;
             mBackgroundColor = 0xdd000000;
             setOnLongClickListener(this);
+            setOnClickListener(this);
+            setOnTouchListener(this);
 
             mErasePaint = new Paint();
             mErasePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));
@@ -121,6 +127,46 @@
         }
     }
 
+    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();
+        if (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,
+                    (grid.hotseatIconSize / grid.iconSize));
+
+            // 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 show(boolean animate, int duration) {
         setVisibility(View.VISIBLE);
         setLayerType(View.LAYER_TYPE_HARDWARE, null);
@@ -275,6 +321,32 @@
     };
 
     @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.dismissWorkspaceCling(this);
+            }
+        }
+    }
+
+    @Override
     public boolean onLongClick(View v) {
         if (mDrawIdentifier.equals(WORKSPACE_PORTRAIT) ||
                 mDrawIdentifier.equals(WORKSPACE_LANDSCAPE) ||
@@ -354,8 +426,16 @@
                 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);
+                }
+            }
 
             canvas.restore();
         }
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index 986a89b..1f876fd 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -20,12 +20,11 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
-import android.graphics.Bitmap;
+import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.LayoutInflater;
-import android.view.MotionEvent;
 import android.view.View;
 import android.widget.FrameLayout;
 import android.widget.TextView;
@@ -102,6 +101,25 @@
         }
     }
 
+    /** This returns the coordinates of an app in a given cell, relative to the DragLayer */
+    Rect getCellCoordinates(int cellX, int cellY) {
+        Rect coords = new Rect();
+        mContent.cellToRect(cellX, cellY, 1, 1, coords);
+        int[] hotseatInParent = new int[2];
+        Utilities.getDescendantCoordRelativeToParent(this, mLauncher.getDragLayer(),
+                hotseatInParent, false);
+        coords.offset(hotseatInParent[0], hotseatInParent[1]);
+
+        // Center the icon
+        int cWidth = mContent.getShortcutsAndWidgets().getCellContentWidth();
+        int cHeight = mContent.getShortcutsAndWidgets().getCellContentHeight();
+        int cellPaddingX = (int) Math.max(0, ((coords.width() - cWidth) / 2f));
+        int cellPaddingY = (int) Math.max(0, ((coords.height() - cHeight) / 2f));
+        coords.offset(cellPaddingX, cellPaddingY);
+
+        return coords;
+    }
+
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index afaf223..278b13c 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -4080,6 +4080,13 @@
             return false;
         }
 
+        // For now, limit only to phones
+        LauncherAppState app = LauncherAppState.getInstance();
+        DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
+        if (grid.isTablet()) {
+            return false;
+        }
+
         // disable clings when running in a test harness
         if(ActivityManager.isRunningInTestHarness()) return false;
 
@@ -4279,12 +4286,34 @@
     protected String getFirstRunCustomContentHint() {
         return "";
     }
+    protected int getFirstRunFocusedHotseatAppDrawableId() {
+        return -1;
+    }
+    protected ComponentName getFirstRunFocusedHotseatAppComponentName() {
+        return null;
+    }
+    protected int getFirstRunFocusedHotseatAppRank() {
+        return -1;
+    }
+    protected String getFirstRunFocusedHotseatAppBubbleTitle() {
+        return "";
+    }
+    protected String getFirstRunFocusedHotseatAppBubbleDescription() {
+        return "";
+    }
 
     public void showFirstRunWorkspaceCling() {
         // Enable the clings only if they have not been dismissed before
         if (isClingsEnabled() &&
                 !mSharedPrefs.getBoolean(Cling.WORKSPACE_CLING_DISMISSED_KEY, false)) {
-            initCling(R.id.workspace_cling, 0, false, true);
+            Cling c = initCling(R.id.workspace_cling, 0, false, true);
+
+            // Set the focused hotseat app if there is one
+            c.setFocusedHotseatApp(getFirstRunFocusedHotseatAppDrawableId(),
+                    getFirstRunFocusedHotseatAppRank(),
+                    getFirstRunFocusedHotseatAppComponentName(),
+                    getFirstRunFocusedHotseatAppBubbleTitle(),
+                    getFirstRunFocusedHotseatAppBubbleDescription());
         } else {
             removeCling(R.id.workspace_cling);
         }
@@ -4321,6 +4350,9 @@
         };
         dismissCling(cling, cb, Cling.FIRST_RUN_CLING_DISMISSED_KEY,
                 DISMISS_CLING_DURATION, false);
+
+        // Fade out the search bar for the workspace cling coming up
+        mSearchDropTargetBar.hideSearchBar(true);
     }
     public void dismissWorkspaceCling(View v) {
         Cling cling = (Cling) findViewById(R.id.workspace_cling);
@@ -4334,6 +4366,9 @@
         }
         dismissCling(cling, cb, Cling.WORKSPACE_CLING_DISMISSED_KEY,
                 DISMISS_CLING_DURATION, true);
+
+        // Fade in the search bar
+        mSearchDropTargetBar.showSearchBar(true);
     }
     public void dismissFolderCling(View v) {
         Cling cling = (Cling) findViewById(R.id.folder_cling);
diff --git a/src/com/android/launcher3/ShortcutAndWidgetContainer.java b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
index 1cf4c11..bb5601e 100644
--- a/src/com/android/launcher3/ShortcutAndWidgetContainer.java
+++ b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
@@ -123,6 +123,13 @@
         mIsHotseatLayout = isHotseat;
     }
 
+    int getCellContentWidth() {
+        final LauncherAppState app = LauncherAppState.getInstance();
+        final DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
+        return Math.min(getMeasuredHeight(), mIsHotseatLayout ?
+                grid.hotseatCellWidthPx: grid.cellWidthPx);
+    }
+
     int getCellContentHeight() {
         final LauncherAppState app = LauncherAppState.getInstance();
         final DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index b6900fe..2cb9314 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -295,6 +295,23 @@
         sIconTextureWidth = sIconTextureHeight = widthPx;
     }
 
+    public static void scaleRect(Rect r, float scale) {
+        if (scale != 1.0f) {
+            r.left = (int) (r.left * scale + 0.5f);
+            r.top = (int) (r.top * scale + 0.5f);
+            r.right = (int) (r.right * scale + 0.5f);
+            r.bottom = (int) (r.bottom * scale + 0.5f);
+        }
+    }
+
+    public static void scaleRectAboutCenter(Rect r, float scale) {
+        int cx = r.centerX();
+        int cy = r.centerY();
+        r.offset(-cx, -cy);
+        Utilities.scaleRect(r, scale);
+        r.offset(cx, cy);
+    }
+
     public static void startActivityForResultSafely(
             Activity activity, Intent intent, int requestCode) {
         try {