Code drop from //branches/cupcake/...@124589
diff --git a/src/com/android/launcher/AddAdapter.java b/src/com/android/launcher/AddAdapter.java
index 49422c6..8eebe39 100644
--- a/src/com/android/launcher/AddAdapter.java
+++ b/src/com/android/launcher/AddAdapter.java
@@ -28,6 +28,7 @@
 import android.widget.TextView;
 import android.widget.BaseExpandableListAdapter;
 import android.graphics.drawable.Drawable;
+import android.provider.LiveFolders;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -40,9 +41,11 @@
     private static final int GROUP_APPLICATIONS = 0;
     private static final int GROUP_SHORTCUTS = 1;
     private static final int GROUP_WIDGETS = 2;
-    private static final int GROUP_WALLPAPERS = 3;
+    private static final int GROUP_LIVE_FOLDERS = 3;
+    private static final int GROUP_WALLPAPERS = 4;
 
     private final Intent mCreateShortcutIntent;
+    private final Intent mCreateLiveFolderIntent;
     private Intent mSetWallpaperIntent;
     private final LayoutInflater mInflater;
     private Launcher mLauncher;
@@ -52,7 +55,7 @@
      * Abstract class representing one thing that can be added
      */
     public abstract class AddAction implements Runnable {
-        private final Context mContext;
+        protected final Context mContext;
 
         AddAction(Context context) {
             mContext = context;
@@ -110,8 +113,9 @@
                     mLabel = info.activityInfo.name;
                 }
             }
+
             if (mIcon == null) {
-                mIcon = info.loadIcon(pm);
+                mIcon = Utilities.createIconThumbnail(info.loadIcon(pm), mContext);
             }
 
             text.setText(mLabel);
@@ -126,12 +130,32 @@
             mLauncher.addShortcut(intent);
         }
     }
-    
+
+    /**
+     * Class representing an action that will create a specific type
+     * of live folder
+     */
+    public class CreateLiveFolderAction extends CreateShortcutAction {
+        CreateLiveFolderAction(Context context, ResolveInfo info) {
+            super(context, info);
+        }
+
+        @Override
+        public void run() {
+            Intent intent = new Intent(mCreateLiveFolderIntent);
+            ActivityInfo activityInfo = mInfo.activityInfo;
+            intent.setComponent(new ComponentName(activityInfo.applicationInfo.packageName,
+                    activityInfo.name));
+            mLauncher.addLiveFolder(intent);
+        }
+    }
+
     /**
      * Class representing an action that will add a folder
      */
     public class CreateFolderAction extends AddAction {
-        
+        private Drawable mIcon;
+
         CreateFolderAction(Context context) {
             super(context);
         }
@@ -140,8 +164,8 @@
         public void bindView(View view) {
             TextView text = (TextView) view;
             text.setText(R.string.add_folder);
-            text.setCompoundDrawablesWithIntrinsicBounds(getIcon(R.drawable.ic_launcher_folder),
-                    null, null, null);
+            if (mIcon == null) mIcon = getIcon(R.drawable.ic_launcher_folder);
+            text.setCompoundDrawablesWithIntrinsicBounds(mIcon, null, null, null);
         }
 
         public void run() {
@@ -175,6 +199,8 @@
      * Class representing an action that will add a PhotoFrame
      */
     public class CreatePhotoFrameAction extends AddAction {
+        private Drawable mIcon;
+
         CreatePhotoFrameAction(Context context) {
             super(context);
         }
@@ -183,8 +209,8 @@
         public void bindView(View view) {
             TextView text = (TextView) view;
             text.setText(R.string.add_photo_frame);
-            Drawable icon = getIcon(R.drawable.ic_launcher_gallery);
-            text.setCompoundDrawablesWithIntrinsicBounds(icon, null, null, null);
+            if (mIcon == null) mIcon = getIcon(R.drawable.ic_launcher_gallery);
+            text.setCompoundDrawablesWithIntrinsicBounds(mIcon, null, null, null);
         }
 
         public void run() {
@@ -197,6 +223,8 @@
      * Class representing an action that will add a Search widget
      */
     public class CreateSearchAction extends AddAction {
+        private Drawable mIcon;
+
         CreateSearchAction(Context context) {
             super(context);
         }
@@ -205,8 +233,8 @@
         public void bindView(View view) {
             TextView text = (TextView) view;
             text.setText(R.string.add_search);
-            Drawable icon = getIcon(R.drawable.ic_search_gadget);
-            text.setCompoundDrawablesWithIntrinsicBounds(icon, null, null, null);
+            if (mIcon == null) mIcon = getIcon(R.drawable.ic_search_gadget);
+            text.setCompoundDrawablesWithIntrinsicBounds(mIcon, null, null, null);
         }
 
         public void run() {
@@ -296,22 +324,27 @@
         mCreateShortcutIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT);
         mCreateShortcutIntent.setComponent(null);
 
+        mCreateLiveFolderIntent = new Intent(LiveFolders.ACTION_CREATE_LIVE_FOLDER);
+        mCreateLiveFolderIntent.setComponent(null);
+
         mSetWallpaperIntent = new Intent(Intent.ACTION_SET_WALLPAPER);
         mSetWallpaperIntent.setComponent(null);
 
         mLauncher = launcher;
         mInflater = (LayoutInflater) launcher.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
 
-        mGroups = new Group[forFolder ? 2 : 4];
+        mGroups = new Group[forFolder ? 2 : 5];
         final Group[] groups = mGroups;
         groups[GROUP_APPLICATIONS] = new ApplicationsGroup(mLauncher,
                 mLauncher.getString(R.string.group_applications));
         groups[GROUP_SHORTCUTS] = new Group(mLauncher.getString(R.string.group_shortcuts));
+        groups[GROUP_LIVE_FOLDERS] = new Group(mLauncher.getString(R.string.group_live_folders));
 
         if (!forFolder) {
             groups[GROUP_WALLPAPERS] = new Group(mLauncher.getString(R.string.group_wallpapers));
             groups[GROUP_SHORTCUTS].add(new CreateFolderAction(launcher));
             groups[GROUP_WIDGETS] = new Group(mLauncher.getString(R.string.group_widgets));
+
             final Group widgets = groups[GROUP_WIDGETS];
             widgets.add(new CreateClockAction(launcher));
             widgets.add(new CreatePhotoFrameAction(launcher));
@@ -330,6 +363,16 @@
             }
         }
 
+        list = findTargetsForIntent(mCreateLiveFolderIntent, packageManager);
+        if (list != null && list.size() > 0) {
+            int count = list.size();
+            final Group shortcuts = groups[GROUP_LIVE_FOLDERS];
+            for (int i = 0; i < count; i++) {
+                ResolveInfo resolveInfo = list.get(i);
+                shortcuts.add(new CreateLiveFolderAction(launcher, resolveInfo));
+            }
+        }
+
         list = findTargetsForIntent(mSetWallpaperIntent, packageManager);
         if (list != null && list.size() > 0) {
             int count = list.size();
diff --git a/src/com/android/launcher/ApplicationInfo.java b/src/com/android/launcher/ApplicationInfo.java
index ec1c85a..9bc0950 100644
--- a/src/com/android/launcher/ApplicationInfo.java
+++ b/src/com/android/launcher/ApplicationInfo.java
@@ -20,9 +20,7 @@
 import android.content.ContentValues;
 import android.content.Intent;
 import android.graphics.Bitmap;
-import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
-import com.android.internal.provider.Settings;
 
 /**
  * Represents a launchable application. An application is made of a name (or title),
@@ -63,7 +61,7 @@
     Intent.ShortcutIconResource iconResource;
 
     ApplicationInfo() {
-        itemType = Settings.Favorites.ITEM_TYPE_SHORTCUT;
+        itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
     }
     
     public ApplicationInfo(ApplicationInfo info) {
@@ -82,7 +80,7 @@
 
     /**
      * Creates the application intent based on a component name and various launch flags.
-     * Sets {@link #itemType} to {@link Settings.Favorites#ITEM_TYPE_APPLICATION}.
+     * Sets {@link #itemType} to {@link LauncherSettings.Favorites#ITEM_TYPE_APPLICATION}.
      *
      * @param className the class name of the component representing the intent
      * @param launchFlags the launch flags
@@ -92,7 +90,7 @@
         intent.addCategory(Intent.CATEGORY_LAUNCHER);
         intent.setComponent(className);
         intent.setFlags(launchFlags);
-        itemType = Settings.Favorites.ITEM_TYPE_APPLICATION;
+        itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
     }
 
     @Override
@@ -100,20 +98,22 @@
         super.onAddToDatabase(values);
 
         String titleStr = title != null ? title.toString() : null;
-        values.put(Settings.Favorites.TITLE, titleStr);
+        values.put(LauncherSettings.Favorites.TITLE, titleStr);
 
         String uri = intent != null ? intent.toURI() : null;
-        values.put(Settings.Favorites.INTENT, uri);
+        values.put(LauncherSettings.Favorites.INTENT, uri);
 
         if (customIcon) {
-            values.put(Settings.Favorites.ICON_TYPE, Settings.Favorites.ICON_TYPE_BITMAP);
-            Bitmap bitmap = ((BitmapDrawable) icon).getBitmap();
+            values.put(LauncherSettings.Favorites.ICON_TYPE,
+                    LauncherSettings.Favorites.ICON_TYPE_BITMAP);
+            Bitmap bitmap = ((FastBitmapDrawable) icon).getBitmap();
             writeBitmap(values, bitmap);
         } else {
-            values.put(Settings.Favorites.ICON_TYPE, Settings.Favorites.ICON_TYPE_RESOURCE);
+            values.put(LauncherSettings.Favorites.ICON_TYPE,
+                    LauncherSettings.Favorites.ICON_TYPE_RESOURCE);
             if (iconResource != null) {
-                values.put(Settings.Favorites.ICON_PACKAGE, iconResource.packageName);
-                values.put(Settings.Favorites.ICON_RESOURCE, iconResource.resourceName);
+                values.put(LauncherSettings.Favorites.ICON_PACKAGE, iconResource.packageName);
+                values.put(LauncherSettings.Favorites.ICON_RESOURCE, iconResource.resourceName);
             }
         }
     }
diff --git a/src/com/android/launcher/BubbleTextView.java b/src/com/android/launcher/BubbleTextView.java
index 730e08e..f2c31e9 100644
--- a/src/com/android/launcher/BubbleTextView.java
+++ b/src/com/android/launcher/BubbleTextView.java
@@ -22,7 +22,7 @@
 import android.graphics.Canvas;
 import android.graphics.Paint;
 import android.graphics.RectF;
-import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
 import android.text.Layout;
 
 /**
@@ -38,6 +38,9 @@
     private final RectF mRect = new RectF();
     private Paint mPaint;
 
+    private boolean mBackgroundSizeChanged;
+    private Drawable mBackground;
+
     public BubbleTextView(Context context) {
         super(context);
         init();
@@ -55,13 +58,57 @@
 
     private void init() {
         setFocusable(true);
+        mBackground = getBackground();
+        setBackgroundDrawable(null);
+        mBackground.setCallback(this);
 
         mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
         mPaint.setColor(getContext().getResources().getColor(R.color.bubble_dark_background));
     }
 
     @Override
-    public void onDraw(Canvas canvas) {
+    protected boolean setFrame(int left, int top, int right, int bottom) {
+        if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) {
+            mBackgroundSizeChanged = true;
+        }
+        return super.setFrame(left, top, right, bottom);
+    }
+
+    @Override
+    protected boolean verifyDrawable(Drawable who) {
+        return who == mBackground || super.verifyDrawable(who);
+    }
+
+    @Override
+    protected void drawableStateChanged() {
+        Drawable d = mBackground;
+        if (d != null && d.isStateful()) {
+            d.setState(getDrawableState());
+        }
+        super.drawableStateChanged();
+    }
+
+    @Override
+    public void draw(Canvas canvas) {
+        final Drawable background = mBackground;
+        if (background != null) {
+            final int scrollX = mScrollX;
+            final int scrollY = mScrollY;
+
+            if (mBackgroundSizeChanged) {
+                background.setBounds(0, 0,  mRight - mLeft, mBottom - mTop);
+                mBackgroundSizeChanged = false;
+            }
+
+            if ((scrollX | scrollY) == 0) {
+                background.draw(canvas);
+            } else {
+                canvas.translate(scrollX, scrollY);
+                background.draw(canvas);
+                canvas.translate(-scrollX, -scrollY);
+            }
+        }
+
         final Layout layout = getLayout();
         final RectF rect = mRect;
         final int left = getCompoundPaddingLeft();
@@ -69,10 +116,10 @@
 
         rect.set(left + layout.getLineLeft(0) - PADDING_H,
                 top + layout.getLineTop(0) - PADDING_V,
-                left + layout.getLineRight(0) + PADDING_H,
+                Math.min(left + layout.getLineRight(0) + PADDING_H, mScrollX + mRight - mLeft),
                 top + layout.getLineBottom(0) + PADDING_V);
         canvas.drawRoundRect(rect, CORNER_RADIUS, CORNER_RADIUS, mPaint);
 
-        super.onDraw(canvas);
+        super.draw(canvas);
     }
 }
diff --git a/src/com/android/launcher/CellLayout.java b/src/com/android/launcher/CellLayout.java
index 03cf7fc..02646bf 100644
--- a/src/com/android/launcher/CellLayout.java
+++ b/src/com/android/launcher/CellLayout.java
@@ -105,6 +105,17 @@
     }
 
     @Override
+    public void addView(View child, int index, ViewGroup.LayoutParams params) {
+        // Generate an id for each view, this assumes we have at most 256x256 cells
+        // per workspace screen
+        final LayoutParams cellParams = (LayoutParams) params;
+        child.setId(((getId() & 0xFF) << 16) |
+                (cellParams.cellX & 0xFF) << 8 | (cellParams.cellY & 0xFF));
+
+        super.addView(child, index, params);
+    }
+
+    @Override
     public void requestChildFocus(View child, View focused) {
         super.requestChildFocus(child, focused);
         if (child != null) {
diff --git a/src/com/android/launcher/DeleteZone.java b/src/com/android/launcher/DeleteZone.java
index ab2b891..798cf0d 100644
--- a/src/com/android/launcher/DeleteZone.java
+++ b/src/com/android/launcher/DeleteZone.java
@@ -20,7 +20,6 @@
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.util.AttributeSet;
-import com.android.internal.provider.Settings;
 import android.view.View;
 import android.view.animation.TranslateAnimation;
 import android.view.animation.Animation;
@@ -35,6 +34,8 @@
     private static final int TRANSITION_DURATION = 250;
     private static final int ANIMATION_DURATION = 200;
 
+    private final int[] mLocation = new int[2];
+    
     private Launcher mLauncher;
     private boolean mTrashMode;
 
@@ -74,15 +75,16 @@
 
     public boolean acceptDrop(DragSource source, int x, int y, int xOffset, int yOffset,
             Object dragInfo) {
-        final ItemInfo item = (ItemInfo) dragInfo;
-        // Accept anything except items in the all apps folder
-        return item.container != ItemInfo.NO_ID;
+        return true;
     }
 
     public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo) {
         final ItemInfo item = (ItemInfo) dragInfo;
+
+        if (item.container == -1) return;
+
         final LauncherModel model = Launcher.getModel();
-        if (item.container == Settings.Favorites.CONTAINER_DESKTOP) {
+        if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
             model.removeDesktopItem(item);
         } else {
             if (source instanceof UserFolder) {
@@ -115,7 +117,7 @@
 
     public void onDragStart(View v, DragSource source, Object info, int dragAction) {
         final ItemInfo item = (ItemInfo) info;
-        if (item != null && item.container != ItemInfo.NO_ID) {
+        if (item != null) {
             mTrashMode = true;
             createAnimations();
             final int[] location = mLocation;
diff --git a/src/com/android/launcher/FastBitmapDrawable.java b/src/com/android/launcher/FastBitmapDrawable.java
new file mode 100644
index 0000000..170f1ad
--- /dev/null
+++ b/src/com/android/launcher/FastBitmapDrawable.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2008 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.launcher;
+
+import android.graphics.drawable.Drawable;
+import android.graphics.PixelFormat;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+
+class FastBitmapDrawable extends Drawable {
+    private Bitmap mBitmap;
+
+    FastBitmapDrawable(Bitmap b) {
+        mBitmap = b;
+    }
+
+    @Override
+    public void draw(Canvas canvas) {
+        canvas.drawBitmap(mBitmap, 0.0f, 0.0f, null);
+    }
+
+    @Override
+    public int getOpacity() {
+        return PixelFormat.TRANSLUCENT;
+    }
+
+    @Override
+    public void setAlpha(int alpha) {
+    }
+
+    @Override
+    public void setColorFilter(ColorFilter cf) {
+    }
+
+    @Override
+    public int getIntrinsicWidth() {
+        return mBitmap.getWidth();
+    }
+
+    @Override
+    public int getIntrinsicHeight() {
+        return mBitmap.getHeight();
+    }
+
+    @Override
+    public int getMinimumWidth() {
+        return mBitmap.getWidth();
+    }
+
+    @Override
+    public int getMinimumHeight() {
+        return mBitmap.getHeight();
+    }
+
+    public Bitmap getBitmap() {
+        return mBitmap;
+    }
+}
diff --git a/src/com/android/launcher/Folder.java b/src/com/android/launcher/Folder.java
index 1a91eb1..bcbccf7 100644
--- a/src/com/android/launcher/Folder.java
+++ b/src/com/android/launcher/Folder.java
@@ -21,10 +21,10 @@
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.widget.AdapterView;
-import android.widget.ArrayAdapter;
 import android.widget.Button;
-import android.widget.GridView;
 import android.widget.LinearLayout;
+import android.widget.AbsListView;
+import android.widget.ListAdapter;
 import android.widget.AdapterView.OnItemClickListener;
 import android.widget.AdapterView.OnItemLongClickListener;
 
@@ -34,7 +34,7 @@
 public class Folder extends LinearLayout implements DragSource, OnItemLongClickListener,
         OnItemClickListener, OnClickListener, View.OnLongClickListener {
 
-    protected GridView mContent;
+    protected AbsListView mContent;
     protected DragController mDragger;
     
     protected Launcher mLauncher;
@@ -64,7 +64,7 @@
     protected void onFinishInflate() {
         super.onFinishInflate();
 
-        mContent = (GridView) findViewById(R.id.content);
+        mContent = (AbsListView) findViewById(R.id.content);
         mContent.setOnItemClickListener(this);
         mContent.setOnItemLongClickListener(this);
         
@@ -83,7 +83,9 @@
     }
 
     public boolean onLongClick(View v) {
-        return false;
+        mLauncher.closeFolder(this);
+        mLauncher.showRenameDialog(mInfo);
+        return true;
     }
 
     public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
@@ -120,7 +122,7 @@
      *
      * @param adapter The list of applications to display in the folder.
      */
-    void setContentAdapter(ArrayAdapter<ApplicationInfo> adapter) {
+    void setContentAdapter(ListAdapter adapter) {
         mContent.setAdapter(adapter);
     }
 
@@ -145,4 +147,9 @@
         final Workspace workspace = mLauncher.getWorkspace();
         workspace.getChildAt(workspace.getCurrentScreen()).requestFocus();
     }
+
+    void bind(FolderInfo info) {
+        mInfo = info;
+        mCloseButton.setText(info.title);
+    }
 }
diff --git a/src/com/android/launcher/FolderIcon.java b/src/com/android/launcher/FolderIcon.java
index d7c623d..667f92e 100644
--- a/src/com/android/launcher/FolderIcon.java
+++ b/src/com/android/launcher/FolderIcon.java
@@ -19,7 +19,6 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.drawable.Drawable;
-import com.android.internal.provider.Settings;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
 import android.view.ViewGroup;
@@ -65,8 +64,8 @@
             Object dragInfo) {
         final ItemInfo item = (ItemInfo) dragInfo;
         final int itemType = item.itemType;
-        return (itemType == Settings.Favorites.ITEM_TYPE_APPLICATION || 
-                itemType == Settings.Favorites.ITEM_TYPE_SHORTCUT)
+        return (itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
+                itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT)
                 && item.container != mInfo.id;
     }
 
diff --git a/src/com/android/launcher/FolderInfo.java b/src/com/android/launcher/FolderInfo.java
index b226b62..a58675b 100644
--- a/src/com/android/launcher/FolderInfo.java
+++ b/src/com/android/launcher/FolderInfo.java
@@ -26,4 +26,9 @@
      * Whether this folder has been opened
      */
     boolean opened;
+
+    /**
+     * The folder name.
+     */
+    CharSequence title;
 }
diff --git a/src/com/android/launcher/HandleView.java b/src/com/android/launcher/HandleView.java
new file mode 100644
index 0000000..437d559
--- /dev/null
+++ b/src/com/android/launcher/HandleView.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2008 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.launcher;
+
+import android.widget.ImageView;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.KeyEvent;
+
+public class HandleView extends ImageView {
+    private static final int ORIENTATION_HORIZONTAL = 1;
+
+    private Launcher mLauncher;
+    private int mOrientation = ORIENTATION_HORIZONTAL;
+
+    public HandleView(Context context) {
+        super(context);
+    }
+
+    public HandleView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public HandleView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+
+        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.HandleView, defStyle, 0);
+        mOrientation = a.getInt(R.styleable.HandleView_direction, ORIENTATION_HORIZONTAL);
+        a.recycle();
+    }
+
+    @Override
+    public View focusSearch(int direction) {
+        View newFocus = super.focusSearch(direction);
+        if (newFocus == null) {
+            final Workspace workspace = mLauncher.getWorkspace();
+            workspace.dispatchUnhandledMove(null, direction);
+            return (mOrientation == ORIENTATION_HORIZONTAL && direction == FOCUS_DOWN) ?
+                    this : workspace;
+        }
+        return newFocus;
+    }
+
+    @Override
+    public boolean onKeyDown(int keyCode, KeyEvent event) {
+        final boolean handled = super.onKeyDown(keyCode, event);
+
+        if (!handled && !mLauncher.isDrawerDown() && !isDirectionKey(keyCode)) {
+            return mLauncher.getApplicationsGrid().onKeyDown(keyCode, event);
+        }
+
+        return handled;
+    }
+
+    @Override
+    public boolean onKeyUp(int keyCode, KeyEvent event) {
+        final boolean handled = super.onKeyUp(keyCode, event);
+
+        if (!handled && !mLauncher.isDrawerDown() && !isDirectionKey(keyCode)) {
+            return mLauncher.getApplicationsGrid().onKeyUp(keyCode, event);
+        }
+
+        return handled;
+    }
+
+    private static boolean isDirectionKey(int keyCode) {
+        return keyCode == KeyEvent.KEYCODE_DPAD_DOWN || keyCode == KeyEvent.KEYCODE_DPAD_LEFT ||
+                keyCode == KeyEvent.KEYCODE_DPAD_RIGHT || keyCode == KeyEvent.KEYCODE_DPAD_UP;
+    }
+
+    void setLauncher(Launcher launcher) {
+        mLauncher = launcher;
+    }
+}
diff --git a/src/com/android/launcher/InstallShortcutReceiver.java b/src/com/android/launcher/InstallShortcutReceiver.java
index d99e2b4..a1e954a 100644
--- a/src/com/android/launcher/InstallShortcutReceiver.java
+++ b/src/com/android/launcher/InstallShortcutReceiver.java
@@ -21,7 +21,6 @@
 import android.content.Intent;
 import android.content.ContentResolver;
 import android.database.Cursor;
