Merge "Fixing issue where we were not clearing the set of removed items since the last event. (Bug 6749258)"
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index 4b769aa..9f48ef2 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -21,13 +21,13 @@
     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="uid_name" msgid="3371120195364560632">"برنامه های Android Core"</string>
+    <string name="uid_name" msgid="3371120195364560632">"برنامه‌های Android Core"</string>
     <string name="folder_name" msgid="8551881338202938211"></string>
     <string name="chooser_wallpaper" msgid="6063168087625352235">"انتخاب تصویر زمینه از"</string>
     <string name="wallpaper_instructions" msgid="4215640646180727542">"تنظیم تصویر زمینه"</string>
     <string name="pick_wallpaper" msgid="5630222540525626723">"تصاویر زمینه"</string>
     <string name="activity_not_found" msgid="217823393239365967">"برنامه نصب نشده است."</string>
-    <string name="widgets_tab_label" msgid="9145860100000983599">"ابزارک ها"</string>
+    <string name="widgets_tab_label" msgid="9145860100000983599">"ابزارک‌ها"</string>
     <string name="long_press_widget_to_add" msgid="7395697462851217506">"برای انتخاب یک ابزارک لمس کنید و نگه دارید."</string>
     <string name="market" msgid="2652226429823445833">"فروشگاه"</string>
     <string name="external_drop_widget_error" msgid="2285187188524172774">"این مورد را نمی‌توان در این صفحهٔ اصلی رها کرد."</string>
@@ -39,7 +39,7 @@
     <string name="menu_item_add_item" msgid="6233177331075781114">"افزودن به صفحهٔ اصلی"</string>
     <string name="group_applications" msgid="2103752818818161976">"برنامه‌ها"</string>
     <string name="group_shortcuts" msgid="9133529424900391877">"میانبرها"</string>
-    <string name="group_widgets" msgid="6704978494073105844">"ابزارک ها"</string>
+    <string name="group_widgets" msgid="6704978494073105844">"ابزارک‌ها"</string>
     <string name="group_wallpapers" msgid="1568191644272224858">"تصاویر زمینه"</string>
     <string name="completely_out_of_space" msgid="1759078539443491182">"فضای بیشتری در صفحات نمایش اصلی شما موجود نیست."</string>
     <string name="out_of_space" msgid="8365249326091984698">"اتاق دیگری در این صفحهٔ اصلی موجود نیست."</string>
@@ -50,7 +50,7 @@
     <string name="shortcut_duplicate" msgid="4757756326465060694">"میانبر \"<xliff:g id="NAME">%s</xliff:g>\" در حال حاضر وجود دارد."</string>
     <string name="title_select_shortcut" msgid="1873670208166882222">"انتخاب میانبر"</string>
     <string name="title_select_application" msgid="1793455815754848652">"انتخاب برنامه"</string>
-    <string name="all_apps_button_label" msgid="2578400570124163469">"برنامه های کاربردی"</string>
+    <string name="all_apps_button_label" msgid="2578400570124163469">"برنامه‌های کاربردی"</string>
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"صفحهٔ اصلی"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"حذف"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"حذف نصب"</string>
@@ -63,7 +63,7 @@
     <string name="accessibility_delete_button" msgid="3628162007991023603">"حذف"</string>
     <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"حذف نصب به‌روزرسانی"</string>
     <string name="menu_add" msgid="3065046628354640854">"افزودن"</string>
-    <string name="menu_manage_apps" msgid="2308685199463588895">"مدیریت برنامه ها"</string>
+    <string name="menu_manage_apps" msgid="2308685199463588895">"مدیریت برنامه‌ها"</string>
     <string name="menu_wallpaper" msgid="5837429080911269832">"تصویر زمینه"</string>
     <string name="menu_search" msgid="4826514464423239041">"جستجو"</string>
     <string name="menu_notifications" msgid="6424587053194766192">"اعلان‌ها"</string>
