First cut at new home screen customization for xlarge displays.

- Add new layout for xlarge, removing hotseat, next/prev page, etc.
- Add a "+" button in top right which switches to customization mode
- Add a widget chooser which slides up from bottom of screen
- Initial support for dragging widgets onto home screen

Change-Id: I14e2e013ccceff4066fcb7c4492b4f6bef6595e7
diff --git a/src/com/android/launcher2/CellLayout.java b/src/com/android/launcher2/CellLayout.java
index 56b62ba..73481c2 100644
--- a/src/com/android/launcher2/CellLayout.java
+++ b/src/com/android/launcher2/CellLayout.java
@@ -158,67 +158,72 @@
         mCellInfo.screen = ((ViewGroup) getParent()).indexOfChild(this);
     }
 
+    public void setTagToCellInfoForPoint(int touchX, int touchY) {
+        final CellInfo cellInfo = mCellInfo;
+        final Rect frame = mRect;
+        final int x = touchX + mScrollX;
+        final int y = touchY + mScrollY;
+        final int count = getChildCount();
+
+        boolean found = false;
+        for (int i = count - 1; i >= 0; i--) {
+            final View child = getChildAt(i);
+
+            if ((child.getVisibility()) == VISIBLE || child.getAnimation() != null) {
+                child.getHitRect(frame);
+                if (frame.contains(x, y)) {
+                    final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+                    cellInfo.cell = child;
+                    cellInfo.cellX = lp.cellX;
+                    cellInfo.cellY = lp.cellY;
+                    cellInfo.spanX = lp.cellHSpan;
+                    cellInfo.spanY = lp.cellVSpan;
+                    cellInfo.valid = true;
+                    found = true;
+                    mDirtyTag = false;
+                    break;
+                }
+            }
+        }
+            
+        mLastDownOnOccupiedCell = found;
+
+        if (!found) {
+            int cellXY[] = mCellXY;
+            pointToCellExact(x, y, cellXY);
+
+            final boolean portrait = mPortrait;
+            final int xCount = portrait ? mShortAxisCells : mLongAxisCells;
+            final int yCount = portrait ? mLongAxisCells : mShortAxisCells;
+
+            final boolean[][] occupied = mOccupied;
+            findOccupiedCells(xCount, yCount, occupied, null);
+
+            cellInfo.cell = null;
+            cellInfo.cellX = cellXY[0];
+            cellInfo.cellY = cellXY[1];
+            cellInfo.spanX = 1;
+            cellInfo.spanY = 1;
+            cellInfo.valid = cellXY[0] >= 0 && cellXY[1] >= 0 && cellXY[0] < xCount &&
+                    cellXY[1] < yCount && !occupied[cellXY[0]][cellXY[1]];
+
+            // Instead of finding the interesting vacant cells here, wait until a
+            // caller invokes getTag() to retrieve the result. Finding the vacant
+            // cells is a bit expensive and can generate many new objects, it's
+            // therefore better to defer it until we know we actually need it.
+
+            mDirtyTag = true;
+        }
+        setTag(cellInfo);
+    }
+
     @Override
     public boolean onInterceptTouchEvent(MotionEvent ev) {
         final int action = ev.getAction();
         final CellInfo cellInfo = mCellInfo;
 
         if (action == MotionEvent.ACTION_DOWN) {
-            final Rect frame = mRect;
-            final int x = (int) ev.getX() + mScrollX;
-            final int y = (int) ev.getY() + mScrollY;
-            final int count = getChildCount();
-
-            boolean found = false;
-            for (int i = count - 1; i >= 0; i--) {
-                final View child = getChildAt(i);
-
-                if ((child.getVisibility()) == VISIBLE || child.getAnimation() != null) {
-                    child.getHitRect(frame);
-                    if (frame.contains(x, y)) {
-                        final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-                        cellInfo.cell = child;
-                        cellInfo.cellX = lp.cellX;
-                        cellInfo.cellY = lp.cellY;
-                        cellInfo.spanX = lp.cellHSpan;
-                        cellInfo.spanY = lp.cellVSpan;
-                        cellInfo.valid = true;
-                        found = true;
-                        mDirtyTag = false;
-                        break;
-                    }
-                }
-            }
-            
-            mLastDownOnOccupiedCell = found;
-
-            if (!found) {
-                int cellXY[] = mCellXY;
-                pointToCellExact(x, y, cellXY);
-
-                final boolean portrait = mPortrait;
-                final int xCount = portrait ? mShortAxisCells : mLongAxisCells;
-                final int yCount = portrait ? mLongAxisCells : mShortAxisCells;
-
-                final boolean[][] occupied = mOccupied;
-                findOccupiedCells(xCount, yCount, occupied, null);
-
-                cellInfo.cell = null;
-                cellInfo.cellX = cellXY[0];
-                cellInfo.cellY = cellXY[1];
-                cellInfo.spanX = 1;
-                cellInfo.spanY = 1;
-                cellInfo.valid = cellXY[0] >= 0 && cellXY[1] >= 0 && cellXY[0] < xCount &&
-                        cellXY[1] < yCount && !occupied[cellXY[0]][cellXY[1]];
-
-                // Instead of finding the interesting vacant cells here, wait until a
-                // caller invokes getTag() to retrieve the result. Finding the vacant
-                // cells is a bit expensive and can generate many new objects, it's
-                // therefore better to defer it until we know we actually need it.
-
-                mDirtyTag = true;
-            }
-            setTag(cellInfo);
+            setTagToCellInfoForPoint((int) ev.getX(), (int) ev.getY());
         } else if (action == MotionEvent.ACTION_UP) {
             cellInfo.cell = null;
             cellInfo.cellX = -1;
diff --git a/src/com/android/launcher2/Launcher.java b/src/com/android/launcher2/Launcher.java
index a5988bf..07e8834 100644
--- a/src/com/android/launcher2/Launcher.java
+++ b/src/com/android/launcher2/Launcher.java
@@ -17,6 +17,7 @@
 package com.android.launcher2;
 
 import com.android.common.Search;
+import com.android.launcher.R;
 
 import android.app.Activity;
 import android.app.AlertDialog;
@@ -24,6 +25,8 @@
 import android.app.SearchManager;
 import android.app.StatusBarManager;
 import android.app.WallpaperManager;
+import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetProviderInfo;
 import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -31,9 +34,8 @@
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
-import android.content.Intent.ShortcutIconResource;
 import android.content.IntentFilter;
-import android.content.pm.ActivityInfo;
+import android.content.Intent.ShortcutIconResource;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.res.Configuration;
@@ -41,10 +43,10 @@
 import android.content.res.TypedArray;
 import android.database.ContentObserver;
 import android.graphics.Bitmap;
-import android.graphics.Rect;
 import android.graphics.Canvas;
-import android.graphics.drawable.Drawable;
+import android.graphics.Rect;
 import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
@@ -66,25 +68,22 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.View.OnLongClickListener;
+import android.view.animation.AnimationUtils;
 import android.view.inputmethod.InputMethodManager;
 import android.widget.EditText;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.PopupWindow;
 import android.widget.TextView;
 import android.widget.Toast;
-import android.widget.ImageView;
-import android.widget.PopupWindow;
-import android.widget.LinearLayout;
-import android.appwidget.AppWidgetManager;
-import android.appwidget.AppWidgetProviderInfo;
 
-import java.util.ArrayList;
-import java.util.List;
-import java.util.HashMap;
+import java.io.DataInputStream;
 import java.io.DataOutputStream;
 import java.io.FileNotFoundException;
 import java.io.IOException;
-import java.io.DataInputStream;
-
-import com.android.launcher.R;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
 
 /**
  * Default launcher application.
@@ -182,6 +181,7 @@
     private DeleteZone mDeleteZone;
     private HandleView mHandleView;
     private AllAppsView mAllAppsGrid;
+    private WidgetChooser mWidgetChooser;
 
     private Bundle mSavedState;
 
@@ -536,10 +536,13 @@
                     completeAddLiveFolder(data, mAddItemCellInfo);
                     break;
                 case REQUEST_PICK_APPWIDGET:
-                    addAppWidget(data);
+                    addAppWidgetFromPick(data);
                     break;
                 case REQUEST_CREATE_APPWIDGET:
-                    completeAddAppWidget(data, mAddItemCellInfo);
+                    int appWidgetId = data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
+                    // TODO: Is this log message meaningful?
+                    if (LOGD) Log.d(TAG, "dumping extras content=" + data.getExtras());
+                    completeAddAppWidget(appWidgetId, mAddItemCellInfo);
                     break;
                 case REQUEST_PICK_WALLPAPER:
                     // We just wanted the activity result here so we can clear mWaitingForResult
@@ -572,8 +575,11 @@
     @Override
     protected void onPause() {
         super.onPause();
-        dismissPreview(mPreviousView);
-        dismissPreview(mNextView);
+        // Some launcher layouts don't have a previous and next view
+        if (mPreviousView != null) {
+            dismissPreview(mPreviousView);
+            dismissPreview(mNextView);
+        }
         mDragController.cancelDrag();
     }
 
@@ -720,24 +726,30 @@
         mHandleView.setOnClickListener(this);
         mHandleView.setOnLongClickListener(this);
 
-        ImageView hotseatLeft = (ImageView) findViewById(R.id.hotseat_left);
-        hotseatLeft.setContentDescription(mHotseatLabels[0]);
-        hotseatLeft.setImageDrawable(mHotseatIcons[0]);
-        ImageView hotseatRight = (ImageView) findViewById(R.id.hotseat_right);
-        hotseatRight.setContentDescription(mHotseatLabels[1]);
-        hotseatRight.setImageDrawable(mHotseatIcons[1]);
+        mWidgetChooser = (WidgetChooser) findViewById(R.id.widget_chooser);
+        if (mWidgetChooser != null) {
+            mWidgetChooser.setDragController(dragController);
+            mWidgetChooser.setLauncher(this);
+        } else {
+             ImageView hotseatLeft = (ImageView) findViewById(R.id.hotseat_left);
+             hotseatLeft.setContentDescription(mHotseatLabels[0]);
+             hotseatLeft.setImageDrawable(mHotseatIcons[0]);
+             ImageView hotseatRight = (ImageView) findViewById(R.id.hotseat_right);
+             hotseatRight.setContentDescription(mHotseatLabels[1]);
+             hotseatRight.setImageDrawable(mHotseatIcons[1]);
 
-        mPreviousView = (ImageView) dragLayer.findViewById(R.id.previous_screen);
-        mNextView = (ImageView) dragLayer.findViewById(R.id.next_screen);
+             mPreviousView = (ImageView) dragLayer.findViewById(R.id.previous_screen);
+             mNextView = (ImageView) dragLayer.findViewById(R.id.next_screen);
 
-        Drawable previous = mPreviousView.getDrawable();
-        Drawable next = mNextView.getDrawable();
-        mWorkspace.setIndicators(previous, next);
+             Drawable previous = mPreviousView.getDrawable();
+             Drawable next = mNextView.getDrawable();
+             mWorkspace.setIndicators(previous, next);
 
-        mPreviousView.setHapticFeedbackEnabled(false);
-        mPreviousView.setOnLongClickListener(this);
-        mNextView.setHapticFeedbackEnabled(false);
-        mNextView.setOnLongClickListener(this);
+             mPreviousView.setHapticFeedbackEnabled(false);
+             mPreviousView.setOnLongClickListener(this);
+             mNextView.setHapticFeedbackEnabled(false);
+             mNextView.setOnLongClickListener(this);
+        }
 
         workspace.setOnLongClickListener(this);
         workspace.setDragController(dragController);
@@ -745,7 +757,8 @@
 
         deleteZone.setLauncher(this);
         deleteZone.setDragController(dragController);
-        deleteZone.setHandle(findViewById(R.id.all_apps_button_cluster));
+        int deleteZoneHandleId = isScreenXLarge() ? R.id.add_button : R.id.all_apps_button_cluster;
+        deleteZone.setHandle(findViewById(deleteZoneHandleId));
 
         dragController.setDragScoller(workspace);
         dragController.setDragListener(deleteZone);
@@ -876,12 +889,7 @@
      * @param data The intent describing the appWidgetId.
      * @param cellInfo The position on screen where to create the widget.
      */
-    private void completeAddAppWidget(Intent data, CellLayout.CellInfo cellInfo) {
-        Bundle extras = data.getExtras();
-        int appWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
-
-        if (LOGD) Log.d(TAG, "dumping extras content=" + extras.toString());
-
+    private void completeAddAppWidget(int appWidgetId, CellLayout.CellInfo cellInfo) {
         AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
 
         // Calculate the grid spans needed to fit this widget
@@ -1171,9 +1179,27 @@
         showAddDialog(mMenuAddInfo);
     }
 
-    void addAppWidget(Intent data) {
+    boolean isScreenXLarge() {
+        int screenLayout = getResources().getConfiguration().screenLayout;
+        return (screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_XLARGE;
+    }
+
+    void addAppWidgetFromDrop(ComponentName appWidgetProvider, CellLayout.CellInfo cellInfo) {
+        mAddItemCellInfo = cellInfo;
+        int appWidgetId = getAppWidgetHost().allocateAppWidgetId();
+        AppWidgetManager.getInstance(this).bindAppWidgetId(appWidgetId, appWidgetProvider);
+        addAppWidgetImpl(appWidgetId);
+    }
+
+    void addAppWidgetFromPick(Intent data) {
         // TODO: catch bad widget exception when sent
         int appWidgetId = data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
+        // TODO: Is this log message meaningful?
+        if (LOGD) Log.d(TAG, "dumping extras content=" + data.getExtras());
+        addAppWidgetImpl(appWidgetId);
+    }
+
+    void addAppWidgetImpl(int appWidgetId) {
         AppWidgetProviderInfo appWidget = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
 
         if (appWidget.configure != null) {
@@ -1185,7 +1211,7 @@
             startActivityForResultSafely(intent, REQUEST_CREATE_APPWIDGET);
         } else {
             // Otherwise just add it
-            onActivityResult(REQUEST_CREATE_APPWIDGET, Activity.RESULT_OK, data);
+            completeAddAppWidget(appWidgetId, mAddItemCellInfo);
         }
     }
 
@@ -1389,8 +1415,11 @@
         } else {
             closeFolder();
         }
-        dismissPreview(mPreviousView);
-        dismissPreview(mNextView);
+        // Some launcher layouts don't have a previous and next view
+        if (mPreviousView != null) {
+            dismissPreview(mPreviousView);
+            dismissPreview(mNextView);
+        }
     }
 
     private void closeFolder() {
@@ -1456,6 +1485,24 @@
         }
     }
 
+    /**
+     * Event handler for the "plus" button that appears on the home screen, which
+     * enters home screen customization mode.
+     *
+     * @param v The view that was clicked.
+     */
+    public void onClickAddButton(View v) {
+        View widgetChooser = findViewById(R.id.widget_chooser);
+        widgetChooser.setVisibility(View.VISIBLE);
+
+        // Animate the widget chooser up from the bottom of the screen
+        widgetChooser.startAnimation(AnimationUtils.loadAnimation(this, R.anim.widget_chooser_slide_up));
+    }
+
+    public void onClickAllAppsButton(View w) {
+        showAllApps(true);
+    }
+
     void startActivitySafely(Intent intent, Object tag) {
         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         try {
diff --git a/src/com/android/launcher2/LauncherAppWidgetInfo.java b/src/com/android/launcher2/LauncherAppWidgetInfo.java
index 8499ebb..3c81bac 100644
--- a/src/com/android/launcher2/LauncherAppWidgetInfo.java
+++ b/src/com/android/launcher2/LauncherAppWidgetInfo.java
@@ -17,6 +17,7 @@
 package com.android.launcher2;
 
 import android.appwidget.AppWidgetHostView;
+import android.content.ComponentName;
 import android.content.ContentValues;
 
 /**
@@ -29,6 +30,7 @@
      * {@link android.appwidget.AppWidgetManager} for updates.
      */
     int appWidgetId;
+    ComponentName providerName;
     
     /**
      * View that holds this widget after it's been created.  This view isn't created
diff --git a/src/com/android/launcher2/WidgetChooser.java b/src/com/android/launcher2/WidgetChooser.java
new file mode 100644
index 0000000..fc354d7
--- /dev/null
+++ b/src/com/android/launcher2/WidgetChooser.java
@@ -0,0 +1,94 @@
+package com.android.launcher2;
+
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.Context;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.Gallery;
+
+public class WidgetChooser extends Gallery
+    implements Gallery.OnItemLongClickListener, DragSource {
+
+    Context mContext;
+
+    private Launcher mLauncher;
+    private DragController mDragController;
+    private WidgetGalleryAdapter mWidgetGalleryAdapter;
+
+    private int mMotionDownRawX;
+    private int mMotionDownRawY;
+
+    public WidgetChooser(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        setLongClickable(true);
+        setOnItemLongClickListener(this);
+        mContext = context;
+
+        setCallbackDuringFling(false);
+
+        mWidgetGalleryAdapter = new WidgetGalleryAdapter(context);
+        setAdapter(mWidgetGalleryAdapter);
+    }
+
+    public void onDropCompleted(View target, boolean success) {
+        // TODO Auto-generated method stub
+
+    }
+
+    public void setDragController(DragController dragger) {
+        mDragController = dragger;
+    }
+
+    public void setLauncher(Launcher launcher) {
+        mLauncher = launcher;
+    }
+
+    public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
+        AppWidgetProviderInfo info = (AppWidgetProviderInfo)mWidgetGalleryAdapter.getItem(position);
+        try {
+            Resources r = mContext.getPackageManager().getResourcesForApplication(info.provider.getPackageName());
+
+            Bitmap bmp = BitmapFactory.decodeResource(r, info.icon);
+            final int w = bmp.getWidth();
+            final int h = bmp.getHeight();
+
+            // We don't really have an accurate location to use.  This will do.
+            int screenX = mMotionDownRawX - (w / 2);
+            int screenY = mMotionDownRawY - h;
+
+            LauncherAppWidgetInfo dragInfo = new LauncherAppWidgetInfo(-1);
+            dragInfo.providerName = info.provider;
+            mDragController.startDrag(bmp, screenX, screenY,
+                    0, 0, w, h, this, dragInfo, DragController.DRAG_ACTION_COPY);
+            return true;
+        } catch (NameNotFoundException e) {
+            return false;
+        }
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        if (ev.getAction() == MotionEvent.ACTION_DOWN && mLauncher.isAllAppsVisible()) {
+            return false;
+        }
+
+        super.onTouchEvent(ev);
+
+        int x = (int) ev.getX();
+        int y = (int) ev.getY();
+
+        switch (ev.getAction()) {
+        case MotionEvent.ACTION_DOWN:
+            mMotionDownRawX = (int) ev.getRawX();
+            mMotionDownRawY = (int) ev.getRawY();
+        }
+        return true;
+    }
+}
diff --git a/src/com/android/launcher2/WidgetGalleryAdapter.java b/src/com/android/launcher2/WidgetGalleryAdapter.java
new file mode 100644
index 0000000..d6272d4
--- /dev/null
+++ b/src/com/android/launcher2/WidgetGalleryAdapter.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2010 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.launcher2;
+
+import com.android.launcher.R;
+
+import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.graphics.drawable.Drawable;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.ImageView;
+
+import java.util.List;
+
+public class WidgetGalleryAdapter extends BaseAdapter {
+    private LayoutInflater mLayoutInflater;
+    private PackageManager mPackageManager;
+    private List<AppWidgetProviderInfo> mWidgets;
+
+    WidgetGalleryAdapter(Context context) {
+        mLayoutInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        AppWidgetManager widgetManager = AppWidgetManager.getInstance(context);
+        mWidgets = widgetManager.getInstalledProviders();
+        mPackageManager = context.getPackageManager();
+    }
+
+    public int getCount() {
+        return mWidgets.size();
+    }
+
+    public Object getItem(int position) {
+        return mWidgets.get(position);
+    }
+
+    public long getItemId(int position) {
+        return position;
+    }
+
+    public View getView(int position, View convertView, ViewGroup parent) {
+        ImageView imageView;
+
+        if (convertView == null) {
+            imageView = (ImageView) mLayoutInflater.inflate(R.layout.widget_item, parent, false);
+        } else {
+            imageView = (ImageView) convertView;
+        }
+
+        AppWidgetProviderInfo info = mWidgets.get(position);
+        Drawable drawable = mPackageManager.getDrawable(info.provider.getPackageName(), info.icon, null);
+        imageView.setImageDrawable(drawable);
+
+        return imageView;
+    }
+}
diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java
index c337c30..c56a313 100644
--- a/src/com/android/launcher2/Workspace.java
+++ b/src/com/android/launcher2/Workspace.java
@@ -16,8 +16,7 @@
 
 package com.android.launcher2;
 
-import java.util.ArrayList;
-import java.util.HashSet;
+import com.android.launcher.R;
 
 import android.app.WallpaperManager;
 import android.appwidget.AppWidgetManager;
@@ -47,7 +46,8 @@
 import android.widget.Scroller;
 import android.widget.TextView;
 
-import com.android.launcher.R;
+import java.util.ArrayList;
+import java.util.HashSet;
 
 /**
  * The workspace is a wide area with a wallpaper and a finite number of screens. Each
@@ -450,8 +450,10 @@
             postInvalidate();
         } else if (mNextScreen != INVALID_SCREEN) {
             mCurrentScreen = Math.max(0, Math.min(mNextScreen, getChildCount() - 1));
-            mPreviousIndicator.setLevel(mCurrentScreen);
-            mNextIndicator.setLevel(mCurrentScreen);
+            if (mPreviousIndicator != null) {
+                mPreviousIndicator.setLevel(mCurrentScreen);
+                mNextIndicator.setLevel(mCurrentScreen);
+            }
             Launcher.setScreen(mCurrentScreen);
             mNextScreen = INVALID_SCREEN;
             clearChildrenCache();
@@ -963,8 +965,10 @@
 
         mNextScreen = whichScreen;
 
+        if (mPreviousIndicator != null) {
         mPreviousIndicator.setLevel(mNextScreen);
         mNextIndicator.setLevel(mNextScreen);
+        }
 
         View focusedChild = getFocusedChild();
         if (focusedChild != null && whichScreen != mCurrentScreen &&
@@ -1098,7 +1102,7 @@
         // Drag from somewhere else
         ItemInfo info = (ItemInfo) dragInfo;
 
-        View view;
+        View view = null;
 
         switch (info.itemType) {
         case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
@@ -1113,23 +1117,31 @@
             view = FolderIcon.fromXml(R.layout.folder_icon, mLauncher,
                     (ViewGroup) getChildAt(mCurrentScreen), ((UserFolderInfo) info));
             break;
+        case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
+            cellLayout.setTagToCellInfoForPoint(x, y);
+            mLauncher.addAppWidgetFromDrop(((LauncherAppWidgetInfo)dragInfo).providerName, cellLayout.getTag());
+            break;
         default:
             throw new IllegalStateException("Unknown item type: " + info.itemType);
         }
 
-        cellLayout.addView(view, insertAtFirst ? 0 : -1);
-        view.setHapticFeedbackEnabled(false);
-        view.setOnLongClickListener(mLongClickListener);
-        if (view instanceof DropTarget) {
-            mDragController.addDropTarget((DropTarget) view);
+        // addAppWidgetFromDrop already took care of attaching the widget view to the appropriate cell
+        // TODO why aren't we calling addInScreen here?
+        if (info.itemType != LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET) {
+            cellLayout.addView(view, insertAtFirst ? 0 : -1);
+            view.setHapticFeedbackEnabled(false);
+            view.setOnLongClickListener(mLongClickListener);
+            if (view instanceof DropTarget) {
+                mDragController.addDropTarget((DropTarget) view);
+            }
+
+            mTargetCell = estimateDropCell(x, y, 1, 1, view, cellLayout, mTargetCell);
+            cellLayout.onDropChild(view, mTargetCell);
+            CellLayout.LayoutParams lp = (CellLayout.LayoutParams) view.getLayoutParams();
+
+            LauncherModel.addOrMoveItemInDatabase(mLauncher, info,
+                    LauncherSettings.Favorites.CONTAINER_DESKTOP, mCurrentScreen, lp.cellX, lp.cellY);
         }
-
-        mTargetCell = estimateDropCell(x, y, 1, 1, view, cellLayout, mTargetCell);
-        cellLayout.onDropChild(view, mTargetCell);
-        CellLayout.LayoutParams lp = (CellLayout.LayoutParams) view.getLayoutParams();
-
-        LauncherModel.addOrMoveItemInDatabase(mLauncher, info,
-                LauncherSettings.Favorites.CONTAINER_DESKTOP, mCurrentScreen, lp.cellX, lp.cellY);
     }
     
     /**