-import com.android.internal.provider.Settings;
 
 public class InstallShortcutReceiver extends BroadcastReceiver {
     private final int[] mCoordinates = new int[2];
@@ -29,6 +28,15 @@
     public void onReceive(Context context, Intent data) {
         int screen = Launcher.getScreen();
 
+        if (!installShortcut(context, data, screen)) {
+            // The target screen is full, let's try the other screens
+            for (int i = 0; i < Launcher.SCREEN_COUNT; i++) {
+                if (i != screen && installShortcut(context, data, i)) break;
+            }
+        }
+    }
+
+    private boolean installShortcut(Context context, Intent data, int screen) {
         if (findEmptyCell(context, mCoordinates, screen)) {
             CellLayout.CellInfo cell = new CellLayout.CellInfo();
             cell.cellX = mCoordinates[0];
@@ -48,7 +56,11 @@
             if (duplicate || !LauncherModel.shortcutExists(context, name, intent)) {
                 Launcher.addShortcut(context, data, cell, true);
             }
+
+            return true;
         }
+
+        return false;
     }
 
     private static boolean findEmptyCell(Context context, int[] xy, int screen) {
@@ -58,14 +70,16 @@
         boolean[][] occupied = new boolean[xCount][yCount];
 
         final ContentResolver cr = context.getContentResolver();
-        Cursor c = cr.query(Settings.Favorites.CONTENT_URI,
-            new String[] { "cellX", "cellY", "spanX", "spanY" }, "screen=?",
+        Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI,
+            new String[] { LauncherSettings.Favorites.CELLX, LauncherSettings.Favorites.CELLY,
+                    LauncherSettings.Favorites.SPANX, LauncherSettings.Favorites.SPANY },
+            LauncherSettings.Favorites.SCREEN + "=?",
             new String[] { String.valueOf(screen) }, null);
 
-        final int cellXIndex = c.getColumnIndexOrThrow(Settings.Favorites.CELLX);
-        final int cellYIndex = c.getColumnIndexOrThrow(Settings.Favorites.CELLY);
-        final int spanXIndex = c.getColumnIndexOrThrow(Settings.Favorites.SPANX);
-        final int spanYIndex = c.getColumnIndexOrThrow(Settings.Favorites.SPANY);
+        final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);
+        final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);
+        final int spanXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANX);
+        final int spanYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANY);
 
         try {
             while (c.moveToNext()) {
diff --git a/src/com/android/launcher/ItemInfo.java b/src/com/android/launcher/ItemInfo.java
index f2ce23d..61745dd 100644
--- a/src/com/android/launcher/ItemInfo.java
+++ b/src/com/android/launcher/ItemInfo.java
@@ -21,10 +21,8 @@
 
 import android.content.ContentValues;
 import android.graphics.Bitmap;
-import com.android.internal.provider.Settings;
 import android.util.Log;
 
-
 /**
  * Represents an item in the launcher.
  */
@@ -38,18 +36,18 @@
     long id = NO_ID;
     
     /**
-     * One of {@link Settings.Favorites#ITEM_TYPE_APPLICATION},
-     * {@link Settings.Favorites#ITEM_TYPE_SHORTCUT}, 
-     * {@link Settings.Favorites#ITEM_TYPE_USER_FOLDER},
-     * {@link Settings.Favorites#ITEM_TYPE_WIDGET_CLOCK},
-     * {@link Settings.Favorites#ITEM_TYPE_WIDGET_SEARCH} or
-     * {@link Settings.Favorites#ITEM_TYPE_WIDGET_PHOTO_FRAME},
+     * One of {@link LauncherSettings.Favorites#ITEM_TYPE_APPLICATION},
+     * {@link LauncherSettings.Favorites#ITEM_TYPE_SHORTCUT},
+     * {@link LauncherSettings.Favorites#ITEM_TYPE_USER_FOLDER},
+     * {@link LauncherSettings.Favorites#ITEM_TYPE_WIDGET_CLOCK},
+     * {@link LauncherSettings.Favorites#ITEM_TYPE_WIDGET_SEARCH} or
+     * {@link LauncherSettings.Favorites#ITEM_TYPE_WIDGET_PHOTO_FRAME},
      */
     int itemType;
     
     /**
      * The id of the container that holds this item. For the desktop, this will be 
-     * {@link Settings.Favorites#CONTAINER_DESKTOP}. For the all applications folder it 
+     * {@link LauncherSettings.Favorites#CONTAINER_DESKTOP}. For the all applications folder it
      * will be {@link #NO_ID} (since it is not stored in the settings DB). For user folders
      * it will be the id of the folder.
      */
@@ -100,13 +98,13 @@
      * @param values
      */
     void onAddToDatabase(ContentValues values) { 
-        values.put(Settings.Favorites.ITEM_TYPE, itemType);
-        values.put(Settings.Favorites.CONTAINER, container);
-        values.put(Settings.Favorites.SCREEN, screen);
-        values.put(Settings.Favorites.CELLX, cellX);
-        values.put(Settings.Favorites.CELLY, cellY);
-        values.put(Settings.Favorites.SPANX, spanX);
-        values.put(Settings.Favorites.SPANY, spanY);
+        values.put(LauncherSettings.Favorites.ITEM_TYPE, itemType);
+        values.put(LauncherSettings.Favorites.CONTAINER, container);
+        values.put(LauncherSettings.Favorites.SCREEN, screen);
+        values.put(LauncherSettings.Favorites.CELLX, cellX);
+        values.put(LauncherSettings.Favorites.CELLY, cellY);
+        values.put(LauncherSettings.Favorites.SPANX, spanX);
+        values.put(LauncherSettings.Favorites.SPANY, spanY);
     }
 
     static void writeBitmap(ContentValues values, Bitmap bitmap) {
@@ -120,7 +118,7 @@
                 out.flush();
                 out.close();
 
-                values.put(Settings.Favorites.ICON, out.toByteArray());
+                values.put(LauncherSettings.Favorites.ICON, out.toByteArray());
             } catch (IOException e) {
                 Log.w("Favorite", "Could not write icon");
             }
diff --git a/src/com/android/launcher/Launcher.java b/src/com/android/launcher/Launcher.java
index 2ae5037..928f4ca 100644
--- a/src/com/android/launcher/Launcher.java
+++ b/src/com/android/launcher/Launcher.java
@@ -29,16 +29,15 @@
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.SharedPreferences;
 import android.content.pm.PackageManager;
-import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.content.res.Configuration;
 import android.database.ContentObserver;
 import android.graphics.Bitmap;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.TransitionDrawable;
-import android.hardware.SensorListener;
-import android.hardware.SensorManager;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
@@ -46,15 +45,12 @@
 import android.os.Parcelable;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.os.SystemClock;
-import android.os.SystemProperties;
-import android.provider.Contacts;
+import android.provider.*;
 import android.telephony.PhoneNumberUtils;
 import android.text.Selection;
 import android.text.SpannableStringBuilder;
 import android.text.TextUtils;
 import android.text.method.TextKeyListener;
-import android.util.Config;
 import android.util.Log;
 import android.view.Display;
 import android.view.Gravity;
@@ -66,14 +62,15 @@
 import android.view.ViewGroup;
 import android.view.WindowManager;
 import android.view.View.OnLongClickListener;
+import android.view.inputmethod.InputMethodManager;
 import android.widget.EditText;
 import android.widget.ExpandableListView;
 import android.widget.ImageView;
 import android.widget.TextView;
 import android.widget.Toast;
+import android.widget.GridView;
 import android.app.IWallpaperService;
 
-import com.android.internal.provider.Settings;
 import com.android.internal.widget.SlidingDrawer;
 
 import java.lang.ref.WeakReference;
@@ -88,18 +85,8 @@
     private static final boolean PROFILE_STARTUP = false;
     private static final boolean DEBUG_USER_INTERFACE = false;
 
-    private static final String USE_OPENGL_BY_DEFAULT = "false";
-
     private static final boolean REMOVE_SHORTCUT_ON_PACKAGE_REMOVE = false;    
 
-    // Type: boolean
-    private static final String PROPERTY_USE_OPENGL = "launcher.opengl";
-    // Type: boolean
-    private static final String PROPERTY_USE_SENSORS = "launcher.sensors";
-
-    private static final boolean USE_OPENGL = true;
-    private static final boolean USE_SENSORS = false;
-
     private static final int WALLPAPER_SCREENS_SPAN = 2;
 
     private static final int MENU_GROUP_ADD = 1;
@@ -112,9 +99,11 @@
     private static final int REQUEST_CREATE_SHORTCUT = 1;
     private static final int REQUEST_CHOOSE_PHOTO = 2;
     private static final int REQUEST_UPDATE_PHOTO = 3;
+    private static final int REQUEST_CREATE_LIVE_FOLDER = 4;
 
     static final String EXTRA_SHORTCUT_DUPLICATE = "duplicate";
 
+    static final int SCREEN_COUNT = 3;
     static final int DEFAULT_SCREN = 1;
     static final int NUMBER_CELLS_X = 4;
     static final int NUMBER_CELLS_Y = 4;    
@@ -122,6 +111,11 @@
     private static final int DIALOG_CREATE_SHORTCUT = 1;
     static final int DIALOG_RENAME_FOLDER = 2;    
 
+    private static final String PREFERENCES = "launcher";
+    private static final String KEY_LOCALE = "locale";
+    private static final String KEY_MCC = "mcc";
+    private static final String KEY_MNC = "mnc";
+
     // Type: int
     private static final String RUNTIME_STATE_CURRENT_SCREEN = "launcher.current_screen";
     // Type: boolean
@@ -165,19 +159,15 @@
     private final BroadcastReceiver mApplicationsReceiver = new ApplicationsIntentReceiver();
     private final ContentObserver mObserver = new FavoritesChangeObserver();
 
-    private final Handler mHandler = new Handler();
     private LayoutInflater mInflater;
 
-    private SensorManager mSensorManager;
-    private SensorHandler mSensorHandler;
-
     private DragLayer mDragLayer;
     private Workspace mWorkspace;
 
     private CellLayout.CellInfo mAddItemCellInfo;
     private CellLayout.CellInfo mMenuAddInfo;
     private final int[] mCellCoordinates = new int[2];
-    private UserFolderInfo mFolderInfo;
+    private FolderInfo mFolderInfo;
 
     private SlidingDrawer mDrawer;
     private TransitionDrawable mHandleIcon;
@@ -192,11 +182,10 @@
 
     private boolean mRestoring;
     private boolean mWaitingForResult;
+    private boolean mLocaleChanged;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
-        dalvik.system.VMRuntime.getRuntime().setMinimumHeapSize(4 * 1024 * 1024);
-
         super.onCreate(savedInstanceState);
         mInflater = getLayoutInflater();
 
@@ -204,11 +193,9 @@
             android.os.Debug.startMethodTracing("/sdcard/launcher");
         }
 
+        checkForLocaleChange();
         setWallpaperDimension();
 
-        enableSensors();
-        enableOpenGL();
-
         if (sModel == null) {
             sModel = new LauncherModel();
         }
@@ -234,6 +221,30 @@
         mDefaultKeySsb = new SpannableStringBuilder();
         Selection.setSelection(mDefaultKeySsb, 0);
     }