diff --git a/src/com/android/launcher2/AppWidgetResizeFrame.java b/src/com/android/launcher2/AppWidgetResizeFrame.java
index e8b1dc0..2070eb6 100644
--- a/src/com/android/launcher2/AppWidgetResizeFrame.java
+++ b/src/com/android/launcher2/AppWidgetResizeFrame.java
@@ -53,6 +53,9 @@
     private int mBackgroundPadding;
     private int mTouchTargetWidth;
 
+    private int mTopTouchRegionAdjustment = 0;
+    private int mBottomTouchRegionAdjustment = 0;
+
     int[] mDirectionVector = new int[2];
 
     final int SNAP_DURATION = 150;
@@ -139,10 +142,12 @@
     public boolean beginResizeIfPointInRegion(int x, int y) {
         boolean horizontalActive = (mResizeMode & AppWidgetProviderInfo.RESIZE_HORIZONTAL) != 0;
         boolean verticalActive = (mResizeMode & AppWidgetProviderInfo.RESIZE_VERTICAL) != 0;
+
         mLeftBorderActive = (x < mTouchTargetWidth) && horizontalActive;
         mRightBorderActive = (x > getWidth() - mTouchTargetWidth) && horizontalActive;
-        mTopBorderActive = (y < mTouchTargetWidth) && verticalActive;
-        mBottomBorderActive = (y > getHeight() - mTouchTargetWidth) && verticalActive;
+        mTopBorderActive = (y < mTouchTargetWidth + mTopTouchRegionAdjustment) && verticalActive;
+        mBottomBorderActive = (y > getHeight() - mTouchTargetWidth + mBottomTouchRegionAdjustment)
+                && verticalActive;
 
         boolean anyBordersActive = mLeftBorderActive || mRightBorderActive
                 || mTopBorderActive || mBottomBorderActive;
@@ -378,13 +383,20 @@
         int newX = mWidgetView.getLeft() - mBackgroundPadding + xOffset + mWidgetPaddingLeft;
         int newY = mWidgetView.getTop() - mBackgroundPadding + yOffset + mWidgetPaddingTop;
 
-        // We need to make sure the frame stays within the bounds of the CellLayout
+        // We need to make sure the frame's touchable regions lie fully within the bounds of the 
+        // DragLayer. We allow the actual handles to be clipped, but we shift the touch regions
+        // down accordingly to provide a proper touch target.
         if (newY < 0) {
-            newHeight -= -newY;
-            newY = 0;
+            // In this case we shift the touch region down to start at the top of the DragLayer
+            mTopTouchRegionAdjustment = -newY;
+        } else {
+            mTopTouchRegionAdjustment = 0;
         }
         if (newY + newHeight > mDragLayer.getHeight()) {
-            newHeight -= newY + newHeight - mDragLayer.getHeight();
+            // In this case we shift the touch region up to end at the bottom of the DragLayer
+            mBottomTouchRegionAdjustment = -(newY + newHeight - mDragLayer.getHeight());
+        } else {
+            mBottomTouchRegionAdjustment = 0;
         }
 
         if (!animate) {
diff --git a/src/com/android/launcher2/CellLayout.java b/src/com/android/launcher2/CellLayout.java
index aa8c132..3ad1336 100644
--- a/src/com/android/launcher2/CellLayout.java
+++ b/src/com/android/launcher2/CellLayout.java
@@ -1538,7 +1538,6 @@
         int x = cellX + direction[0];
         int y = cellY + direction[1];
         while (x >= 0 && x + spanX <= mCountX && y >= 0 && y + spanY <= mCountY) {
-
             boolean fail = false;
             for (int i = 0; i < spanX; i++) {
                 for (int j = 0; j < spanY; j++) {
@@ -1581,8 +1580,9 @@
         return success;
     }
 
-    // This method looks in the specified direction to see if there is an additional view
-    // immediately adjecent in that direction
+    // This method looks in the specified direction to see if there are additional views adjacent
+    // to the current set of views in the. If there is, then these views are added to the current
+    // set of views. This is performed iteratively, giving a cascading push behaviour.
     private boolean addViewInDirection(ArrayList<View> views, Rect boundingRect, int[] direction,
             boolean[][] occupied, View dragView, ItemConfiguration currentState) {
         boolean found = false;
@@ -1591,23 +1591,27 @@
         Rect r0 = new Rect(boundingRect);
         Rect r1 = new Rect();
 
+        // First, we consider the rect of the views that we are trying to translate
         int deltaX = 0;
         int deltaY = 0;
         if (direction[1] < 0) {
-            r0.set(r0.left, r0.top - 1, r0.right, r0.bottom);
+            r0.set(r0.left, r0.top - 1, r0.right, r0.bottom - 1);
             deltaY = -1;
         } else if (direction[1] > 0) {
-            r0.set(r0.left, r0.top, r0.right, r0.bottom + 1);
+            r0.set(r0.left, r0.top + 1, r0.right, r0.bottom + 1);
             deltaY = 1;
         } else if (direction[0] < 0) {
-            r0.set(r0.left - 1, r0.top, r0.right, r0.bottom);
+            r0.set(r0.left - 1, r0.top, r0.right - 1, r0.bottom);
             deltaX = -1;
         } else if (direction[0] > 0) {
-            r0.set(r0.left, r0.top, r0.right + 1, r0.bottom);
+            r0.set(r0.left + 1, r0.top, r0.right + 1, r0.bottom);
             deltaX = 1;
         }
 
+        // Now we see which views, if any, are being overlapped by shifting the current group
+        // of views in the desired direction.
         for (int i = 0; i < childCount; i++) {
+            // We don't need to worry about views already in our group, or the current drag view.
             View child = mShortcutsAndWidgets.getChildAt(i);
             if (views.contains(child) || child == dragView) continue;
             CellAndSpan c = currentState.map.get(child);
@@ -1618,20 +1622,30 @@
                 if (!lp.canReorder) {
                     return false;
                 }
-                boolean pushed = false;
-                for (int x = c.x; x < c.x + c.spanX; x++) {
-                    for (int y = c.y; y < c.y + c.spanY; y++) {
-                        boolean inBounds = x - deltaX >= 0 && x -deltaX < mCountX
-                                && y - deltaY >= 0 && y - deltaY < mCountY;
-                        if (inBounds && occupied[x - deltaX][y - deltaY]) {
-                            pushed = true;
+                // First we verify that the view in question is at the border of the extents
+                // of the block of items we are pushing
+                if ((direction[0] < 0 && c.x == r0.left) ||
+                        (direction[0] > 0 && c.x == r0.right - 1) ||
+                        (direction[1] < 0 && c.y == r0.top) ||
+                        (direction[1] > 0 && c.y == r0.bottom - 1)) {
+                    boolean pushed = false;
+                    // Since the bounding rect is a course description of the region (there can
+                    // be holes at the edge of the block), we need to check to verify that a solid
+                    // piece is intersecting. This ensures that interlocking is possible.
+                    for (int x = c.x; x < c.x + c.spanX; x++) {
+                        for (int y = c.y; y < c.y + c.spanY; y++) {
+                            if (occupied[x - deltaX][y - deltaY]) {
+                                pushed = true;
+                                break;
+                            }
+                            if (pushed) break;
                         }
                     }
-                }
-                if (pushed) {
-                    views.add(child);
-                    boundingRect.union(c.x, c.y, c.x + c.spanX, c.y + c.spanY);
-                    found = true;
+                    if (pushed) {
+                        views.add(child);
+                        boundingRect.union(c.x, c.y, c.x + c.spanX, c.y + c.spanY);
+                        found = true;
+                    }
                 }
             }
         }
@@ -1672,7 +1686,7 @@
         int top = boundingRect.top;
         int left = boundingRect.left;
         // We mark more precisely which parts of the bounding rect are truly occupied, allowing
-        // for tetris-style interlocking.
+        // for interlocking.
         for (View v: dup) {
             CellAndSpan c = currentState.map.get(v);
             markCellsForView(c.x - left, c.y - top, c.spanX, c.spanY, blockOccupied, true);