Merge "Updating launcher transitions."
diff --git a/res/values-sw600dp/config.xml b/res/values-sw600dp/config.xml
index a701e69..00b2e15 100644
--- a/res/values-sw600dp/config.xml
+++ b/res/values-sw600dp/config.xml
@@ -1,4 +1,6 @@
 <resources>
+    <bool name="allow_rotation">true</bool>
+
     <integer name="cell_count_x">6</integer>
     <integer name="cell_count_y">6</integer>
     <integer name="hotseat_cell_count">7</integer>
diff --git a/res/values/config.xml b/res/values/config.xml
index 2a75af8..1890125 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -2,6 +2,7 @@
     <bool name="config_hardwareAccelerated">true</bool>
     <bool name="config_largeHeap">false</bool>
     <bool name="is_large_screen">false</bool>
+    <bool name="allow_rotation">false</bool>
 
 <!-- AllApps/Customize/AppsCustomize -->
     <!-- The alpha of the AppsCustomize bg in spring loaded mode -->
diff --git a/res/values/strings.xml b/res/values/strings.xml
index f707c8c..7e9d12c 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -81,8 +81,10 @@
     <string name="group_widgets">Widgets</string>
     <!-- Options in "Add to Home" dialog box; Title of the group containing the list of apps that can set the wallpaper-->
     <string name="group_wallpapers">Wallpapers</string>
-    <!-- Error message when user has filled a home screen, possibly not used -->
-    <string name="out_of_space">No more room on your Home screens.</string>
+    <!-- Error message when user has filled all their home screens -->
+    <string name="completely_out_of_space">No more room on your Home screens.</string>
+    <!-- Error message when user has filled a home screen -->
+    <string name="out_of_space">No more room on this Home screen.</string>
     <!-- Error message when user has filled the hotseat -->
     <string name="hotseat_out_of_space">No more room on the hotseat.</string>
     <!-- Error message when user tries to drop an invalid item on the hotseat -->
diff --git a/src/com/android/launcher2/DropTarget.java b/src/com/android/launcher2/DropTarget.java
index 397d462..d627a4c 100644
--- a/src/com/android/launcher2/DropTarget.java
+++ b/src/com/android/launcher2/DropTarget.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.graphics.PointF;
 import android.graphics.Rect;