+    
+    private void checkForLocaleChange() {
+        final SharedPreferences preferences = getSharedPreferences(PREFERENCES, MODE_PRIVATE);
+        final Configuration configuration = getResources().getConfiguration();
+
+        final String previousLocale = preferences.getString(KEY_LOCALE, null);
+        final String locale = configuration.locale.toString();
+
+        final int previousMcc = preferences.getInt(KEY_MCC, -1);
+        final int mcc = configuration.mcc;
+
+        final int previousMnc = preferences.getInt(KEY_MNC, -1);
+        final int mnc = configuration.mnc;
+
+        mLocaleChanged = !locale.equals(previousLocale) || mcc != previousMcc || mnc != previousMnc;
+
+        if (mLocaleChanged) {
+            final SharedPreferences.Editor editor = preferences.edit();
+            editor.putString(KEY_LOCALE, locale);
+            editor.putInt(KEY_MCC, mcc);
+            editor.putInt(KEY_MNC, mnc);
+            editor.commit();
+        }
+    }
 
     static int getScreen() {
         synchronized (sLock) {
@@ -248,19 +259,11 @@
     }
 
     private void startLoaders() {
-        sModel.loadApplications(true, this);
-        sModel.loadUserItems(true, this);
+        sModel.loadApplications(true, this, mLocaleChanged);
+        sModel.loadUserItems(!mLocaleChanged, this, mLocaleChanged);
         mRestoring = false;
     }
 
-    @Override
-    public void onConfigurationChanged(Configuration newConfig) {
-        super.onConfigurationChanged(newConfig);
-
-        // When MMC/MNC changes, so can applications, so we reload them
-        sModel.loadApplications(false, Launcher.this);
-    }
-
     private void setWallpaperDimension() {
         IBinder binder = ServiceManager.getService(WALLPAPER_SERVICE);
         IWallpaperService wallpaperService = IWallpaperService.Stub.asInterface(binder);
@@ -277,31 +280,6 @@
         }
     }
 
-    private void enableSensors() {
-        //noinspection PointlessBooleanExpression,ConstantConditions
-        if (USE_SENSORS || "true".equals(SystemProperties.get(PROPERTY_USE_SENSORS, "false"))) {
-            if (Config.LOGD) {
-                Log.d(LOG_TAG, "Launcher activating sensors");
-            }
-            mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
-            mSensorHandler = new SensorHandler();
-        }
-    }
-
-    private void enableOpenGL() {
-        //noinspection PointlessBooleanExpression,ConstantConditions
-        if (USE_OPENGL && "true".equals(SystemProperties.get(PROPERTY_USE_OPENGL,
-                USE_OPENGL_BY_DEFAULT))) {
-            if (Config.LOGD) {
-                Log.d(LOG_TAG, "Launcher starting in OpenGL");
-            }
-            //requestWindowFeature(Window.FEATURE_OPENGL);
-            //sOpenGlEnabled = true;
-        } else {
-            sOpenGlEnabled = false;
-        }
-    }
-
     @Override
     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
         if (resultCode == RESULT_OK && mAddItemCellInfo != null) {
@@ -315,6 +293,9 @@
                 case REQUEST_UPDATE_PHOTO:
                     completeUpdatePhotoFrame(data, mAddItemCellInfo);
                     break;
+                case REQUEST_CREATE_LIVE_FOLDER:
+                    completeAddLiveFolder(data, mAddItemCellInfo, !mDesktopLocked);
+                    break;
             }
         }
         mWaitingForResult = false;
@@ -327,19 +308,6 @@
         if (mRestoring) {
             startLoaders();
         }
-
-        if (mSensorManager != null) {
-            mSensorManager.registerListener(mSensorHandler, SensorManager.SENSOR_ACCELEROMETER);
-        }
-    }
-
-    @Override
-    protected void onStop() {
-        if (mSensorManager != null) {
-            mSensorManager.unregisterListener(mSensorHandler);
-        }
-
-        super.onStop();
     }
 
     @Override
@@ -347,6 +315,7 @@
         boolean handled = super.onKeyUp(keyCode, event);
         if (keyCode == KeyEvent.KEYCODE_SEARCH) {
             handled = mWorkspace.snapToSearch();
+            if (handled) closeDrawer(true);
         }
         return handled;
     }
@@ -455,7 +424,8 @@
 
         final DeleteZone deleteZone = (DeleteZone) dragLayer.findViewById(R.id.delete_zone);
 
-        final ImageView handleIcon = (ImageView) drawer.findViewById(R.id.all_apps);
+        final HandleView handleIcon = (HandleView) drawer.findViewById(R.id.all_apps);
+        handleIcon.setLauncher(this);
         mHandleIcon = (TransitionDrawable) handleIcon.getDrawable();
         mHandleIcon.setCrossFadeEnabled(true);
 
@@ -577,7 +547,7 @@
         Intent.ShortcutIconResource iconResource = null;
 
         if (bitmap != null) {
-            icon = new BitmapDrawable(Utilities.createBitmapThumbnail(bitmap, context));
+            icon = new FastBitmapDrawable(Utilities.createBitmapThumbnail(bitmap, context));
             filtered = true;
             customIcon = true;
         } else {
@@ -608,7 +578,7 @@
         info.customIcon = customIcon;
         info.iconResource = iconResource;
 
-        LauncherModel.addItemToDatabase(context, info, Settings.Favorites.CONTAINER_DESKTOP,
+        LauncherModel.addItemToDatabase(context, info, LauncherSettings.Favorites.CONTAINER_DESKTOP,
                 cellInfo.screen, cellInfo.cellX, cellInfo.cellY, notify);
         return info;
     }
@@ -630,7 +600,7 @@
             final int[] xy = mCellCoordinates;
             if (!findSlot(cellInfo, xy, info.spanX, info.spanY)) return;
 
-            LauncherModel.addItemToDatabase(this, info, Settings.Favorites.CONTAINER_DESKTOP,
+            LauncherModel.addItemToDatabase(this, info, LauncherSettings.Favorites.CONTAINER_DESKTOP,
                     mWorkspace.getCurrentScreen(), xy[0], xy[1], false);
 
             if (!mRestoring) {
@@ -746,6 +716,12 @@
                     mWorkspace.moveToDefaultScreen();
                 }
                 closeDrawer();
+                View v = getWindow().peekDecorView();
+                if (v != null && v.getWindowToken() != null) {
+                    InputMethodManager imm = (InputMethodManager)getSystemService(
+                            INPUT_METHOD_SERVICE);
+                    imm.hideSoftInputFromWindow(v.getWindowToken());
+                }
             } else {
                 closeDrawer(false);
             }
@@ -818,6 +794,16 @@
     }
 
     @Override
+    public void startSearch(String initialQuery, boolean selectInitialQuery, 
+            Bundle appSearchData, boolean globalSearch) {
+        if (appSearchData == null) {
+            appSearchData = new Bundle();
+            appSearchData.putString(SearchManager.SOURCE, "launcher-search");
+        }
+        super.startSearch(initialQuery, selectInitialQuery, appSearchData, globalSearch);
+    }
+
+    @Override
     public boolean onCreateOptionsMenu(Menu menu) {
         if (mDesktopLocked) return false;
 
@@ -893,6 +879,10 @@
         startActivityForResult(intent, REQUEST_CREATE_SHORTCUT);
     }
 
+    void addLiveFolder(Intent intent) {
+        startActivityForResult(intent, REQUEST_CREATE_LIVE_FOLDER);
+    }
+
     void addFolder() {
         UserFolderInfo folderInfo = new UserFolderInfo();
         folderInfo.title = getText(R.string.folder_name);
@@ -900,10 +890,10 @@
         int cellY = mAddItemCellInfo.cellY;
 
         // Update the model
-        LauncherModel.addItemToDatabase(this, folderInfo, Settings.Favorites.CONTAINER_DESKTOP,
+        LauncherModel.addItemToDatabase(this, folderInfo, LauncherSettings.Favorites.CONTAINER_DESKTOP,
                 mWorkspace.getCurrentScreen(), cellX, cellY, false);
         sModel.addDesktopItem(folderInfo);
-        sModel.addUserFolder(folderInfo);
+        sModel.addFolder(folderInfo);
 
         // Create the view
         FolderIcon newFolder = FolderIcon.fromXml(R.layout.folder_icon, this,
@@ -911,6 +901,68 @@
         mWorkspace.addInCurrentScreen(newFolder, cellX, cellY, 1, 1);
     }
 
+    private void completeAddLiveFolder(Intent data, CellLayout.CellInfo cellInfo,
+            boolean insertAtFirst) {
+
+        cellInfo.screen = mWorkspace.getCurrentScreen();
+        final LiveFolderInfo info = addLiveFolder(this, data, cellInfo, false);
+
+        if (!mRestoring) {
+            sModel.addDesktopItem(info);
+
+            final View view = LiveFolderIcon.fromXml(R.layout.live_folder_icon, this,
+                (ViewGroup) mWorkspace.getChildAt(mWorkspace.getCurrentScreen()), info);
+            mWorkspace.addInCurrentScreen(view, cellInfo.cellX, cellInfo.cellY, 1, 1, insertAtFirst);
+        } else if (sModel.isDesktopLoaded()) {
+            sModel.addDesktopItem(info);
+        }
+    }
+
+    static LiveFolderInfo addLiveFolder(Context context, Intent data,
+            CellLayout.CellInfo cellInfo, boolean notify) {
+
+        Intent baseIntent = data.getParcelableExtra(LiveFolders.EXTRA_LIVE_FOLDER_BASE_INTENT);
+        String name = data.getStringExtra(LiveFolders.EXTRA_LIVE_FOLDER_NAME);
+
+        Drawable icon = null;
+        boolean filtered = false;
+        Intent.ShortcutIconResource iconResource = null;
+
+        Parcelable extra = data.getParcelableExtra(LiveFolders.EXTRA_LIVE_FOLDER_ICON);
+        if (extra != null && extra instanceof Intent.ShortcutIconResource) {
+            try {
+                iconResource = (Intent.ShortcutIconResource) extra;
+                final PackageManager packageManager = context.getPackageManager();
+                Resources resources = packageManager.getResourcesForApplication(
+                        iconResource.packageName);
+                final int id = resources.getIdentifier(iconResource.resourceName, null, null);
+                icon = resources.getDrawable(id);
+            } catch (Exception e) {
+                Log.w(LOG_TAG, "Could not load live folder icon: " + extra);
+            }
+        }
+
+        if (icon == null) {
+            icon = context.getResources().getDrawable(R.drawable.ic_launcher_folder);
+        }
+
+        final LiveFolderInfo info = new LiveFolderInfo();
+        info.icon = icon;
+        info.filtered = filtered;
+        info.title = name;
+        info.iconResource = iconResource;
+        info.uri = data.getData();
+        info.baseIntent = baseIntent;
+        info.displayMode = data.getIntExtra(LiveFolders.EXTRA_LIVE_FOLDER_DISPLAY_MODE,
+                LiveFolders.DISPLAY_MODE_GRID);
+
+        LauncherModel.addItemToDatabase(context, info, LauncherSettings.Favorites.CONTAINER_DESKTOP,
+                cellInfo.screen, cellInfo.cellX, cellInfo.cellY, notify);
+        sModel.addFolder(info);
+
+        return info;
+    }
+
     void getPhotoForPhotoFrame() {
         startActivityForResult(createPhotoPickIntent(), REQUEST_CHOOSE_PHOTO);
     }
@@ -935,7 +987,7 @@
         if (!findSlot(cellInfo, xy, spanX, spanY)) return;
 
         sModel.addDesktopItem(info);
-        LauncherModel.addItemToDatabase(this, info, Settings.Favorites.CONTAINER_DESKTOP,
+        LauncherModel.addItemToDatabase(this, info, LauncherSettings.Favorites.CONTAINER_DESKTOP,
                 mWorkspace.getCurrentScreen(), xy[0], xy[1], false);
 
         final View view = mInflater.inflate(info.layoutResource, null);
@@ -999,7 +1051,7 @@
      */
     private void registerContentObservers() {
         ContentResolver resolver = getContentResolver();
-        resolver.registerContentObserver(Settings.Favorites.CONTENT_URI, true, mObserver);
+        resolver.registerContentObserver(LauncherSettings.Favorites.CONTENT_URI, true, mObserver);
     }
 
     @Override
@@ -1059,7 +1111,7 @@
     private void onFavoritesChanged() {
         mDesktopLocked = true;
         mDrawer.lock();
-        sModel.loadUserItems(false, this);
+        sModel.loadUserItems(false, this, false);
     }
 
     void onDesktopItemsLoaded() {
@@ -1074,9 +1126,9 @@
             final long[] userFolders = mSavedState.getLongArray(RUNTIME_STATE_USER_FOLDERS);
             if (userFolders != null) {
                 for (long folderId : userFolders) {
-                    final UserFolderInfo info = sModel.findFolderById(folderId);
+                    final FolderInfo info = sModel.findFolderById(folderId);
                     if (info != null) {
-                        openUserFolder(info);
+                        openFolder(info);
                     }
                 }
                 final Folder openFolder = mWorkspace.getOpenFolder();
@@ -1119,19 +1171,27 @@
         for (int i = 0; i < count; i++) {
             final ItemInfo item = shortcuts.get(i);
             switch (item.itemType) {
-            case Settings.Favorites.ITEM_TYPE_APPLICATION:
-            case Settings.Favorites.ITEM_TYPE_SHORTCUT:
+            case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
+            case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
                 final View shortcut = createShortcut((ApplicationInfo) item);
                 workspace.addInScreen(shortcut, item.screen, item.cellX, item.cellY, 1, 1,
                         !mDesktopLocked);
                 break;
-            case Settings.Favorites.ITEM_TYPE_USER_FOLDER:
+            case LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER:
                 final FolderIcon newFolder = FolderIcon.fromXml(R.layout.folder_icon, this,
                         (ViewGroup) mWorkspace.getChildAt(mWorkspace.getCurrentScreen()),
                         ((UserFolderInfo) item));
                 workspace.addInScreen(newFolder, item.screen, item.cellX, item.cellY, 1, 1,
                         !mDesktopLocked);
                 break;
+            case LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER:
+                final FolderIcon newLiveFolder = LiveFolderIcon.fromXml(
+                        R.layout.live_folder_icon, this,
+                        (ViewGroup) mWorkspace.getChildAt(mWorkspace.getCurrentScreen()),
+                        ((LiveFolderInfo) item));
+                workspace.addInScreen(newLiveFolder, item.screen, item.cellX, item.cellY, 1, 1,
+                        !mDesktopLocked);
+                break;
             default:
                 final Widget widget = (Widget)item;
                 final View view = createWidget(mInflater, widget);
@@ -1148,7 +1208,7 @@
         final int screen = workspace.getCurrentScreen();
         View v = inflater.inflate(widget.layoutResource,
                 (ViewGroup) workspace.getChildAt(screen), false);
-        if (widget.itemType == Settings.Favorites.ITEM_TYPE_WIDGET_PHOTO_FRAME) {
+        if (widget.itemType == LauncherSettings.Favorites.ITEM_TYPE_WIDGET_PHOTO_FRAME) {
             ((ImageView)v).setImageBitmap(widget.photo);
         }
         return v;
@@ -1169,8 +1229,8 @@
             // Open shortcut
             final Intent intent = ((ApplicationInfo) tag).intent;
             startActivitySafely(intent);
-        } else if (tag instanceof UserFolderInfo) {
-            handleFolderClick((UserFolderInfo) tag);
+        } else if (tag instanceof FolderInfo) {
+            handleFolderClick((FolderInfo) tag);
         }
     }
 
@@ -1188,7 +1248,7 @@
             // Close any open folder
             closeFolder();
             // Open the requested folder
-            openUserFolder(folderInfo);
+            openFolder(folderInfo);
         } else {
             // Find the open folder...
             Folder openFolder = mWorkspace.getFolderForTag(folderInfo);
@@ -1201,7 +1261,7 @@
                     // Close any folder open on the current screen
                     closeFolder();
                     // Pull the folder onto this screen
-                    openUserFolder(folderInfo);
+                    openFolder(folderInfo);
                 }
             }
         }
@@ -1226,14 +1286,22 @@
      * is animated relative to the specified View. If the View is null, no animation
      * is played.
      *
-     * @param tag The UserFolderInfo describing the folder to open.
+     * @param folderInfo The FolderInfo describing the folder to open.
      */
-    private void openUserFolder(Object tag) {
-        UserFolder openFolder = UserFolder.fromXml(this);
+    private void openFolder(FolderInfo folderInfo) {
+        Folder openFolder;
+
+        if (folderInfo instanceof UserFolderInfo) {
+            openFolder = UserFolder.fromXml(this);
+        } else if (folderInfo instanceof LiveFolderInfo) {
+            openFolder = com.android.launcher.LiveFolder.fromXml(this, folderInfo);
+        } else {
+            return;
+        }
+
         openFolder.setDragger(mDragLayer);
         openFolder.setLauncher(this);
 
-        UserFolderInfo folderInfo = (UserFolderInfo) tag;
         openFolder.bind(folderInfo);
         folderInfo.opened = true;
 
@@ -1299,6 +1367,10 @@
         return mWorkspace;
     }
 
+    GridView getApplicationsGrid() {
+        return mAllAppsGrid;
+    }
+
     @Override
     protected Dialog onCreateDialog(int id) {
         switch (id) {
@@ -1327,7 +1399,7 @@
         }
     }
 
-    void showRenameDialog(UserFolderInfo info) {
+    void showRenameDialog(FolderInfo info) {
         mFolderInfo = info;
         mWaitingForResult = true;
         showDialog(DIALOG_RENAME_FOLDER);
@@ -1384,16 +1456,17 @@
 
                 if (mDesktopLocked) {
                     mDrawer.lock();
-                    sModel.loadUserItems(false, Launcher.this);
+                    sModel.loadUserItems(false, Launcher.this, false);
                 } else {
-                    final FolderIcon folderIcon = (FolderIcon) mWorkspace.getViewForTag(mFolderInfo);
+                    final FolderIcon folderIcon = (FolderIcon)
+                            mWorkspace.getViewForTag(mFolderInfo);
                     if (folderIcon != null) {
                         folderIcon.setText(name);
                         getWorkspace().requestLayout();
                     } else {
                         mDesktopLocked = true;
                         mDrawer.lock();
-                        sModel.loadUserItems(false, Launcher.this);
+                        sModel.loadUserItems(false, Launcher.this, false);
                     }
                 }
             }
@@ -1479,7 +1552,7 @@
                 removeShortcutsForPackage(intent.getData().getSchemeSpecificPart());
             }
             removeDialog(DIALOG_CREATE_SHORTCUT);
-            sModel.loadApplications(false, Launcher.this);
+            sModel.loadApplications(false, Launcher.this, false);
         }
     }
 
@@ -1488,7 +1561,7 @@
      */
     private class FavoritesChangeObserver extends ContentObserver {
         public FavoritesChangeObserver() {
-            super(mHandler);
+            super(new Handler());
         }
 
         @Override
@@ -1497,34 +1570,6 @@
         }
     }
 
-    private class SensorHandler implements SensorListener {
-        private long mLastNegativeShake;
-        private long mLastPositiveShake;
-
-        public void onSensorChanged(int sensor, float[] values) {
-            if (sensor == SensorManager.SENSOR_ACCELEROMETER) {
-                float shake = values[0];
-                if (shake <= -SensorManager.STANDARD_GRAVITY) {
-                    mLastNegativeShake = SystemClock.uptimeMillis();
-                } else if (shake >= SensorManager.STANDARD_GRAVITY) {
-                    mLastPositiveShake = SystemClock.uptimeMillis();
-                }
-
-                final long difference = mLastPositiveShake - mLastNegativeShake;
-                if (difference <= -80 && difference >= -180) {
-                    mWorkspace.scrollLeft();
-                    mLastNegativeShake = mLastPositiveShake = 0;
-                } else if (difference >= 80 && difference <= 180) {
-                    mWorkspace.scrollRight();
-                    mLastNegativeShake = mLastPositiveShake = 0;
-                }
-            }
-        }
-
-        public void onAccuracyChanged(int sensor, int accuracy) {
-        }
-    }
-
     /**
      * Receives intents from other applications to change the wallpaper.
      */
diff --git a/src/com/android/launcher/LauncherApplication.java b/src/com/android/launcher/LauncherApplication.java
new file mode 100644
index 0000000..d71fa19
--- /dev/null
+++ b/src/com/android/launcher/LauncherApplication.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2008 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.launcher;
+
+import android.app.Application;
+import dalvik.system.VMRuntime;
+
+public class LauncherApplication extends Application {
+    @Override
+    public void onCreate() {
+        VMRuntime.getRuntime().setMinimumHeapSize(4 * 1024 * 1024);
+
+        super.onCreate();
+    }
+}
diff --git a/src/com/android/launcher/LauncherModel.java b/src/com/android/launcher/LauncherModel.java
index 8375bbe..0ef2a80 100644
--- a/src/com/android/launcher/LauncherModel.java
+++ b/src/com/android/launcher/LauncherModel.java
@@ -30,7 +30,6 @@
 import android.graphics.BitmapFactory;
 import android.graphics.drawable.BitmapDrawable;
 import android.net.Uri;
-import com.android.internal.provider.Settings;
 import android.util.Log;
 
 import java.util.ArrayList;
@@ -40,6 +39,7 @@
 import java.util.Comparator;
 import java.lang.ref.WeakReference;
 import java.text.Collator;
+import java.net.URISyntaxException;
 
 /**
  * Maintains in-memory state of the Launcher. It is expected that there should be only one
@@ -58,7 +58,7 @@
     private boolean mDesktopItemsLoaded;
 
     private ArrayList<ItemInfo> mDesktopItems;
-    private HashMap<Long, UserFolderInfo> mUserFolders;
+    private HashMap<Long, FolderInfo> mFolders;
 
     private ArrayList<ApplicationInfo> mApplications;
     private ApplicationsAdapter mApplicationsAdapter;
@@ -81,13 +81,13 @@
     /**
      * Loads the list of installed applications in mApplications.
      */
-    void loadApplications(boolean isLaunching, Launcher launcher) {
-        if (isLaunching && mApplicationsLoaded) {
+    void loadApplications(boolean isLaunching, Launcher launcher, boolean localeChanged) {
+        if (isLaunching && mApplicationsLoaded && !localeChanged) {
             mApplicationsAdapter = new ApplicationsAdapter(launcher, mApplications);
             return;
         }
 
-        if (mApplicationsAdapter == null || isLaunching) {
+        if (mApplicationsAdapter == null || isLaunching || localeChanged) {
             mApplicationsAdapter = new ApplicationsAdapter(launcher,
                     mApplications = new ArrayList<ApplicationInfo>(DEFAULT_APPLICATIONS_NUMBER));
         }
@@ -164,7 +164,7 @@
 
                 action.sort(new Comparator<ApplicationInfo>() {
                     public final int compare(ApplicationInfo a, ApplicationInfo b) {
-                        return sCollator.compare(a.title, b.title);
+                        return sCollator.compare(a.title.toString(), b.title.toString());
                     }
                 });
 
@@ -221,7 +221,7 @@
      * Loads all of the items on the desktop, in folders, or in the dock.
      * These can be apps, shortcuts or widgets
      */
-    void loadUserItems(boolean isLaunching, Launcher launcher) {
+    void loadUserItems(boolean isLaunching, Launcher launcher, boolean localeChanged) {
         if (isLaunching && mDesktopItems != null && mDesktopItemsLoaded) {
             // We have already loaded our data from the DB
             launcher.onDesktopItemsLoaded();
@@ -240,19 +240,88 @@
         }
 
         mDesktopItemsLoaded = false;
-        mDesktopItemsLoader = new DesktopItemsLoader(launcher);
+        mDesktopItemsLoader = new DesktopItemsLoader(launcher, localeChanged);
         mDesktopLoader = new Thread(mDesktopItemsLoader, "Desktop Items Loader");
         mDesktopLoader.start();
     }
 
+    private static void updateShortcutLabels(ContentResolver resolver, PackageManager manager) {
+        final Cursor c = resolver.query(LauncherSettings.Favorites.CONTENT_URI,
+                new String[] { LauncherSettings.Favorites.ID, LauncherSettings.Favorites.TITLE,
+                        LauncherSettings.Favorites.INTENT, LauncherSettings.Favorites.ITEM_TYPE },
+                null, null, null);
+
+        final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ID);
+        final int intentIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.INTENT);
+        final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);
+        final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);
+
+        // boolean changed = false;
+
+        try {
+            while (c.moveToNext()) {
+                try {
+                    if (c.getInt(itemTypeIndex) != LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
+                        continue;
+                    }
+
+                    final String intentUri = c.getString(intentIndex);
+                    if (intentUri != null) {
+                        final Intent shortcut = Intent.getIntent(intentUri);
+                        if (Intent.ACTION_MAIN.equals(shortcut.getAction())) {
+                            final ComponentName name = shortcut.getComponent();
+                            if (name != null) {
+                                final ActivityInfo activityInfo = manager.getActivityInfo(name, 0);
+                                final String title = c.getString(titleIndex);
+                                String label = getLabel(manager, activityInfo);
+
+                                if (title == null || !title.equals(label)) {
+                                    final ContentValues values = new ContentValues();
+                                    values.put(LauncherSettings.Favorites.TITLE, label);
+
+                                    resolver.update(LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION,
+                                            values, "_id=?",
+                                            new String[] { String.valueOf(c.getLong(idIndex)) });
+
+                                    // changed = true;
+                                }
+                            }
+                        }
+                    }
+                } catch (URISyntaxException e) {
+                    // Ignore
+                } catch (PackageManager.NameNotFoundException e) {
+                    // Ignore
+                }
+            }
+        } finally {
+            c.close();
+        }
+
+        // if (changed) resolver.notifyChange(Settings.Favorites.CONTENT_URI, null);
+    }
+
+    private static String getLabel(PackageManager manager, ActivityInfo activityInfo) {
+        String label = activityInfo.loadLabel(manager).toString();
+        if (label == null) {
+            label = manager.getApplicationLabel(activityInfo.applicationInfo).toString();
+            if (label == null) {
+                label = activityInfo.name;
+            }
+        }
+        return label;
+    }
+
     private class DesktopItemsLoader implements Runnable {
         private volatile boolean mStopped;
         private volatile boolean mRunning;
 
         private final WeakReference<Launcher> mLauncher;
+        private boolean mLocaleChanged;
 
-        DesktopItemsLoader(Launcher launcher) {
+        DesktopItemsLoader(Launcher launcher, boolean localeChanged) {
             mLauncher = new WeakReference<Launcher>(launcher);
+            mLocaleChanged = localeChanged;
         }
 
         void stop() {
@@ -267,54 +336,61 @@
             mRunning = true;
 
             final Launcher launcher = mLauncher.get();
+            final ContentResolver contentResolver = launcher.getContentResolver();
+            final PackageManager manager = launcher.getPackageManager();
+
+            if (mLocaleChanged) {
+                updateShortcutLabels(contentResolver, manager);
+            }
 
             mDesktopItems = new ArrayList<ItemInfo>();
-            mUserFolders = new HashMap<Long, UserFolderInfo>();
+            mFolders = new HashMap<Long, FolderInfo>();
 
             final ArrayList<ItemInfo> desktopItems = mDesktopItems;
 
-            final Cursor c = launcher.getContentResolver().query(Settings.Favorites.CONTENT_URI,
-                    null, null, null, null);
+            final Cursor c = contentResolver.query(
+                    LauncherSettings.Favorites.CONTENT_URI, null, null, null, null);
 
             try {
-                final int idIndex = c.getColumnIndexOrThrow(Settings.Favorites.ID);
-                final int intentIndex = c.getColumnIndexOrThrow(Settings.Favorites.INTENT);
-                final int titleIndex = c.getColumnIndexOrThrow(Settings.Favorites.TITLE);
-                final int iconTypeIndex = c.getColumnIndexOrThrow(Settings.Favorites.ICON_TYPE);
-                final int iconIndex = c.getColumnIndexOrThrow(Settings.Favorites.ICON);
-                final int iconPackageIndex = c.getColumnIndexOrThrow(Settings.Favorites.ICON_PACKAGE);
-                final int iconResourceIndex = c.getColumnIndexOrThrow(Settings.Favorites.ICON_RESOURCE);
-                final int containerIndex = c.getColumnIndexOrThrow(Settings.Favorites.CONTAINER);
-                final int itemTypeIndex = c.getColumnIndexOrThrow(Settings.Favorites.ITEM_TYPE);
-                final int screenIndex = c.getColumnIndexOrThrow(Settings.Favorites.SCREEN);
-                final int cellXIndex = c.getColumnIndexOrThrow(Settings.Favorites.CELLX);
-                final int cellYIndex = c.getColumnIndexOrThrow(Settings.Favorites.CELLY);
-
-                final PackageManager manager = launcher.getPackageManager();
+                final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ID);
+                final int intentIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.INTENT);
+                final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);
+                final int iconTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_TYPE);
+                final int iconIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON);
+                final int iconPackageIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_PACKAGE);
+                final int iconResourceIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_RESOURCE);
+                final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER);
+                final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);
+                final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);
+                final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);
+                final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);
+                final int uriIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.URI);
+                final int displayModeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.DISPLAY_MODE);
 
                 ApplicationInfo info;
                 String intentDescription;
                 Widget widgetInfo = null;
                 int container;
+                long id;
+                Intent intent;
 