+import android.util.Log;
 
 /**
  * Interface defining an object that can receive a drag.
@@ -26,6 +27,8 @@
  */
 public interface DropTarget {
 
+    public static final String TAG = "DropTarget";
+
     class DragObject {
         public int x = -1;
         public int y = -1;
@@ -75,28 +78,28 @@
         void onDragEnter() {
             dragParity++;
             if (dragParity != 1) {
-                throw new RuntimeException("onDragEnter: Drag contract violated: " + dragParity);
+                Log.e(TAG, "onDragEnter: Drag contract violated: " + dragParity);
             }
         }
 
         void onDragExit() {
             dragParity--;
             if (dragParity != 0) {
-                throw new RuntimeException("onDragExit: Drag contract violated: " + dragParity);
+                Log.e(TAG, "onDragExit: Drag contract violated: " + dragParity);
             }
         }
 
         @Override
         public void onDragStart(DragSource source, Object info, int dragAction) {
             if (dragParity != 0) {
-                throw new RuntimeException("onDragEnter: Drag contract violated: " + dragParity);
+                Log.e(TAG, "onDragEnter: Drag contract violated: " + dragParity);
             }
         }
 
         @Override
         public void onDragEnd() {
             if (dragParity != 0) {
-                throw new RuntimeException("onDragExit: Drag contract violated: " + dragParity);
+                Log.e(TAG, "onDragExit: Drag contract violated: " + dragParity);
             }
         }
     }
diff --git a/src/com/android/launcher2/InstallShortcutReceiver.java b/src/com/android/launcher2/InstallShortcutReceiver.java
index 19b1c69..eda82e0 100644
--- a/src/com/android/launcher2/InstallShortcutReceiver.java
+++ b/src/com/android/launcher2/InstallShortcutReceiver.java
@@ -97,7 +97,7 @@
         // will provide feedback otherwise
         if (!found) {
             if (result[0] == INSTALL_SHORTCUT_NO_SPACE) {
-                Toast.makeText(context, context.getString(R.string.out_of_space),
+                Toast.makeText(context, context.getString(R.string.completely_out_of_space),
                         Toast.LENGTH_SHORT).show();
             } else if (result[0] == INSTALL_SHORTCUT_IS_DUPLICATE) {
                 Toast.makeText(context, context.getString(R.string.shortcut_duplicate, name),
@@ -174,8 +174,8 @@
                     cellY = item.cellY;
                     spanX = item.spanX;
                     spanY = item.spanY;
-                    for (int x = cellX; x < cellX + spanX && x < xCount; x++) {
-                        for (int y = cellY; y < cellY + spanY && y < yCount; y++) {
+                    for (int x = cellX; 0 <= x && x < cellX + spanX && x < xCount; x++) {
+                        for (int y = cellY; 0 <= y && y < cellY + spanY && y < yCount; y++) {
                             occupied[x][y] = true;
                         }
                     }
diff --git a/src/com/android/launcher2/Launcher.java b/src/com/android/launcher2/Launcher.java
index 84a3b4f..3ba93af 100644
--- a/src/com/android/launcher2/Launcher.java
+++ b/src/com/android/launcher2/Launcher.java
@@ -381,8 +381,10 @@
         final String forceEnableRotation = 
                 SystemProperties.get(FORCE_ENABLE_ROTATION_PROPERTY, "false");
 
+        boolean enableRotation = getResources().getBoolean(R.bool.allow_rotation);
+
         // On large interfaces, we want the screen to auto-rotate based on the current orientation
-        if (LauncherApplication.isScreenLarge() || "true".equalsIgnoreCase(forceEnableRotation)) {
+        if (enableRotation || "true".equalsIgnoreCase(forceEnableRotation)) {
             setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
         }
     }
@@ -1817,7 +1819,7 @@
 
         Intent intent = new Intent(RecognizerIntent.ACTION_WEB_SEARCH);
         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
-        startActivity(intent);
+        startActivitySafely(intent, "onClickVoiceButton");
     }
 
     /**
@@ -1848,7 +1850,7 @@
         Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
                 Uri.fromParts("package", packageName, null));
         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
-        startActivity(intent);
+        startActivitySafely(intent, "startApplicationDetailsActivity");
     }
 
     void startApplicationUninstallActivity(ApplicationInfo appInfo) {
@@ -2742,6 +2744,7 @@
         final View searchDivider = findViewById(R.id.search_divider);
         final View voiceButtonContainer = findViewById(R.id.voice_button_container);
         final View voiceButton = findViewById(R.id.voice_button);
+        final View voiceButtonProxy = findViewById(R.id.voice_button_proxy);
 
         final SearchManager searchManager =
                 (SearchManager) getSystemService(Context.SEARCH_SERVICE);
@@ -2762,6 +2765,7 @@
             if (voiceButtonContainer != null) voiceButtonContainer.setVisibility(View.GONE);
             searchButton.setVisibility(View.GONE);
             voiceButton.setVisibility(View.GONE);
+            voiceButtonProxy.setVisibility(View.GONE);
             return false;
         }
     }
@@ -2777,6 +2781,7 @@
         final View searchDivider = findViewById(R.id.search_divider);
         final View voiceButtonContainer = findViewById(R.id.voice_button_container);
         final View voiceButton = findViewById(R.id.voice_button);
+        final View voiceButtonProxy = findViewById(R.id.voice_button_proxy);
 
         // We only show/update the voice search icon if the search icon is enabled as well
         Intent intent = new Intent(RecognizerIntent.ACTION_WEB_SEARCH);
@@ -2788,12 +2793,14 @@
             if (searchDivider != null) searchDivider.setVisibility(View.VISIBLE);
             if (voiceButtonContainer != null) voiceButtonContainer.setVisibility(View.VISIBLE);
             voiceButton.setVisibility(View.VISIBLE);
+            voiceButtonProxy.setVisibility(View.VISIBLE);
             invalidatePressedFocusedStates(voiceButtonContainer, voiceButton);
             return true;
         } else {
             if (searchDivider != null) searchDivider.setVisibility(View.GONE);
             if (voiceButtonContainer != null) voiceButtonContainer.setVisibility(View.GONE);
             voiceButton.setVisibility(View.GONE);
+            voiceButtonProxy.setVisibility(View.GONE);
             return false;
         }
     }