-                final HashMap<Long, UserFolderInfo> userFolders = mUserFolders;
+                final HashMap<Long, FolderInfo> folders = mFolders;
 
                 while (!mStopped && c.moveToNext()) {
                     try {
                         int itemType = c.getInt(itemTypeIndex);
 
                         switch (itemType) {
-                        case Settings.Favorites.ITEM_TYPE_APPLICATION:
-                        case Settings.Favorites.ITEM_TYPE_SHORTCUT:
+                        case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
+                        case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
                             intentDescription = c.getString(intentIndex);
-                            Intent intent;
                             try {
                                 intent = Intent.getIntent(intentDescription);
                             } catch (java.net.URISyntaxException e) {
                                 continue;
                             }
 
-                            if (itemType == Settings.Favorites.ITEM_TYPE_APPLICATION) {
+                            if (itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
                                 info = getApplicationInfo(manager, intent);
                             } else {
                                 info = getApplicationInfoShortcut(c, launcher, iconTypeIndex,
@@ -338,22 +414,22 @@
                                 info.cellY = c.getInt(cellYIndex);
 
                                 switch (container) {
-                                case Settings.Favorites.CONTAINER_DESKTOP:
+                                case LauncherSettings.Favorites.CONTAINER_DESKTOP:
                                     desktopItems.add(info);
                                     break;
                                 default:
                                     // Item is in a user folder
                                     UserFolderInfo folderInfo =
-                                            findOrMakeFolder(userFolders, container);
+                                            findOrMakeUserFolder(folders, container);
                                     folderInfo.add(info);
                                     break;
                                 }
                             }
                             break;
-                        case Settings.Favorites.ITEM_TYPE_USER_FOLDER:
+                        case LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER:
 
-                            long id = c.getLong(idIndex);
-                            UserFolderInfo folderInfo = findOrMakeFolder(userFolders, id);
+                            id = c.getLong(idIndex);
+                            UserFolderInfo folderInfo = findOrMakeUserFolder(folders, id);
 
                             folderInfo.title = c.getString(titleIndex);
 
@@ -365,24 +441,57 @@
                             folderInfo.cellY = c.getInt(cellYIndex);
 
                             switch (container) {
-                            case Settings.Favorites.CONTAINER_DESKTOP:
-                                desktopItems.add(folderInfo);
-                                break;
-                            default:
-
+                                case LauncherSettings.Favorites.CONTAINER_DESKTOP:
+                                    desktopItems.add(folderInfo);
+                                    break;
                             }
                             break;
-                        case Settings.Favorites.ITEM_TYPE_WIDGET_CLOCK:
-                        case Settings.Favorites.ITEM_TYPE_WIDGET_SEARCH:
-                        case Settings.Favorites.ITEM_TYPE_WIDGET_PHOTO_FRAME:
+                        case LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER:
+
+                            id = c.getLong(idIndex);
+                            LiveFolderInfo liveFolderInfo = findOrMakeLiveFolder(folders, id);
+
+                            intentDescription = c.getString(intentIndex);
+                            intent = null;
+                            if (intentDescription != null) {
+                                try {
+                                    intent = Intent.getIntent(intentDescription);
+                                } catch (java.net.URISyntaxException e) {
+                                    // Ignore, a live folder might not have a base intent
+                                }
+                            }
+
+                            liveFolderInfo.title = c.getString(titleIndex);
+                            liveFolderInfo.id = id;
+                            container = c.getInt(containerIndex);
+                            liveFolderInfo.container = container;
+                            liveFolderInfo.screen = c.getInt(screenIndex);
+                            liveFolderInfo.cellX = c.getInt(cellXIndex);
+                            liveFolderInfo.cellY = c.getInt(cellYIndex);
+                            liveFolderInfo.uri = Uri.parse(c.getString(uriIndex));
+                            liveFolderInfo.baseIntent = intent;
+                            liveFolderInfo.displayMode = c.getInt(displayModeIndex);
+
+                            loadLiveFolderIcon(launcher, c, iconTypeIndex, iconPackageIndex,
+                                    iconResourceIndex, liveFolderInfo);
+
+                            switch (container) {
+                                case LauncherSettings.Favorites.CONTAINER_DESKTOP:
+                                    desktopItems.add(liveFolderInfo);
+                                    break;
+                            }
+                            break;
+                        case LauncherSettings.Favorites.ITEM_TYPE_WIDGET_CLOCK:
+                        case LauncherSettings.Favorites.ITEM_TYPE_WIDGET_SEARCH:
+                        case LauncherSettings.Favorites.ITEM_TYPE_WIDGET_PHOTO_FRAME:
                             switch (itemType) {
-                            case Settings.Favorites.ITEM_TYPE_WIDGET_CLOCK:
+                            case LauncherSettings.Favorites.ITEM_TYPE_WIDGET_CLOCK:
                                 widgetInfo = Widget.makeClock();
                                 break;
-                            case Settings.Favorites.ITEM_TYPE_WIDGET_SEARCH:
+                            case LauncherSettings.Favorites.ITEM_TYPE_WIDGET_SEARCH:
                                 widgetInfo = Widget.makeSearch();
                                 break;
-                            case Settings.Favorites.ITEM_TYPE_WIDGET_PHOTO_FRAME:
+                            case LauncherSettings.Favorites.ITEM_TYPE_WIDGET_PHOTO_FRAME:
                                 widgetInfo = Widget.makePhotoFrame();
                                 byte[] data = c.getBlob(iconIndex);
                                 if (data != null) {
@@ -394,7 +503,7 @@
 
                             if (widgetInfo != null) {
                                 container = c.getInt(containerIndex);
-                                if (container != Settings.Favorites.CONTAINER_DESKTOP) {
+                                if (container != LauncherSettings.Favorites.CONTAINER_DESKTOP) {
                                     Log.e(Launcher.LOG_TAG, "Widget found where container "
                                             + "!= CONTAINER_DESKTOP -- ignoring!");
                                     continue;
@@ -432,6 +541,33 @@
         }
     }
 
+    private static void loadLiveFolderIcon(Launcher launcher, Cursor c, int iconTypeIndex,
+            int iconPackageIndex, int iconResourceIndex, LiveFolderInfo liveFolderInfo) {
+
+        int iconType = c.getInt(iconTypeIndex);
+        switch (iconType) {
+            case LauncherSettings.Favorites.ICON_TYPE_RESOURCE:
+                String packageName = c.getString(iconPackageIndex);
+                String resourceName = c.getString(iconResourceIndex);
+                PackageManager packageManager = launcher.getPackageManager();
+                try {
+                    Resources resources = packageManager.getResourcesForApplication(packageName);
+                    final int id = resources.getIdentifier(resourceName, null, null);
+                    liveFolderInfo.icon = resources.getDrawable(id);
+                } catch (Exception e) {
+                    liveFolderInfo.icon =
+                            launcher.getResources().getDrawable(R.drawable.ic_launcher_folder);
+                }
+                liveFolderInfo.iconResource = new Intent.ShortcutIconResource();
+                liveFolderInfo.iconResource.packageName = packageName;
+                liveFolderInfo.iconResource.resourceName = resourceName;
+                break;
+            default:
+                liveFolderInfo.icon =
+                        launcher.getResources().getDrawable(R.drawable.ic_launcher_folder);                                    
+        }
+    }
+
     /**
      * Finds the user folder defined by the specified id.
      *
@@ -439,28 +575,42 @@
      * 
      * @return A UserFolderInfo if the folder exists or null otherwise.
      */
-    UserFolderInfo findFolderById(long id) {
-        return mUserFolders.get(id);
+    FolderInfo findFolderById(long id) {
+        return mFolders.get(id);
     }
 
-    void addUserFolder(UserFolderInfo info) {
-        mUserFolders.put(info.id, info);
+    void addFolder(FolderInfo info) {
+        mFolders.put(info.id, info);
     }
 
     /**
      * Return an existing UserFolderInfo object if we have encountered this ID previously, or make a
      * new one.
      */
-    private UserFolderInfo findOrMakeFolder(HashMap<Long, UserFolderInfo> userFolders, long id) {
-        UserFolderInfo folderInfo;
+    private UserFolderInfo findOrMakeUserFolder(HashMap<Long, FolderInfo> folders, long id) {
         // See if a placeholder was created for us already
-        folderInfo = userFolders.get(id);
-        if (folderInfo == null) {
+        FolderInfo folderInfo = folders.get(id);
+        if (folderInfo == null || !(folderInfo instanceof UserFolderInfo)) {
             // No placeholder -- create a new instance
             folderInfo = new UserFolderInfo();
-            userFolders.put(id, folderInfo);
+            folders.put(id, folderInfo);
         }
-        return folderInfo;
+        return (UserFolderInfo) folderInfo;
+    }
+
+    /**
+     * Return an existing UserFolderInfo object if we have encountered this ID previously, or make a
+     * new one.
+     */
+    private LiveFolderInfo findOrMakeLiveFolder(HashMap<Long, FolderInfo> folders, long id) {
+        // See if a placeholder was created for us already
+        FolderInfo folderInfo = folders.get(id);
+        if (folderInfo == null || !(folderInfo instanceof LiveFolderInfo)) {
+            // No placeholder -- create a new instance
+            folderInfo = new LiveFolderInfo();
+            folders.put(id, folderInfo);
+        }
+        return (LiveFolderInfo) folderInfo;
     }
 
     /**
@@ -483,8 +633,8 @@
             for (int i = 0; i < count; i++) {
                 ItemInfo item = desktopItems.get(i);
                 switch (item.itemType) {
-                case Settings.Favorites.ITEM_TYPE_APPLICATION:
-                case Settings.Favorites.ITEM_TYPE_SHORTCUT:
+                case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
+                case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
                     ((ApplicationInfo)item).icon.setCallback(null);
                 }
             }
@@ -562,7 +712,7 @@
         if (info.title == null) {
             info.title = "";
         }
-        info.itemType = Settings.Favorites.ITEM_TYPE_APPLICATION;
+        info.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
         return info;
     }
     
@@ -573,11 +723,11 @@
             int iconTypeIndex, int iconPackageIndex, int iconResourceIndex, int iconIndex) {
 
         final ApplicationInfo info = new ApplicationInfo();
-        info.itemType = Settings.Favorites.ITEM_TYPE_SHORTCUT;
+        info.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
 
         int iconType = c.getInt(iconTypeIndex);
         switch (iconType) {
-            case Settings.Favorites.ICON_TYPE_RESOURCE:
+            case LauncherSettings.Favorites.ICON_TYPE_RESOURCE:
                 String packageName = c.getString(iconPackageIndex);
                 String resourceName = c.getString(iconResourceIndex);
                 PackageManager packageManager = launcher.getPackageManager();
@@ -593,10 +743,11 @@
                 info.iconResource.resourceName = resourceName;
                 info.customIcon = false;
                 break;
-            case Settings.Favorites.ICON_TYPE_BITMAP:
+            case LauncherSettings.Favorites.ICON_TYPE_BITMAP:
                 byte[] data = c.getBlob(iconIndex);
                 Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
-                info.icon = new BitmapDrawable(Utilities.createBitmapThumbnail(bitmap, launcher));
+                info.icon = new FastBitmapDrawable(
+                        Utilities.createBitmapThumbnail(bitmap, launcher));
                 info.filtered = true;
                 info.customIcon = true;
                 break;
@@ -621,7 +772,7 @@
      * @param userFolderInfo
      */
     void removeUserFolder(UserFolderInfo userFolderInfo) {
-        mUserFolders.remove(userFolderInfo.id);
+        mFolders.remove(userFolderInfo.id);
     }
     
     /**
@@ -652,12 +803,12 @@
         final ContentValues values = new ContentValues();
         final ContentResolver cr = context.getContentResolver();
 
-        values.put(Settings.Favorites.CONTAINER, item.container);
-        values.put(Settings.Favorites.CELLX, item.cellX);
-        values.put(Settings.Favorites.CELLY, item.cellY);
-        values.put(Settings.Favorites.SCREEN, item.screen);
+        values.put(LauncherSettings.Favorites.CONTAINER, item.container);
+        values.put(LauncherSettings.Favorites.CELLX, item.cellX);
+        values.put(LauncherSettings.Favorites.CELLY, item.cellY);
+        values.put(LauncherSettings.Favorites.SCREEN, item.screen);
 
-        cr.update(Settings.Favorites.getContentUri(item.id, false), values, null, null);
+        cr.update(LauncherSettings.Favorites.getContentUri(item.id, false), values, null, null);
     }
 
     /**
@@ -666,7 +817,7 @@
      */
     static boolean shortcutExists(Context context, String title, Intent intent) {
         final ContentResolver cr = context.getContentResolver();
-        Cursor c = cr.query(Settings.Favorites.CONTENT_URI,
+        Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI,
             new String[] { "title", "intent" }, "title=? and intent=?",
             new String[] { title, intent.toURI() }, null);
         boolean result = false;
@@ -678,21 +829,32 @@
         return result;
     }
 
-    UserFolderInfo getFolderById(Context context, long id) {
+    FolderInfo getFolderById(Context context, long id) {
         final ContentResolver cr = context.getContentResolver();
-        Cursor c = cr.query(Settings.Favorites.CONTENT_URI, null, "_id=? and itemType=?",
-            new String[] { String.valueOf(id),
-                    String.valueOf(Settings.Favorites.ITEM_TYPE_USER_FOLDER) }, null);
+        Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI, null,
+                "_id=? and itemType=? or itemType=?",
+                new String[] { String.valueOf(id),
+                        String.valueOf(LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER),
+                        String.valueOf(LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER) }, null);
 
         try {
             if (c.moveToFirst()) {
-                final int titleIndex = c.getColumnIndexOrThrow(Settings.Favorites.TITLE);
-                final int containerIndex = c.getColumnIndexOrThrow(Settings.Favorites.CONTAINER);
-                final int screenIndex = c.getColumnIndexOrThrow(Settings.Favorites.SCREEN);
-                final int cellXIndex = c.getColumnIndexOrThrow(Settings.Favorites.CELLX);
-                final int cellYIndex = c.getColumnIndexOrThrow(Settings.Favorites.CELLY);
+                final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);
+                final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);
+                final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER);
+                final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);
+                final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);
+                final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);
 
-                UserFolderInfo folderInfo = findOrMakeFolder(mUserFolders, id);
+                FolderInfo folderInfo = null;
+                switch (c.getInt(itemTypeIndex)) {
+                    case LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER:
+                        folderInfo = findOrMakeUserFolder(mFolders, id);
+                        break;
+                    case LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER:
+                        folderInfo = findOrMakeLiveFolder(mFolders, id);
+                        break;
+                }
 
                 folderInfo.title = c.getString(titleIndex);
                 folderInfo.id = id;
@@ -712,18 +874,18 @@
 
     static Widget getPhotoFrameInfo(Context context, int screen, int cellX, int cellY) {
         final ContentResolver cr = context.getContentResolver();
-        Cursor c = cr.query(Settings.Favorites.CONTENT_URI,
+        Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI,
             null, "screen=? and cellX=? and cellY=? and itemType=?",
             new String[] { String.valueOf(screen), String.valueOf(cellX), String.valueOf(cellY),
-                String.valueOf(Settings.Favorites.ITEM_TYPE_WIDGET_PHOTO_FRAME) }, null);
+                String.valueOf(LauncherSettings.Favorites.ITEM_TYPE_WIDGET_PHOTO_FRAME) }, null);
 
         try {
             if (c.moveToFirst()) {
-                final int idIndex = c.getColumnIndexOrThrow(Settings.Favorites.ID);
-                final int containerIndex = c.getColumnIndexOrThrow(Settings.Favorites.CONTAINER);
-                final int screenIndex = c.getColumnIndexOrThrow(Settings.Favorites.SCREEN);
-                final int cellXIndex = c.getColumnIndexOrThrow(Settings.Favorites.CELLX);
-                final int cellYIndex = c.getColumnIndexOrThrow(Settings.Favorites.CELLY);
+                final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ID);
+                final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER);
+                final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);
+                final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);
+                final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);
 
                 Widget widgetInfo = Widget.makePhotoFrame();
                 widgetInfo.id = c.getLong(idIndex);
@@ -757,8 +919,8 @@
         
         item.onAddToDatabase(values);
         
-        Uri result = cr.insert(notify ? Settings.Favorites.CONTENT_URI :
-                Settings.Favorites.CONTENT_URI_NO_NOTIFICATION, values);
+        Uri result = cr.insert(notify ? LauncherSettings.Favorites.CONTENT_URI :
+                LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION, values);
 
         if (result != null) {
             item.id = Integer.parseInt(result.getPathSegments().get(1));
@@ -774,7 +936,7 @@
 
         item.onAddToDatabase(values);
 
-        cr.update(Settings.Favorites.getContentUri(item.id, false), values, null, null);
+        cr.update(LauncherSettings.Favorites.getContentUri(item.id, false), values, null, null);
     }
     
     /**
@@ -785,7 +947,7 @@
     static void deleteItemFromDatabase(Context context, ItemInfo item) {
         final ContentResolver cr = context.getContentResolver();
 
-        cr.delete(Settings.Favorites.getContentUri(item.id, false), null, null);
+        cr.delete(LauncherSettings.Favorites.getContentUri(item.id, false), null, null);
     }
 
 
@@ -795,8 +957,8 @@
     static void deleteUserFolderContentsFromDatabase(Context context, UserFolderInfo info) {
         final ContentResolver cr = context.getContentResolver();
 
-        cr.delete(Settings.Favorites.getContentUri(info.id, false), null, null);
-        cr.delete(Settings.Favorites.CONTENT_URI, Settings.Favorites.CONTAINER + "=" + info.id, 
+        cr.delete(LauncherSettings.Favorites.getContentUri(info.id, false), null, null);
+        cr.delete(LauncherSettings.Favorites.CONTENT_URI, LauncherSettings.Favorites.CONTAINER + "=" + info.id,
                 null);
     }
 }
diff --git a/src/com/android/launcher/LauncherProvider.java b/src/com/android/launcher/LauncherProvider.java
new file mode 100644
index 0000000..a3e529d
--- /dev/null
+++ b/src/com/android/launcher/LauncherProvider.java
@@ -0,0 +1,435 @@
+/*
+ * Copyright (C) 2008 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.launcher;
+
+import android.content.ContentProvider;
+import android.content.Context;
+import android.content.ContentValues;
+import android.content.Intent;
+import android.content.ComponentName;
+import android.content.ContentUris;
+import android.content.ContentResolver;
+import android.content.pm.PackageManager;
+import android.content.pm.ActivityInfo;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteQueryBuilder;
+import android.database.Cursor;
+import android.util.Log;
+import android.util.Xml;
+import android.net.Uri;
+import android.text.TextUtils;
+import android.os.*;
+import android.provider.Settings;
+
+import java.io.FileReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import com.android.internal.util.XmlUtils;
+
+public class LauncherProvider extends ContentProvider {
+    private static final String LOG_TAG = "LauncherSettingsProvider";
+
+    private static final String DATABASE_NAME = "launcher.db";
+    private static final int DATABASE_VERSION = 1;
+
+    static final String AUTHORITY = "com.android.launcher.settings";
+
+    static final String TABLE_FAVORITES = "favorites";
+    static final String PARAMETER_NOTIFY = "notify";
+
+    private SQLiteOpenHelper mOpenHelper;
+
+    @Override
+    public boolean onCreate() {
+        mOpenHelper = new DatabaseHelper(getContext());
+        return true;
+    }
+
+    @Override
+    public String getType(Uri uri) {
+        SqlArguments args = new SqlArguments(uri, null, null);
+        if (TextUtils.isEmpty(args.where)) {
+            return "vnd.android.cursor.dir/" + args.table;
+        } else {
+            return "vnd.android.cursor.item/" + args.table;
+        }
+    }
+
+    @Override
+    public Cursor query(Uri uri, String[] projection, String selection,
+            String[] selectionArgs, String sortOrder) {
+
+        SqlArguments args = new SqlArguments(uri, selection, selectionArgs);
+        SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
+        qb.setTables(args.table);
+
+        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
+        Cursor result = qb.query(db, projection, args.where, args.args, null, null, sortOrder);
+        result.setNotificationUri(getContext().getContentResolver(), uri);
+
+        return result;
+    }
+
+    @Override
+    public Uri insert(Uri uri, ContentValues initialValues) {
+        SqlArguments args = new SqlArguments(uri);
+
+        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+        final long rowId = db.insert(args.table, null, initialValues);
+        if (rowId <= 0) return null;
+
+        uri = ContentUris.withAppendedId(uri, rowId);
+        sendNotify(uri);
+
+        return uri;
+    }
+
+    @Override
+    public int bulkInsert(Uri uri, ContentValues[] values) {
+        SqlArguments args = new SqlArguments(uri);
+
+        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+        db.beginTransaction();
+        try {
+            int numValues = values.length;
+            for (int i = 0; i < numValues; i++) {
+                if (db.insert(args.table, null, values[i]) < 0) return 0;
+            }
+            db.setTransactionSuccessful();
+        } finally {
+            db.endTransaction();
+        }
+
+        sendNotify(uri);
+        return values.length;
+    }
+
+    @Override
+    public int delete(Uri uri, String selection, String[] selectionArgs) {
+        SqlArguments args = new SqlArguments(uri, selection, selectionArgs);
+
+        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+        int count = db.delete(args.table, args.where, args.args);
+        if (count > 0) sendNotify(uri);
+
+        return count;
+    }
+
+    @Override
+    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+        SqlArguments args = new SqlArguments(uri, selection, selectionArgs);
+
+        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+        int count = db.update(args.table, values, args.where, args.args);
+        if (count > 0) sendNotify(uri);
+
+        return count;
+    }
+
+    private void sendNotify(Uri uri) {
+        String notify = uri.getQueryParameter(PARAMETER_NOTIFY);
+        if (notify == null || "true".equals(notify)) {
+            getContext().getContentResolver().notifyChange(uri, null);
+        }
+    }
+
+    private static class DatabaseHelper extends SQLiteOpenHelper {
+        /**
+         * Path to file containing default favorite packages, relative to ANDROID_ROOT.
+         */
+        private static final String DEFAULT_FAVORITES_PATH = "etc/favorites.xml";
+
+        private static final String TAG_FAVORITES = "favorites";
+        private static final String TAG_FAVORITE = "favorite";
+        private static final String TAG_PACKAGE = "package";
+        private static final String TAG_CLASS = "class";
+
+        private static final String ATTRIBUTE_SCREEN = "screen";
+        private static final String ATTRIBUTE_X = "x";
+        private static final String ATTRIBUTE_Y = "y";
+
+        private final Context mContext;
+
+        DatabaseHelper(Context context) {
+            super(context, DATABASE_NAME, null, DATABASE_VERSION);
+            mContext = context;
+        }
+
+        @Override
+        public void onCreate(SQLiteDatabase db) {
+            db.execSQL("CREATE TABLE favorites (" +
+                    "_id INTEGER PRIMARY KEY," +
+                    "title TEXT," +
+                    "intent TEXT," +
+                    "container INTEGER," +
+                    "screen INTEGER," +
+                    "cellX INTEGER," +
+                    "cellY INTEGER," +
+                    "spanX INTEGER," +
+                    "spanY INTEGER," +
+                    "itemType INTEGER," +
+                    "isShortcut INTEGER," +
+                    "iconType INTEGER," +
+                    "iconPackage TEXT," +
+                    "iconResource TEXT," +
+                    "icon BLOB," +
+                    "uri TEXT," +
+                    "displayMode INTEGER" +
+                    ");");
+
+            if (!convertDatabase(db)) {
+                // Populate favorites table with initial favorites
+                loadFavorites(db, DEFAULT_FAVORITES_PATH);
+            }
+        }
+
+        private boolean convertDatabase(SQLiteDatabase db) {
+            boolean converted = false;
+
+            final Uri uri = Uri.parse("content://" + Settings.AUTHORITY +
+                    "/favorites?notify=true");
+            final ContentResolver resolver = mContext.getContentResolver();
+            Cursor cursor = null;
+
+            try {
+                cursor = resolver.query(uri, null, null, null, null);
+            } catch (Exception e) {
+	            // Ignore
+            }
+
+            // We already have a favorites database in the old provider
+            if (cursor != null && cursor.getCount() > 0) {
+                try {
+                    converted = copyFromCursor(db, cursor) > 0;
+                } finally {
+                    cursor.close();
+                }
+
+                if (converted) {
+                    resolver.delete(uri, null, null);
+                }
+            }
+
+            return converted;
+        }
+
+        private int copyFromCursor(SQLiteDatabase db, Cursor c) {
+            final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ID);
+            final int intentIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.INTENT);
+            final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);
+            final int iconTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_TYPE);
+            final int iconIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON);
+            final int iconPackageIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_PACKAGE);
+            final int iconResourceIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_RESOURCE);
+            final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER);
+            final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);
+            final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);
+            final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);
+            final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);
+            final int uriIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.URI);
+            final int displayModeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.DISPLAY_MODE);
+
+            ContentValues[] rows = new ContentValues[c.getCount()];
+            int i = 0;
+            while (c.moveToNext()) {
+                ContentValues values = new ContentValues(c.getColumnCount());
+                values.put(LauncherSettings.Favorites.ID, c.getLong(idIndex));
+                values.put(LauncherSettings.Favorites.INTENT, c.getString(intentIndex));
+                values.put(LauncherSettings.Favorites.TITLE, c.getString(titleIndex));
+                values.put(LauncherSettings.Favorites.ICON_TYPE, c.getInt(iconTypeIndex));
+                values.put(LauncherSettings.Favorites.ICON, c.getBlob(iconIndex));
+                values.put(LauncherSettings.Favorites.ICON_PACKAGE, c.getString(iconPackageIndex));
+                values.put(LauncherSettings.Favorites.ICON_RESOURCE, c.getString(iconResourceIndex));
+                values.put(LauncherSettings.Favorites.CONTAINER, c.getInt(containerIndex));
+                values.put(LauncherSettings.Favorites.ITEM_TYPE, c.getInt(itemTypeIndex));
+                values.put(LauncherSettings.Favorites.SCREEN, c.getInt(screenIndex));
+                values.put(LauncherSettings.Favorites.CELLX, c.getInt(cellXIndex));
+                values.put(LauncherSettings.Favorites.CELLY, c.getInt(cellYIndex));
+                values.put(LauncherSettings.Favorites.URI, c.getString(uriIndex));
+                values.put(LauncherSettings.Favorites.DISPLAY_MODE, c.getInt(displayModeIndex));
+                rows[i++] = values;
+            }
+
+            db.beginTransaction();
+            int total = 0;
+            try {
+                int numValues = rows.length;
+                for (i = 0; i < numValues; i++) {
+                    if (db.insert(TABLE_FAVORITES, null, rows[i]) < 0) {
+                        return 0;
+                    } else {
+                        total++;
+                    }
+                }
+                db.setTransactionSuccessful();
+            } finally {
+                db.endTransaction();
+            }
+
+            return total;
+        }
+
+        @Override
+        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+            Log.w(LOG_TAG, "Upgrading database from version " + oldVersion + " to " +
+                    newVersion + ", which will destroy all old data");
+
+            db.execSQL("DROP TABLE IF EXISTS " + TABLE_FAVORITES);
+            onCreate(db);
+        }
+
+
+        /**
+         * Loads the default set of favorite packages from an xml file.
+         *
+         * @param db The database to write the values into
+         * @param subPath The relative path from ANDROID_ROOT to the file to read
+         */
+        private int loadFavorites(SQLiteDatabase db, String subPath) {
+            FileReader favReader;
+
+            // Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system".
+            final File favFile = new File(Environment.getRootDirectory(), subPath);
+            try {
+                favReader = new FileReader(favFile);
+            } catch (FileNotFoundException e) {
+                Log.e(LOG_TAG, "Couldn't find or open favorites file " + favFile);
+                return 0;
+            }
+
+            Intent intent = new Intent(Intent.ACTION_MAIN, null);
+            intent.addCategory(Intent.CATEGORY_LAUNCHER);
+            ContentValues values = new ContentValues();
+
+            PackageManager packageManager = mContext.getPackageManager();
+            ActivityInfo info;
+            int i = 0;
+            try {
+                XmlPullParser parser = Xml.newPullParser();
+                parser.setInput(favReader);
+
+                XmlUtils.beginDocument(parser, TAG_FAVORITES);
+
+                while (true) {
+                    XmlUtils.nextElement(parser);
+
+                    String name = parser.getName();
+                    if (!TAG_FAVORITE.equals(name)) {
+                        break;
+                    }
+
+                    String pkg = parser.getAttributeValue(null, TAG_PACKAGE);
+                    String cls = parser.getAttributeValue(null, TAG_CLASS);
+                    try {
+                        ComponentName cn = new ComponentName(pkg, cls);
+                        info = packageManager.getActivityInfo(cn, 0);
+                        intent.setComponent(cn);
+                        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                        values.put(LauncherSettings.Favorites.INTENT, intent.toURI());
+                        values.put(LauncherSettings.Favorites.TITLE,
+                                info.loadLabel(packageManager).toString());
+                        values.put(LauncherSettings.Favorites.CONTAINER,
+                                LauncherSettings.Favorites.CONTAINER_DESKTOP);
+                        values.put(LauncherSettings.Favorites.ITEM_TYPE,
+                                LauncherSettings.Favorites.ITEM_TYPE_APPLICATION);
+                        values.put(LauncherSettings.Favorites.SCREEN,
+                                parser.getAttributeValue(null, ATTRIBUTE_SCREEN));
+                        values.put(LauncherSettings.Favorites.CELLX,
+                                parser.getAttributeValue(null, ATTRIBUTE_X));
+                        values.put(LauncherSettings.Favorites.CELLY,
+                                parser.getAttributeValue(null, ATTRIBUTE_Y));
+                        values.put(LauncherSettings.Favorites.SPANX, 1);
+                        values.put(LauncherSettings.Favorites.SPANY, 1);
+                        db.insert(TABLE_FAVORITES, null, values);
+                        i++;
+                    } catch (PackageManager.NameNotFoundException e) {
+                        Log.w(LOG_TAG, "Unable to add favorite: " + pkg + "/" + cls, e);
+                    }
+                }
+            } catch (XmlPullParserException e) {
+                Log.w(LOG_TAG, "Got exception parsing favorites.", e);
+            } catch (IOException e) {
+                Log.w(LOG_TAG, "Got exception parsing favorites.", e);
+            }
+
+            // Add a clock
+            values.clear();
+            values.put(LauncherSettings.Favorites.CONTAINER,
+                    LauncherSettings.Favorites.CONTAINER_DESKTOP);
+            values.put(LauncherSettings.Favorites.ITEM_TYPE,
+                    LauncherSettings.Favorites.ITEM_TYPE_WIDGET_CLOCK);
+            values.put(LauncherSettings.Favorites.SCREEN, 1);
+            values.put(LauncherSettings.Favorites.CELLX, 1);
+            values.put(LauncherSettings.Favorites.CELLY, 0);
+            values.put(LauncherSettings.Favorites.SPANX, 2);
+            values.put(LauncherSettings.Favorites.SPANY, 2);
+            db.insert(TABLE_FAVORITES, null, values);
+
+            // Add a search box
+            values.clear();
+            values.put(LauncherSettings.Favorites.CONTAINER,
+                    LauncherSettings.Favorites.CONTAINER_DESKTOP);
+            values.put(LauncherSettings.Favorites.ITEM_TYPE,
+                    LauncherSettings.Favorites.ITEM_TYPE_WIDGET_SEARCH);
+            values.put(LauncherSettings.Favorites.SCREEN, 2);
+            values.put(LauncherSettings.Favorites.CELLX, 0);
+            values.put(LauncherSettings.Favorites.CELLY, 0);
+            values.put(LauncherSettings.Favorites.SPANX, 4);
+            values.put(LauncherSettings.Favorites.SPANY, 1);
+            db.insert(TABLE_FAVORITES, null, values);
+
+            return i;
+        }
+    }
+
+    static class SqlArguments {
+        public final String table;
+        public final String where;
+        public final String[] args;
+
+        SqlArguments(Uri url, String where, String[] args) {
+            if (url.getPathSegments().size() == 1) {
+                this.table = url.getPathSegments().get(0);
+                this.where = where;
+                this.args = args;
+            } else if (url.getPathSegments().size() != 2) {
+                throw new IllegalArgumentException("Invalid URI: " + url);
+            } else if (!TextUtils.isEmpty(where)) {
+                throw new UnsupportedOperationException("WHERE clause not supported: " + url);
+            } else {
+                this.table = url.getPathSegments().get(0);
+                this.where = "_id=" + ContentUris.parseId(url);                
+                this.args = null;
+            }
+        }
+
+        SqlArguments(Uri url) {
+            if (url.getPathSegments().size() == 1) {
+                table = url.getPathSegments().get(0);
+                where = null;
+                args = null;
+            } else {
+                throw new IllegalArgumentException("Invalid URI: " + url);
+            }
+        }
+    }
+}
diff --git a/src/com/android/launcher/LauncherSettings.java b/src/com/android/launcher/LauncherSettings.java
new file mode 100644
index 0000000..c5dfd1f
--- /dev/null
+++ b/src/com/android/launcher/LauncherSettings.java
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2008 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.launcher;
+
+import android.provider.BaseColumns;
+import android.net.Uri;
+
+/**
+ * Settings related utilities.
+ */
+class LauncherSettings {
+    /**
+     * Favorites.
+     */
+    static final class Favorites implements BaseColumns {
+        /**
+         * The content:// style URL for this table
+         */
+        static final Uri CONTENT_URI = Uri.parse("content://" +
+                LauncherProvider.AUTHORITY + "/" + LauncherProvider.TABLE_FAVORITES +
+                "?" + LauncherProvider.PARAMETER_NOTIFY + "=true");
+
+        /**
+         * The content:// style URL for this table. When this Uri is used, no notification is
+         * sent if the content changes.
+         */
+        static final Uri CONTENT_URI_NO_NOTIFICATION = Uri.parse("content://" +
+                LauncherProvider.AUTHORITY + "/" + LauncherProvider.TABLE_FAVORITES +
+                "?" + LauncherProvider.PARAMETER_NOTIFY + "=false");
+
+        /**
+         * The content:// style URL for a given row, identified by its id.
+         *
+         * @param id The row id.
+         * @param notify True to send a notification is the content changes.
+         *
+         * @return The unique content URL for the specified row.
+         */
+        static Uri getContentUri(long id, boolean notify) {
+            return Uri.parse("content://" + LauncherProvider.AUTHORITY +
+                    "/" + LauncherProvider.TABLE_FAVORITES + "/" + id + "?" +
+                    LauncherProvider.PARAMETER_NOTIFY + "=" + notify);
+        }
+
+        /**
+         * The row ID.
+         * <p>Type: INTEGER</p>
+         */
+        static final String ID = "_id";
+
+        /**
+         * Descriptive name of the favorite that can be displayed to the user.
+         * <P>Type: TEXT</P>
+         */
+        static final String TITLE = "title";
+
+        /**
+         * The Intent URL of the favorite, describing what it points to.  This
+         * value is given to {@link android.content.Intent#getIntent} to create
+         * an Intent that can be launched.
+         * <P>Type: TEXT</P>
+         */
+        static final String INTENT = "intent";
+
+        /**
+         * The container holding the favorite
+         * <P>Type: INTEGER</P>
+         */
+        static final String CONTAINER = "container";
+
+        /**
+         * The icon is a resource identified by a package name and an integer id.
+         */
+        static final int CONTAINER_DESKTOP = -100;
+
+        /**
+         * The screen holding the favorite (if container is CONTAINER_DESKTOP)
+         * <P>Type: INTEGER</P>
+         */
+        static final String SCREEN = "screen";
+
+        /**
+         * The X coordinate of the cell holding the favorite
+         * (if container is CONTAINER_DESKTOP or CONTAINER_DOCK)
+         * <P>Type: INTEGER</P>
+         */
+        static final String CELLX = "cellX";
+
+        /**
+         * The Y coordinate of the cell holding the favorite
+         * (if container is CONTAINER_DESKTOP)
+         * <P>Type: INTEGER</P>
+         */
+        static final String CELLY = "cellY";
+
+        /**
+         * The X span of the cell holding the favorite
+         * <P>Type: INTEGER</P>
+         */
+        static final String SPANX = "spanX";
+
+        /**
+         * The Y span of the cell holding the favorite
+         * <P>Type: INTEGER</P>
+         */
+        static final String SPANY = "spanY";
+
+        /**
+         * The type of the favorite
+         *
+         * <P>Type: INTEGER</P>
+         */
+        static final String ITEM_TYPE = "itemType";
+
+        /**
+         * The favorite is an application
+         */
+        static final int ITEM_TYPE_APPLICATION = 0;
+
+        /**
+         * The favorite is an application created shortcut
+         */
+        static final int ITEM_TYPE_SHORTCUT = 1;
+
+        /**
+         * The favorite is a user created folder
+         */
+        static final int ITEM_TYPE_USER_FOLDER = 2;
+
+        /**
+         * The favorite is a live folder
+         */
+        static final int ITEM_TYPE_LIVE_FOLDER = 3;
+
+        /**
+         * The favorite is a clock
+         */
+        static final int ITEM_TYPE_WIDGET_CLOCK = 1000;
+
+        /**
+         * The favorite is a search widget
+         */
+        static final int ITEM_TYPE_WIDGET_SEARCH = 1001;
+
+        /**
+         * The favorite is a photo frame
+         */
+        static final int ITEM_TYPE_WIDGET_PHOTO_FRAME = 1002;
+
+        /**
+         * Indicates whether this favorite is an application-created shortcut or not.
+         * If the value is 0, the favorite is not an application-created shortcut, if the
+         * value is 1, it is an application-created shortcut.
+         * <P>Type: INTEGER</P>
+         */
+        static final String IS_SHORTCUT = "isShortcut";
+
+        /**
+         * The icon type.
+         * <P>Type: INTEGER</P>
+         */
+        static final String ICON_TYPE = "iconType";
+
+        /**
+         * The icon is a resource identified by a package name and an integer id.
+         */
+        static final int ICON_TYPE_RESOURCE = 0;
+
+        /**
+         * The icon is a bitmap.
+         */
+        static final int ICON_TYPE_BITMAP = 1;
+
+        /**
+         * The icon package name, if icon type is ICON_TYPE_RESOURCE.
+         * <P>Type: TEXT</P>
+         */
+        static final String ICON_PACKAGE = "iconPackage";
+
+        /**
+         * The icon resource id, if icon type is ICON_TYPE_RESOURCE.
+         * <P>Type: TEXT</P>
+         */
+        static final String ICON_RESOURCE = "iconResource";
+
+        /**
+         * The custom icon bitmap, if icon type is ICON_TYPE_BITMAP.
+         * <P>Type: BLOB</P>
+         */
+        static final String ICON = "icon";
+
+        /**
+         * The URI associated with the favorite. It is used, for instance, by
+         * live folders to find the content provider.
+         * <P>Type: TEXT</P>
+         */
+        static final String URI = "uri";
+
+        /**
+         * The display mode if the item is a live folder.
+         * <P>Type: INTEGER</P>
+         *
+         * @see android.provider.LiveFolders#DISPLAY_MODE_GRID
+         * @see android.provider.LiveFolders#DISPLAY_MODE_LIST
+         */
+        static final String DISPLAY_MODE = "displayMode";
+    }
+}
diff --git a/src/com/android/launcher/LiveFolder.java b/src/com/android/launcher/LiveFolder.java
new file mode 100644
index 0000000..37b98e0
--- /dev/null
+++ b/src/com/android/launcher/LiveFolder.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2008 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.launcher;
+
+import android.content.Context;
+import android.content.Intent;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.AdapterView;
+import android.net.Uri;
+import android.provider.LiveFolders;
+
+public class LiveFolder extends Folder {
+    public LiveFolder(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    static LiveFolder fromXml(Context context, FolderInfo folderInfo) {
+        final int layout = isDisplayModeList(folderInfo) ?
+                R.layout.live_folder_list : R.layout.live_folder_grid;
+        return (LiveFolder) LayoutInflater.from(context).inflate(layout, null);
+    }
+
+    private static boolean isDisplayModeList(FolderInfo folderInfo) {
+        return ((LiveFolderInfo) folderInfo).displayMode ==
+                LiveFolders.DISPLAY_MODE_LIST;
+    }
+
+    @Override
+    public void onItemClick(AdapterView parent, View v, int position, long id) {
+        LiveFolderAdapter.ViewHolder holder = (LiveFolderAdapter.ViewHolder) v.getTag();
+
+        if (holder.useBaseIntent) {
+            final Intent baseIntent = ((LiveFolderInfo) mInfo).baseIntent;
+            if (baseIntent != null) {
+                final Intent intent = new Intent(baseIntent);
+                Uri uri = baseIntent.getData();
+                uri = uri.buildUpon().appendPath(Long.toString(holder.id)).build();
+                intent.setData(uri);
+                mLauncher.startActivitySafely(intent);
+            }
+        } else if (holder.intent != null) {
+            mLauncher.startActivitySafely(holder.intent);
+        }
+    }
+
+    @Override
+    public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
+        return false;
+    }
+
+    void bind(FolderInfo info) {
+        super.bind(info);
+        setContentAdapter(new LiveFolderAdapter(mLauncher, (LiveFolderInfo) info));
+    }
+
+    @Override
+    void onOpen() {
+        super.onOpen();
+        requestFocus();
+    }
+
+    @Override
+    void onClose() {
+        super.onClose();
+        ((LiveFolderAdapter) mContent.getAdapter()).cleanup();
+    }
+}
diff --git a/src/com/android/launcher/LiveFolderAdapter.java b/src/com/android/launcher/LiveFolderAdapter.java
new file mode 100644
index 0000000..01db5a6
--- /dev/null
+++ b/src/com/android/launcher/LiveFolderAdapter.java
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2008 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.launcher;
+
+import android.widget.CursorAdapter;
+import android.widget.TextView;
+import android.widget.ImageView;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.content.pm.PackageManager;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.LayoutInflater;
+import android.database.Cursor;
+import android.provider.LiveFolders;
+import android.graphics.drawable.Drawable;
+import android.graphics.BitmapFactory;
+import android.graphics.Bitmap;
+
+import java.net.URISyntaxException;
+import java.util.HashMap;
+import java.lang.ref.SoftReference;
+
+class LiveFolderAdapter extends CursorAdapter {
+    private boolean mIsList;
+    private LayoutInflater mInflater;
+
+    private final HashMap<String, Drawable> mIcons = new HashMap<String, Drawable>();
+    private final HashMap<Long, SoftReference<Drawable>> mCustomIcons =
+            new HashMap<Long, SoftReference<Drawable>>();
+    private final Launcher mLauncher;
+
+    LiveFolderAdapter(Launcher launcher, LiveFolderInfo info) {
+        super(launcher, query(launcher, info), true);
+        mIsList = info.displayMode == LiveFolders.DISPLAY_MODE_LIST;
+        mInflater = LayoutInflater.from(launcher);
+        mLauncher = launcher;
+
+        mLauncher.startManagingCursor(getCursor());
+    }
+
+    private static Cursor query(Context context, LiveFolderInfo info) {
+        return context.getContentResolver().query(info.uri, null, null, null, LiveFolders.NAME + " ASC");
+    }
+
+    public View newView(Context context, Cursor cursor, ViewGroup parent) {
+        View view;
+        final ViewHolder holder = new ViewHolder();
+
+        if (!mIsList) {
+            view = mInflater.inflate(R.layout.application_boxed, parent, false);
+        } else {
+            view = mInflater.inflate(R.layout.application_list, parent, false);
+            holder.description = (TextView) view.findViewById(R.id.description);
+            holder.icon = (ImageView) view.findViewById(R.id.icon);
+        }
+
+        holder.name = (TextView) view.findViewById(R.id.name);
+
+        holder.idIndex = cursor.getColumnIndexOrThrow(LiveFolders._ID);
+        holder.nameIndex = cursor.getColumnIndexOrThrow(LiveFolders.NAME);
+        holder.descriptionIndex = cursor.getColumnIndex(LiveFolders.DESCRIPTION);
+        holder.intentIndex = cursor.getColumnIndex(LiveFolders.INTENT);
+        holder.iconBitmapIndex = cursor.getColumnIndex(LiveFolders.ICON_BITMAP);
+        holder.iconResourceIndex = cursor.getColumnIndex(LiveFolders.ICON_RESOURCE);
+        holder.iconPackageIndex = cursor.getColumnIndex(LiveFolders.ICON_PACKAGE);
+
+        view.setTag(holder);
+
+        return view;
+    }
+
+    public void bindView(View view, Context context, Cursor cursor) {
+        final ViewHolder holder = (ViewHolder) view.getTag();
+
+        holder.id = cursor.getLong(holder.idIndex);
+        final Drawable icon = loadIcon(context, cursor, holder);
+
+        holder.name.setText(cursor.getString(holder.nameIndex));
+
+        if (!mIsList) {
+            holder.name.setCompoundDrawablesWithIntrinsicBounds(null, icon, null, null);
+        } else {
+            final boolean hasIcon = icon != null;
+            holder.icon.setVisibility(hasIcon ? View.VISIBLE : View.GONE);
+            if (hasIcon) holder.icon.setImageDrawable(icon);
+
+            if (holder.descriptionIndex != -1) {
+                final String description = cursor.getString(holder.descriptionIndex);
+                if (description != null) {
+                    holder.description.setText(description);
+                    holder.description.setVisibility(View.VISIBLE);
+                } else {
+                    holder.description.setVisibility(View.GONE);                    
+                }
+            } else {
+                holder.description.setVisibility(View.GONE);                
+            }
+        }
+
+        if (holder.intentIndex != -1) {
+            try {
+                holder.intent = Intent.getIntent(cursor.getString(holder.intentIndex));
+            } catch (URISyntaxException e) {
+                // Ignore
+            }
+        } else {
+            holder.useBaseIntent = true;
+        }
+    }
+
+    private Drawable loadIcon(Context context, Cursor cursor, ViewHolder holder) {
+        Drawable icon = null;
+        byte[] data = null;
+
+        if (holder.iconBitmapIndex != -1) {
+            data = cursor.getBlob(holder.iconBitmapIndex);
+        }
+
+        if (data != null) {
+            final SoftReference<Drawable> reference = mCustomIcons.get(holder.id);
+            if (reference != null) {
+                icon = reference.get();
+            }
+
+            if (icon == null) {
+                final Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
+                icon = new FastBitmapDrawable(Utilities.createBitmapThumbnail(bitmap, mContext));
+                mCustomIcons.put(holder.id, new SoftReference<Drawable>(icon));
+            }
+        } else if (holder.iconResourceIndex != -1 && holder.iconPackageIndex != -1) {
+            final String resource = cursor.getString(holder.iconResourceIndex);
+            icon = mIcons.get(resource);
+            if (icon == null) {
+                try {
+                    final PackageManager packageManager = context.getPackageManager();
+                    Resources resources = packageManager.getResourcesForApplication(
+                            cursor.getString(holder.iconPackageIndex));
+                    final int id = resources.getIdentifier(resource,
+                            null, null);
+                    icon = Utilities.createIconThumbnail(resources.getDrawable(id), mContext);
+                    mIcons.put(resource, icon);
+                } catch (Exception e) {
+                    // Ignore
+                }
+            }
+        }
+
+        return icon;
+    }
+
+    void cleanup() {
+        for (Drawable icon : mIcons.values()) {
+            icon.setCallback(null);
+        }
+        mIcons.clear();
+
+        for (SoftReference<Drawable> icon : mCustomIcons.values()) {
+            final Drawable drawable = icon.get();
+            if (drawable != null) {
+                drawable.setCallback(null);
+            }
+        }
+        mCustomIcons.clear();
+
+        try {
+            getCursor().close();
+        } finally {
+            mLauncher.stopManagingCursor(getCursor());
+        }
+    }
+
+    static class ViewHolder {
+        TextView name;
+        TextView description;
+        ImageView icon;
+
+        Intent intent;
+        long id;
+        boolean useBaseIntent;
+
+        int idIndex;
+        int nameIndex;
+        int descriptionIndex = -1;
+        int intentIndex = -1;
+        int iconBitmapIndex = -1;
+        int iconResourceIndex = -1;
+        int iconPackageIndex = -1;
+    }
+}
diff --git a/src/com/android/launcher/LiveFolderIcon.java b/src/com/android/launcher/LiveFolderIcon.java
new file mode 100644
index 0000000..33cb0b7
--- /dev/null
+++ b/src/com/android/launcher/LiveFolderIcon.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2008 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.launcher;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.util.AttributeSet;
+import android.view.ViewGroup;
+import android.view.LayoutInflater;
+import android.graphics.drawable.Drawable;
+
+public class LiveFolderIcon extends FolderIcon {
+    public LiveFolderIcon(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public LiveFolderIcon(Context context) {
+        super(context);
+    }
+
+    static LiveFolderIcon fromXml(int resId, Launcher launcher, ViewGroup group,
+            LiveFolderInfo folderInfo) {
+
+        LiveFolderIcon icon = (LiveFolderIcon)
+                LayoutInflater.from(launcher).inflate(resId, group, false);
+
+        final Resources resources = launcher.getResources();
+        Drawable d = folderInfo.icon;
+        if (d == null) {
+            resources.getDrawable(R.drawable.ic_launcher_folder);
+            d = Utilities.createIconThumbnail(d, launcher);
+            folderInfo.filtered = true;
+        }
+        icon.setCompoundDrawablesWithIntrinsicBounds(null, d, null, null);
+        icon.setText(folderInfo.title);
+        icon.setTag(folderInfo);
+        icon.setOnClickListener(launcher);
+        
+        return icon;
+    }
+
+    @Override
+    public boolean acceptDrop(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo) {
+        return false;
+    }
+
+    @Override
+    public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo) {
+    }
+
+    @Override
+    public void onDragEnter(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo) {
+    }
+
+    @Override
+    public void onDragOver(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo) {
+    }
+
+    @Override
+    public void onDragExit(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo) {
+    }
+}
diff --git a/src/com/android/launcher/LiveFolderInfo.java b/src/com/android/launcher/LiveFolderInfo.java
new file mode 100644
index 0000000..2432cc3
--- /dev/null
+++ b/src/com/android/launcher/LiveFolderInfo.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2008 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.launcher;
+
+import android.content.ContentValues;
+import android.content.Intent;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+
+class LiveFolderInfo extends FolderInfo {
+
+    /**
+     * The base intent, if it exists.
+     */
+    Intent baseIntent;
+
+    /**
+     * The live folder's content uri.
+     */
+    Uri uri;
+
+    /**
+     * The live folder's display type.
+     */
+    int displayMode;
+
+    /**
+     * The live folder icon.
+     */
+    Drawable icon;
+
+    /**
+     * When set to true, indicates that the icon has been resized.
+     */
+    boolean filtered;
+
+    /**
+     * Reference to the live folder icon as an application's resource.
+     */
+    Intent.ShortcutIconResource iconResource;
+
+    LiveFolderInfo() {
+        itemType = LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER;
+    }
+
+    @Override
+    void onAddToDatabase(ContentValues values) {
+        super.onAddToDatabase(values);
+        values.put(LauncherSettings.Favorites.TITLE, title.toString());
+        values.put(LauncherSettings.Favorites.URI, uri.toString());
+        if (baseIntent != null) {
+            values.put(LauncherSettings.Favorites.INTENT, baseIntent.toURI());
+        }
+        values.put(LauncherSettings.Favorites.ICON_TYPE, LauncherSettings.Favorites.ICON_TYPE_RESOURCE);
+        values.put(LauncherSettings.Favorites.DISPLAY_MODE, displayMode);
+        if (iconResource != null) {
+            values.put(LauncherSettings.Favorites.ICON_PACKAGE, iconResource.packageName);
+            values.put(LauncherSettings.Favorites.ICON_RESOURCE, iconResource.resourceName);
+        }
+    }
+}
diff --git a/src/com/android/launcher/Search.java b/src/com/android/launcher/Search.java
index 69e26ac..b330527 100644
--- a/src/com/android/launcher/Search.java
+++ b/src/com/android/launcher/Search.java
@@ -16,13 +16,19 @@
 
 package com.android.launcher;
 
+import java.util.List;
+
 import android.app.ISearchManager;
 import android.app.SearchManager;
+import android.content.ActivityNotFoundException;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
 import android.content.res.Resources;
 import android.content.res.Resources.NotFoundException;
 import android.database.Cursor;
+import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.Bundle;
@@ -43,9 +49,9 @@
 import android.view.View.OnLongClickListener;
 import android.widget.AdapterView;
 import android.widget.AutoCompleteTextView;
-import android.widget.Button;
 import android.widget.CursorAdapter;
 import android.widget.Filter;
+import android.widget.ImageButton;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.SimpleCursorAdapter;
@@ -59,7 +65,7 @@
     private final String TAG = "SearchGadget";
 
     private AutoCompleteTextView mSearchText;
-    private Button mGoButton;
+    private ImageButton mGoButton;
     private OnLongClickListener mLongClickListener;
     
     // Support for suggestions
@@ -69,12 +75,14 @@
     private Uri mSuggestionData = null;
     private String mSuggestionQuery = null;
     private int mItemSelected = -1;
+    
+    private Rect mTempRect = new Rect();
 
     /**
      * Used to inflate the Workspace from XML.
      *
      * @param context The application's context.
-     * @param attrs The attribtues set containing the Workspace's customization values.
+     * @param attrs The attributes set containing the Workspace's customization values.
      */
     public Search(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -84,7 +92,9 @@
      * Implements OnClickListener (for button)
      */
     public void onClick(View v) {
-        query();
+        if (v == mGoButton) {
+            query();
+        }
     }
 
     private void query() {
@@ -92,7 +102,9 @@
         if (TextUtils.getTrimmedLength(mSearchText.getText()) == 0) {
             return;
         }
-        sendLaunchIntent(Intent.ACTION_SEARCH, null, query, null, 0, null, mSearchable);
+        Bundle appData = new Bundle();
+        appData.putString(SearchManager.SOURCE, "launcher-widget");
+        sendLaunchIntent(Intent.ACTION_SEARCH, null, query, appData, 0, null, mSearchable);
     }
     
     /**
@@ -254,7 +266,7 @@
         mSearchText.setOnKeyListener(this);
         mSearchText.addTextChangedListener(this);
 
-        mGoButton = (Button) findViewById(R.id.go);
+        mGoButton = (ImageButton) findViewById(R.id.search_go_btn);
         mGoButton.setOnClickListener(this);
         mGoButton.setOnKeyListener(this);
         
@@ -296,8 +308,8 @@
         
         // attach the suggestions adapter
         mSuggestionsAdapter = new SuggestionsAdapter(mContext, 
-                com.android.internal.R.layout.search_dropdown_item_1line, null,
-                SuggestionsAdapter.ONE_LINE_FROM, SuggestionsAdapter.ONE_LINE_TO, mSearchable);
+                com.android.internal.R.layout.search_dropdown_item_2line, null,
+                SuggestionsAdapter.TWO_LINE_FROM, SuggestionsAdapter.TWO_LINE_TO, mSearchable);
         mSearchText.setAdapter(mSuggestionsAdapter);
     }
     
@@ -432,10 +444,14 @@
         
     /**
      * This class provides the filtering-based interface to suggestions providers.
+     * It is hardwired in a couple of places to support GoogleSearch - for example, it supports
+     * two-line suggestions, but it does not support icons.
      */
     private static class SuggestionsAdapter extends SimpleCursorAdapter {
-        public final static String[] ONE_LINE_FROM =   { SearchManager.SUGGEST_COLUMN_TEXT_1 };
-        public final static int[] ONE_LINE_TO =        { com.android.internal.R.id.text1 };
+        public final static String[] TWO_LINE_FROM =    {SearchManager.SUGGEST_COLUMN_TEXT_1,
+                                                         SearchManager.SUGGEST_COLUMN_TEXT_2 };
+        public final static int[] TWO_LINE_TO =         {com.android.internal.R.id.text1, 
+                                                         com.android.internal.R.id.text2};
         
         private final String TAG = "SuggestionsAdapter";
         
diff --git a/src/com/android/launcher/UninstallShortcutReceiver.java b/src/com/android/launcher/UninstallShortcutReceiver.java
index 2d7909e..e490f9c 100644
--- a/src/com/android/launcher/UninstallShortcutReceiver.java
+++ b/src/com/android/launcher/UninstallShortcutReceiver.java
@@ -21,11 +21,10 @@
 import android.content.Intent;
 import android.content.ContentResolver;
 import android.database.Cursor;
+import android.net.Uri;
 
 import java.net.URISyntaxException;
 
-import com.android.internal.provider.Settings;
-
 public class UninstallShortcutReceiver extends BroadcastReceiver {
     public void onReceive(Context context, Intent data) {
         Intent intent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);
@@ -34,18 +33,23 @@
 
         if (intent != null && name != null) {
             final ContentResolver cr = context.getContentResolver();
-            Cursor c = cr.query(Settings.Favorites.CONTENT_URI,
-                new String[] { "_id", "intent" }, "title=?", new String[]{ name }, null);
+            Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI,
+                new String[] { LauncherSettings.Favorites.ID, LauncherSettings.Favorites.INTENT },
+                LauncherSettings.Favorites.TITLE + "=?", new String[] { name }, null);
 
-            final int intentIndex = c.getColumnIndexOrThrow(Settings.Favorites.INTENT);
-            final int idIndex = c.getColumnIndexOrThrow(Settings.Favorites._ID);
+            final int intentIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.INTENT);
+            final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);
+
+            boolean changed = false;
 
             try {
                 while (c.moveToNext()) {
                     try {
                         if (intent.filterEquals(Intent.getIntent(c.getString(intentIndex)))) {
                             final long id = c.getLong(idIndex);
-                            cr.delete(Settings.Favorites.getContentUri(id, false), null, null);
+                            final Uri uri = LauncherSettings.Favorites.getContentUri(id, false);
+                            cr.delete(uri, null, null);
+                            changed = true;
                             if (!duplicate) {
                                 break;
                             }
@@ -58,7 +62,7 @@
                 c.close();
             }
 
-            cr.notifyChange(Settings.Favorites.CONTENT_URI, null);
+            if (changed) cr.notifyChange(LauncherSettings.Favorites.CONTENT_URI, null);
         }
     }
 }
diff --git a/src/com/android/launcher/UserFolder.java b/src/com/android/launcher/UserFolder.java
index dee44baa..1044e96 100644
--- a/src/com/android/launcher/UserFolder.java
+++ b/src/com/android/launcher/UserFolder.java
@@ -1,7 +1,6 @@
 package com.android.launcher;
 
 import android.content.Context;
-import com.android.internal.provider.Settings;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -31,8 +30,8 @@
             Object dragInfo) {
         final ItemInfo item = (ItemInfo) dragInfo;
         final int itemType = item.itemType;
-        return (itemType == Settings.Favorites.ITEM_TYPE_APPLICATION || 
-                itemType == Settings.Favorites.ITEM_TYPE_SHORTCUT) && item.container != mInfo.id;
+        return (itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
+                itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) && item.container != mInfo.id;
     }
 
     public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo) {
@@ -52,13 +51,6 @@
     }
 
     @Override
-    public boolean onLongClick(View v) {
-        mLauncher.closeFolder(this);
-        mLauncher.showRenameDialog((UserFolderInfo) mInfo);
-        return true;
-    }
-
-    @Override
     public void onDropCompleted(View target, boolean success) {
         if (success) {
             //noinspection unchecked
@@ -68,10 +60,9 @@
         }
     }
 
-    void bind(UserFolderInfo info) {
-        mInfo = info;
-        setContentAdapter(new ApplicationsAdapter(mContext, info.contents));
-        mCloseButton.setText(info.title);
+    void bind(FolderInfo info) {
+        super.bind(info);
+        setContentAdapter(new ApplicationsAdapter(mContext, ((UserFolderInfo) info).contents));
     }
 
     // When the folder opens, we need to refresh the GridView's selection by
diff --git a/src/com/android/launcher/UserFolderInfo.java b/src/com/android/launcher/UserFolderInfo.java
index 075b89a..639894e 100644
--- a/src/com/android/launcher/UserFolderInfo.java
+++ b/src/com/android/launcher/UserFolderInfo.java
@@ -17,7 +17,6 @@
 package com.android.launcher;
 
 import android.content.ContentValues;
-import com.android.internal.provider.Settings;
 
 import java.util.ArrayList;
 
@@ -26,17 +25,12 @@
  */
 class UserFolderInfo extends FolderInfo {
     /**
-     * The application name.
-     */
-    CharSequence title;
-
-    /**
      * The apps and shortcuts 
      */
     ArrayList<ApplicationInfo> contents = new ArrayList<ApplicationInfo>();
     
     UserFolderInfo() {
-        itemType = Settings.Favorites.ITEM_TYPE_USER_FOLDER;
+        itemType = LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER;
     }
     
     /**
@@ -60,6 +54,6 @@
     @Override
     void onAddToDatabase(ContentValues values) { 
         super.onAddToDatabase(values);
-        values.put(Settings.Favorites.TITLE, title.toString());
+        values.put(LauncherSettings.Favorites.TITLE, title.toString());
     }
 }
diff --git a/src/com/android/launcher/Utilities.java b/src/com/android/launcher/Utilities.java
index 2373897..cb8976c 100644
--- a/src/com/android/launcher/Utilities.java
+++ b/src/com/android/launcher/Utilities.java
@@ -18,7 +18,6 @@
 
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.PaintDrawable;
-import android.graphics.drawable.BitmapDrawable;
 import android.graphics.Bitmap;
 import android.graphics.PixelFormat;
 import android.graphics.Canvas;
@@ -97,30 +96,46 @@
             painter.setIntrinsicHeight(height);
         }
 
-        if (width > 0 && height > 0 && (width < iconWidth || height < iconHeight)) {
-            final float ratio = (float) iconWidth / iconHeight;
+        if (width > 0 && height > 0) {
+            if (width < iconWidth || height < iconHeight) {
+                final float ratio = (float) iconWidth / iconHeight;
 
-            if (iconWidth > iconHeight) {
-                height = (int) (width / ratio);
-            } else if (iconHeight > iconWidth) {
-                width = (int) (height * ratio);
+                if (iconWidth > iconHeight) {
+                    height = (int) (width / ratio);
+                } else if (iconHeight > iconWidth) {
+                    width = (int) (height * ratio);
+                }
+
+                final Bitmap.Config c = icon.getOpacity() != PixelFormat.OPAQUE ?
+                            Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
+                final Bitmap thumb = Bitmap.createBitmap(sIconWidth, sIconHeight, c);
+                final Canvas canvas = sCanvas;
+                canvas.setBitmap(thumb);
+                // Copy the old bounds to restore them later
+                // If we were to do oldBounds = icon.getBounds(),
+                // the call to setBounds() that follows would
+                // change the same instance and we would lose the
+                // old bounds
+                sOldBounds.set(icon.getBounds());
+                final int x = (sIconWidth - width) / 2;
+                final int y = (sIconHeight - height) / 2;
+                icon.setBounds(x, y, x + width, y + height);
+                icon.draw(canvas);
+                icon.setBounds(sOldBounds);
+                icon = new FastBitmapDrawable(thumb);
+            } else if (iconWidth < width && iconHeight < height) {
+                final Bitmap.Config c = Bitmap.Config.ARGB_8888;
+                final Bitmap thumb = Bitmap.createBitmap(sIconWidth, sIconHeight, c);
+                final Canvas canvas = sCanvas;
+                canvas.setBitmap(thumb);
+                sOldBounds.set(icon.getBounds());
+                final int x = (width - iconWidth) / 2;
+                final int y = (height - iconHeight) / 2;
+                icon.setBounds(x, y, x + iconWidth, y + iconHeight);
+                icon.draw(canvas);
+                icon.setBounds(sOldBounds);
+                icon = new FastBitmapDrawable(thumb);
             }
-
-            final Bitmap.Config c = icon.getOpacity() != PixelFormat.OPAQUE ?
-                        Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
-            final Bitmap thumb = Bitmap.createBitmap(sIconWidth, sIconHeight, c);
-            final Canvas canvas = sCanvas;
-            canvas.setBitmap(thumb);
-            // Copy the old bounds to restore them later
-            // If we were to do oldBounds = icon.getBounds(),
-            // the call to setBounds() that follows would
-            // change the same instance and we would lose the
-            // old bounds
-            sOldBounds.set(icon.getBounds());
-            icon.setBounds((sIconWidth - width) / 2, (sIconHeight - height) / 2, width, height);
-            icon.draw(canvas);
-            icon.setBounds(sOldBounds);
-            icon = new BitmapDrawable(thumb);
         }
 
         return icon;
diff --git a/src/com/android/launcher/WallpaperChooser.java b/src/com/android/launcher/WallpaperChooser.java
index 268b571..a4e583e 100644
--- a/src/com/android/launcher/WallpaperChooser.java
+++ b/src/com/android/launcher/WallpaperChooser.java
@@ -102,6 +102,7 @@
         mGallery = (Gallery) findViewById(R.id.gallery);
         mGallery.setAdapter(new ImageAdapter(this));
         mGallery.setOnItemSelectedListener(this);
+        mGallery.setCallbackDuringFling(false);
         
         Button b = (Button) findViewById(R.id.set);
         b.setOnClickListener(this);
diff --git a/src/com/android/launcher/Widget.java b/src/com/android/launcher/Widget.java
index b9d8ae6..8812522 100644
--- a/src/com/android/launcher/Widget.java
+++ b/src/com/android/launcher/Widget.java
@@ -18,7 +18,6 @@
 
 import android.content.ContentValues;
 import android.graphics.Bitmap;
-import com.android.internal.provider.Settings;
 
 /**
  * Represents one instance of a Launcher widget (clock, search, photo frame).
@@ -31,7 +30,7 @@
 
     static Widget makeClock() {
         Widget w = new Widget();
-        w.itemType = Settings.Favorites.ITEM_TYPE_WIDGET_CLOCK;
+        w.itemType = LauncherSettings.Favorites.ITEM_TYPE_WIDGET_CLOCK;
         w.spanX = 2;
         w.spanY = 2;
         w.layoutResource = R.layout.widget_clock;
@@ -40,7 +39,7 @@
     
     static Widget makePhotoFrame() {
         Widget w = new Widget();
-        w.itemType = Settings.Favorites.ITEM_TYPE_WIDGET_PHOTO_FRAME;
+        w.itemType = LauncherSettings.Favorites.ITEM_TYPE_WIDGET_PHOTO_FRAME;
         w.spanX = 2;
         w.spanY = 2;
         w.layoutResource = R.layout.widget_photo_frame;
@@ -49,7 +48,7 @@
     
     static Widget makeSearch() {
         Widget w = new Widget();
-        w.itemType = Settings.Favorites.ITEM_TYPE_WIDGET_SEARCH;
+        w.itemType = LauncherSettings.Favorites.ITEM_TYPE_WIDGET_SEARCH;
         w.spanX = 4;
         w.spanY = 1;
         w.layoutResource = R.layout.widget_search;
diff --git a/src/com/android/launcher/Workspace.java b/src/com/android/launcher/Workspace.java
index 73cff02..0ca1b5a 100644
--- a/src/com/android/launcher/Workspace.java
+++ b/src/com/android/launcher/Workspace.java
@@ -34,8 +34,6 @@
 import android.os.Parcelable;
 import android.os.Parcel;
 
-import com.android.internal.provider.Settings;
-
 import java.util.ArrayList;
 
 /**
@@ -249,7 +247,7 @@
      * @param currentScreen
      */
     void setCurrentScreen(int currentScreen) {
-        mCurrentScreen = Math.max(0, Math.min(currentScreen, getChildCount()));
+        mCurrentScreen = Math.max(0, Math.min(currentScreen, getChildCount() - 1));
         scrollTo(mCurrentScreen * getWidth(), 0);
         invalidate();
     }
@@ -426,7 +424,7 @@
             mScrollY = mScroller.getCurrY();
             postInvalidate();
         } else if (mNextScreen != INVALID_SCREEN) {
-            mCurrentScreen = mNextScreen;
+            mCurrentScreen = Math.max(0, Math.min(mNextScreen, getChildCount() - 1));
             Launcher.setScreen(mCurrentScreen);
             mNextScreen = INVALID_SCREEN;
             clearChildrenCache();
@@ -784,6 +782,7 @@
     void snapToScreen(int whichScreen) {
         enableChildrenCache();
 
+        whichScreen = Math.max(0, Math.min(whichScreen, getChildCount() - 1));
         boolean changingScreens = whichScreen != mCurrentScreen;
         
         mNextScreen = whichScreen;
@@ -861,7 +860,7 @@
                 final ItemInfo info = (ItemInfo)cell.getTag();
                 CellLayout.LayoutParams lp = (CellLayout.LayoutParams) cell.getLayoutParams();
                 LauncherModel.moveItemInDatabase(mLauncher, info,
-                        Settings.Favorites.CONTAINER_DESKTOP, mCurrentScreen, lp.cellX, lp.cellY);
+                        LauncherSettings.Favorites.CONTAINER_DESKTOP, mCurrentScreen, lp.cellX, lp.cellY);
             }
         }
     }
@@ -885,8 +884,8 @@
         View view;
 
         switch (info.itemType) {
-        case Settings.Favorites.ITEM_TYPE_APPLICATION:
-        case Settings.Favorites.ITEM_TYPE_SHORTCUT:
+        case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
+        case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
             if (info.container == NO_ID) {
                 // Came from all apps -- make a copy
                 info = new ApplicationInfo((ApplicationInfo) info);
@@ -894,7 +893,7 @@
             view = mLauncher.createShortcut(R.layout.application, cellLayout,
                     (ApplicationInfo) info);
             break;
-        case Settings.Favorites.ITEM_TYPE_USER_FOLDER:
+        case LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER:
             view = FolderIcon.fromXml(R.layout.folder_icon, mLauncher,
                     (ViewGroup) getChildAt(mCurrentScreen), ((UserFolderInfo) info));
             break;
@@ -910,7 +909,7 @@
         final LauncherModel model = Launcher.getModel();
         model.addDesktopItem(info);
         LauncherModel.addOrMoveItemInDatabase(mLauncher, info,
-                Settings.Favorites.CONTAINER_DESKTOP, mCurrentScreen, lp.cellX, lp.cellY);
+                LauncherSettings.Favorites.CONTAINER_DESKTOP, mCurrentScreen, lp.cellX, lp.cellY);
     }
 
     public boolean acceptDrop(DragSource source, int x, int y, int xOffset, int yOffset,