Merge change 24968 into eclair

* changes:
  Minor perf tweak for fountain.
diff --git a/api/current.xml b/api/current.xml
index f8cf61f..ee82e00 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -24714,6 +24714,17 @@
  visibility="public"
 >
 </method>
+<method name="getFastDrawable"
+ return="android.graphics.drawable.Drawable"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getInstance"
  return="android.app.WallpaperManager"
  abstract="false"
@@ -24738,6 +24749,17 @@
  visibility="public"
 >
 </method>
+<method name="peekFastDrawable"
+ return="android.graphics.drawable.Drawable"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="setBitmap"
  return="void"
  abstract="false"
@@ -63330,7 +63352,7 @@
  type="android.graphics.drawable.BitmapDrawable"
  static="false"
  final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 <parameter name="filepath" type="java.lang.String">
@@ -63343,6 +63365,30 @@
  deprecated="not deprecated"
  visibility="public"
 >
+<parameter name="res" type="android.content.res.Resources">
+</parameter>
+<parameter name="filepath" type="java.lang.String">
+</parameter>
+</constructor>
+<constructor name="BitmapDrawable"
+ type="android.graphics.drawable.BitmapDrawable"
+ static="false"
+ final="false"
+ deprecated="deprecated"
+ visibility="public"
+>
+<parameter name="is" type="java.io.InputStream">
+</parameter>
+</constructor>
+<constructor name="BitmapDrawable"
+ type="android.graphics.drawable.BitmapDrawable"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="res" type="android.content.res.Resources">
+</parameter>
 <parameter name="is" type="java.io.InputStream">
 </parameter>
 </constructor>
@@ -64521,6 +64567,19 @@
  visibility="public"
 >
 </method>
+<method name="newDrawable"
+ return="android.graphics.drawable.Drawable"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="res" type="android.content.res.Resources">
+</parameter>
+</method>
 </class>
 <class name="DrawableContainer"
  extends="android.graphics.drawable.Drawable"
@@ -101558,6 +101617,17 @@
  visibility="protected"
 >
 </method>
+<method name="quit"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 </class>
 <interface name="IBinder"
  abstract="true"
diff --git a/core/java/android/app/SuggestionsAdapter.java b/core/java/android/app/SuggestionsAdapter.java
index 8730288..8f7e8ca 100644
--- a/core/java/android/app/SuggestionsAdapter.java
+++ b/core/java/android/app/SuggestionsAdapter.java
@@ -395,7 +395,7 @@
             Drawable.ConstantState cachedBg = mBackgroundsCache.get(backgroundColor);
             if (cachedBg != null) {
                 if (DBG) Log.d(LOG_TAG, "Background cache hit for color " + backgroundColor);
-                return cachedBg.newDrawable();
+                return cachedBg.newDrawable(mProviderContext.getResources());
             }
             if (DBG) Log.d(LOG_TAG, "Creating new background for color " + backgroundColor);
             ColorDrawable transparent = new ColorDrawable(0);
@@ -572,7 +572,7 @@
         Drawable.ConstantState cached = mOutsideDrawablesCache.get(drawableId);
         if (cached != null) {
             if (DBG) Log.d(LOG_TAG, "Found icon in cache: " + drawableId);
-            return cached.newDrawable();
+            return cached.newDrawable(mProviderContext.getResources());
         }
 
         Drawable drawable = null;
@@ -663,7 +663,7 @@
         // Using containsKey() since we also store null values.
         if (mOutsideDrawablesCache.containsKey(componentIconKey)) {
             Drawable.ConstantState cached = mOutsideDrawablesCache.get(componentIconKey);
-            return cached == null ? null : cached.newDrawable();
+            return cached == null ? null : cached.newDrawable(mProviderContext.getResources());
         }
         // Then try the activity or application icon
         Drawable drawable = getActivityIcon(component);
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index da40c8a..38cac87 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -22,7 +22,9 @@
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.Canvas;
+import android.graphics.ColorFilter;
 import android.graphics.Paint;
+import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
@@ -56,9 +58,96 @@
     
     private final Context mContext;
     
+    /**
+     * Special drawable that draws a wallpaper as fast as possible.  Assumes
+     * no scaling or placement off (0,0) of the wallpaper (this should be done
+     * at the time the bitmap is loaded).
+     */
+    static class FastBitmapDrawable extends Drawable {
+        private final Bitmap mBitmap;
+        private final int mWidth;
+        private final int mHeight;
+        private int mDrawLeft;
+        private int mDrawTop;
+
+        private FastBitmapDrawable(Bitmap bitmap) {
+            mBitmap = bitmap;
+            mWidth = bitmap.getWidth();
+            mHeight = bitmap.getHeight();
+            setBounds(0, 0, mWidth, mHeight);
+        }
+
+        @Override
+        public void draw(Canvas canvas) {
+            canvas.drawBitmap(mBitmap, mDrawLeft, mDrawTop, null);
+        }
+
+        @Override
+        public int getOpacity() {
+            return PixelFormat.OPAQUE;
+        }
+
+        @Override
+        public void setBounds(int left, int top, int right, int bottom) {
+            mDrawLeft = left + (right-left - mWidth) / 2;
+            mDrawTop = top + (bottom-top - mHeight) / 2;
+        }
+
+        @Override
+        public void setBounds(Rect bounds) {
+            // TODO Auto-generated method stub
+            super.setBounds(bounds);
+        }
+
+        @Override
+        public void setAlpha(int alpha) {
+            throw new UnsupportedOperationException(
+                    "Not supported with this drawable");
+        }
+
+        @Override
+        public void setColorFilter(ColorFilter cf) {
+            throw new UnsupportedOperationException(
+                    "Not supported with this drawable");
+        }
+
+        @Override
+        public void setDither(boolean dither) {
+            throw new UnsupportedOperationException(
+                    "Not supported with this drawable");
+        }
+
+        @Override
+        public void setFilterBitmap(boolean filter) {
+            throw new UnsupportedOperationException(
+                    "Not supported with this drawable");
+        }
+
+        @Override
+        public int getIntrinsicWidth() {
+            return mWidth;
+        }
+
+        @Override
+        public int getIntrinsicHeight() {
+            return mHeight;
+        }
+
+        @Override
+        public int getMinimumWidth() {
+            return mWidth;
+        }
+
+        @Override
+        public int getMinimumHeight() {
+            return mHeight;
+        }
+    }
+    
     static class Globals extends IWallpaperManagerCallback.Stub {
         private IWallpaperManager mService;
         private Bitmap mWallpaper;
+        private Bitmap mDefaultWallpaper;
         
         private static final int MSG_CLEAR_WALLPAPER = 1;
         
@@ -74,6 +163,7 @@
                         case MSG_CLEAR_WALLPAPER:
                             synchronized (this) {
                                 mWallpaper = null;
+                                mDefaultWallpaper = null;
                             }
                             break;
                     }
@@ -90,12 +180,19 @@
             mHandler.sendEmptyMessage(MSG_CLEAR_WALLPAPER);
         }
         
-        public Bitmap peekWallpaperBitmap(Context context) {
+        public Bitmap peekWallpaperBitmap(Context context, boolean returnDefault) {
             synchronized (this) {
                 if (mWallpaper != null) {
                     return mWallpaper;
                 }
+                if (mDefaultWallpaper != null) {
+                    return mDefaultWallpaper;
+                }
                 mWallpaper = getCurrentWallpaperLocked(context);
+                if (mWallpaper == null && returnDefault) {
+                    mDefaultWallpaper = getDefaultWallpaperLocked(context);
+                    return mDefaultWallpaper;
+                }
                 return mWallpaper;
             }
         }
@@ -134,48 +231,48 @@
                         fd.close();
                     } catch (IOException e) {
                     }
-                    if (bm == null) {
+                    
+                    return generateBitmap(context, bm, width, height);
+                }
+            } catch (RemoteException e) {
+            }
+            return null;
+        }
+        
+        private Bitmap getDefaultWallpaperLocked(Context context) {
+            try {
+                InputStream is = context.getResources().openRawResource(
+                        com.android.internal.R.drawable.default_wallpaper);
+                if (is != null) {
+                    int width = mService.getWidthHint();
+                    int height = mService.getHeightHint();
+                    
+                    if (width <= 0 || height <= 0) {
+                        // Degenerate case: no size requested, just load
+                        // bitmap as-is.
+                        Bitmap bm = BitmapFactory.decodeStream(is, null, null);
+                        try {
+                            is.close();
+                        } catch (IOException e) {
+                        }
+                        if (bm != null) {
+                            bm.setDensity(DisplayMetrics.DENSITY_DEVICE);
+                        }
                         return bm;
                     }
-                    bm.setDensity(DisplayMetrics.DENSITY_DEVICE);
                     
-                    // This is the final bitmap we want to return.
-                    Bitmap newbm = Bitmap.createBitmap(width, height,
-                            bm.getConfig());
-                    newbm.setDensity(DisplayMetrics.DENSITY_DEVICE);
-                    Canvas c = new Canvas(newbm);
-                    c.setDensity(DisplayMetrics.DENSITY_DEVICE);
-                    Rect targetRect = new Rect();
-                    targetRect.left = targetRect.top = 0;
-                    targetRect.right = bm.getWidth();
-                    targetRect.bottom = bm.getHeight();
-                    
-                    int deltaw = width - targetRect.right;
-                    int deltah = height - targetRect.bottom;
-                    
-                    if (deltaw > 0 || deltah > 0) {
-                        // We need to scale up so it covers the entire
-                        // area.
-                        float scale = 1.0f;
-                        if (deltaw > deltah) {
-                            scale = width / (float)targetRect.right;
-                        } else {
-                            scale = height / (float)targetRect.bottom;
-                        }
-                        targetRect.right = (int)(targetRect.right*scale);
-                        targetRect.bottom = (int)(targetRect.bottom*scale);
-                        deltaw = width - targetRect.right;
-                        deltah = height - targetRect.bottom;
+                    // Load the bitmap with full color depth, to preserve
+                    // quality for later processing.
+                    BitmapFactory.Options options = new BitmapFactory.Options();
+                    options.inDither = false;
+                    options.inPreferredConfig = Bitmap.Config.ARGB_8888;
+                    Bitmap bm = BitmapFactory.decodeStream(is, null, options);
+                    try {
+                        is.close();
+                    } catch (IOException e) {
                     }
                     
-                    targetRect.offset(deltaw/2, deltah/2);
-                    Paint paint = new Paint();
-                    paint.setFilterBitmap(true);
-                    paint.setDither(true);
-                    c.drawBitmap(bm, null, targetRect, paint);
-                    
-                    bm.recycle();
-                    return newbm;
+                    return generateBitmap(context, bm, width, height);
                 }
             } catch (RemoteException e) {
             }
@@ -219,9 +316,13 @@
      * @return Returns a Drawable object that will draw the wallpaper.
      */
     public Drawable getDrawable() {
-        Drawable dr = peekDrawable();
-        return dr != null ? dr : Resources.getSystem().getDrawable(
-                com.android.internal.R.drawable.default_wallpaper);
+        Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, true);
+        if (bm != null) {
+            Drawable dr = new BitmapDrawable(mContext.getResources(), bm);
+            dr.setDither(false);
+            return dr;
+        }
+        return null;
     }
 
     /**
@@ -234,8 +335,51 @@
      * null pointer if these is none.
      */
     public Drawable peekDrawable() {
-        Bitmap bm = sGlobals.peekWallpaperBitmap(mContext);
-        return bm != null ? new BitmapDrawable(mContext.getResources(), bm) : null;
+        Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, false);
+        if (bm != null) {
+            Drawable dr = new BitmapDrawable(mContext.getResources(), bm);
+            dr.setDither(false);
+            return dr;
+        }
+        return null;
+    }
+
+    /**
+     * Like {@link #peekFastDrawable}, but always returns a valid Drawable.  If
+     * no wallpaper is set, the system default wallpaper is returned.
+     *
+     * @return Returns a Drawable object that will draw the wallpaper.
+     */
+    public Drawable getFastDrawable() {
+        Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, true);
+        if (bm != null) {
+            Drawable dr = new FastBitmapDrawable(bm);
+            return dr;
+        }
+        return null;
+    }
+
+    /**
+     * Like {@link #peekDrawable()}, but the returned Drawable has a number
+     * of limitations to reduce its overhead as much as possible: it will
+     * never scale the wallpaper (only centering it if the requested bounds
+     * do match the bitmap bounds, which should not be typical), doesn't
+     * allow setting an alpha, color filter, or other attributes, etc.  The
+     * bounds of the returned drawable will be initialized to the same bounds
+     * as the wallpaper, so normally you will not need to touch it.  The
+     * drawable also assumes that it will be used in a context running in
+     * the same density as the screen (not in density compatibility mode).
+     *
+     * @return Returns an optimized Drawable object that will draw the
+     * wallpaper or a null pointer if these is none.
+     */
+    public Drawable peekFastDrawable() {
+        Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, false);
+        if (bm != null) {
+            Drawable dr = new FastBitmapDrawable(bm);
+            return dr;
+        }
+        return null;
     }
 
     /**
@@ -429,8 +573,10 @@
      */
     public void setWallpaperOffsets(IBinder windowToken, float xOffset, float yOffset) {
         try {
+            //Log.v(TAG, "Sending new wallpaper offsets from app...");
             ViewRoot.getWindowSession(mContext.getMainLooper()).setWallpaperPosition(
                     windowToken, xOffset, yOffset);
+            //Log.v(TAG, "...app returning after sending offsets!");
         } catch (RemoteException e) {
             // Ignore.
         }
@@ -466,4 +612,51 @@
     public void clear() throws IOException {
         setResource(com.android.internal.R.drawable.default_wallpaper);
     }
+    
+    static Bitmap generateBitmap(Context context, Bitmap bm, int width, int height) {
+        if (bm == null) {
+            return bm;
+        }
+        bm.setDensity(DisplayMetrics.DENSITY_DEVICE);
+        
+        // This is the final bitmap we want to return.
+        // XXX We should get the pixel depth from the system (to match the
+        // physical display depth), when there is a way.
+        Bitmap newbm = Bitmap.createBitmap(width, height,
+                Bitmap.Config.RGB_565);
+        newbm.setDensity(DisplayMetrics.DENSITY_DEVICE);
+        Canvas c = new Canvas(newbm);
+        c.setDensity(DisplayMetrics.DENSITY_DEVICE);
+        Rect targetRect = new Rect();
+        targetRect.left = targetRect.top = 0;
+        targetRect.right = bm.getWidth();
+        targetRect.bottom = bm.getHeight();
+        
+        int deltaw = width - targetRect.right;
+        int deltah = height - targetRect.bottom;
+        
+        if (deltaw > 0 || deltah > 0) {
+            // We need to scale up so it covers the entire
+            // area.
+            float scale = 1.0f;
+            if (deltaw > deltah) {
+                scale = width / (float)targetRect.right;
+            } else {
+                scale = height / (float)targetRect.bottom;
+            }
+            targetRect.right = (int)(targetRect.right*scale);
+            targetRect.bottom = (int)(targetRect.bottom*scale);
+            deltaw = width - targetRect.right;
+            deltah = height - targetRect.bottom;
+        }
+        
+        targetRect.offset(deltaw/2, deltah/2);
+        Paint paint = new Paint();
+        paint.setFilterBitmap(true);
+        paint.setDither(true);
+        c.drawBitmap(bm, null, targetRect, paint);
+        
+        bm.recycle();
+        return newbm;
+    }
 }
diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java
index 6d27bc7..1e590f0 100644
--- a/core/java/android/content/SyncManager.java
+++ b/core/java/android/content/SyncManager.java
@@ -87,13 +87,37 @@
     private static final long MILLIS_IN_4WEEKS = MILLIS_IN_WEEK * 4;
 
     /** Delay a sync due to local changes this long. In milliseconds */
-    private static final long LOCAL_SYNC_DELAY = 30 * 1000; // 30 seconds
+    private static final long LOCAL_SYNC_DELAY;
 
     /**
      * If a sync takes longer than this and the sync queue is not empty then we will
      * cancel it and add it back to the end of the sync queue. In milliseconds.
      */
-    private static final long MAX_TIME_PER_SYNC = 5 * 60 * 1000; // 5 minutes
+    private static final long MAX_TIME_PER_SYNC;
+
+    static {
+        String localSyncDelayString = SystemProperties.get("sync.local_sync_delay");
+        long localSyncDelay = 30 * 1000; // 30 seconds
+        if (localSyncDelayString != null) {
+            try {
+                localSyncDelay = Long.parseLong(localSyncDelayString);
+            } catch (NumberFormatException nfe) {
+                // ignore, use default
+            }
+        }
+        LOCAL_SYNC_DELAY = localSyncDelay;
+
+        String maxTimePerSyncString = SystemProperties.get("sync.max_time_per_sync");
+        long maxTimePerSync = 5 * 60 * 1000; // 5 minutes
+        if (maxTimePerSyncString != null) {
+            try {
+                maxTimePerSync = Long.parseLong(maxTimePerSyncString);
+            } catch (NumberFormatException nfe) {
+                // ignore, use default
+            }
+        }
+        MAX_TIME_PER_SYNC = maxTimePerSync;
+    }
 
     private static final long SYNC_NOTIFICATION_DELAY = 30 * 1000; // 30 seconds
 
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index ba5c9ed..3796201 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -22,8 +22,6 @@
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
-import android.content.pm.ApplicationInfo;
-import android.graphics.BitmapFactory;
 import android.graphics.Movie;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.ColorDrawable;
@@ -1664,7 +1662,7 @@
 
         Drawable.ConstantState cs = sPreloadedDrawables.get(key);
         if (cs != null) {
-            dr = cs.newDrawable();
+            dr = cs.newDrawable(this);
         } else {
             if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT &&
                     value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
@@ -1699,7 +1697,7 @@
                 } else {
                     try {
                         InputStream is = mAssets.openNonAsset(
-                                value.assetCookie, file, AssetManager.ACCESS_BUFFER);
+                                value.assetCookie, file, AssetManager.ACCESS_STREAMING);
         //                System.out.println("Opened file " + file + ": " + is);
                         dr = Drawable.createFromResourceStream(this, value, is,
                                 file, null);
@@ -1745,7 +1743,7 @@
                     //Log.i(TAG, "Returning cached drawable @ #" +
                     //        Integer.toHexString(((Integer)key).intValue())
                     //        + " in " + this + ": " + entry);
-                    return entry.newDrawable();
+                    return entry.newDrawable(this);
                 }
                 else {  // our entry has been purged
                     mDrawableCache.delete(key);
diff --git a/core/java/android/os/HandlerThread.java b/core/java/android/os/HandlerThread.java
index 0ce86db..65301e4 100644
--- a/core/java/android/os/HandlerThread.java
+++ b/core/java/android/os/HandlerThread.java
@@ -64,7 +64,7 @@
     /**
      * This method returns the Looper associated with this thread. If this thread not been started
      * or for any reason is isAlive() returns false, this method will return null. If this thread 
-     * has been started, this method will blocked until the looper has been initialized.  
+     * has been started, this method will block until the looper has been initialized.  
      * @return The looper.
      */
     public Looper getLooper() {
@@ -85,6 +85,21 @@
     }
     
     /**
+     * Ask the currently running looper to quit.  If the thread has not
+     * been started or has finished (that is if {@link #getLooper} returns
+     * null), then false is returned.  Otherwise the looper is asked to
+     * quit and true is returned.
+     */
+    public boolean quit() {
+        Looper looper = getLooper();
+        if (looper != null) {
+            looper.quit();
+            return true;
+        }
+        return false;
+    }
+    
+    /**
      * Returns the identifier of this thread. See Process.myTid().
      */
     public int getThreadId() {
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index e5659d5..cd5cf10 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -28,9 +28,11 @@
 import android.content.IntentFilter;
 import android.graphics.Rect;
 import android.os.IBinder;
+import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
 import android.util.Log;
+import android.util.LogPrinter;
 import android.view.Gravity;
 import android.view.IWindowSession;
 import android.view.MotionEvent;
@@ -74,6 +76,8 @@
     private static final int MSG_WINDOW_RESIZED = 10030;
     private static final int MSG_TOUCH_EVENT = 10040;
     
+    private Looper mCallbackLooper;
+    
     /**
      * The actual implementation of a wallpaper.  A wallpaper service may
      * have multiple instances running (for example as a real wallpaper
@@ -120,6 +124,7 @@
         boolean mOffsetMessageEnqueued;
         float mPendingXOffset;
         float mPendingYOffset;
+        boolean mPendingSync;
         MotionEvent mPendingMove;
         
         final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@@ -212,10 +217,14 @@
             }
 
             @Override
-            public void dispatchWallpaperOffsets(float x, float y) {
+            public void dispatchWallpaperOffsets(float x, float y, boolean sync) {
                 synchronized (mLock) {
+                    if (DEBUG) Log.v(TAG, "Dispatch wallpaper offsets: " + x + ", " + y);
                     mPendingXOffset = x;
                     mPendingYOffset = y;
+                    if (sync) {
+                        mPendingSync = true;
+                    }
                     if (!mOffsetMessageEnqueued) {
                         mOffsetMessageEnqueued = true;
                         Message msg = mCaller.obtainMessage(MSG_WALLPAPER_OFFSETS);
@@ -551,9 +560,12 @@
             
             float xOffset;
             float yOffset;
+            boolean sync;
             synchronized (mLock) {
                 xOffset = mPendingXOffset;
                 yOffset = mPendingYOffset;
+                sync = mPendingSync;
+                mPendingSync = false;
                 mOffsetMessageEnqueued = false;
             }
             if (DEBUG) Log.v(TAG, "Offsets change in " + this
@@ -563,6 +575,14 @@
             final int availh = mIWallpaperEngine.mReqHeight-mCurHeight;
             final int yPixels = availh > 0 ? -(int)(availh*yOffset+.5f) : 0;
             onOffsetsChanged(xOffset, yOffset, xPixels, yPixels);
+            
+            if (sync) {
+                try {
+                    if (DEBUG) Log.v(TAG, "Reporting offsets change complete");
+                    mSession.wallpaperOffsetsComplete(mWindow.asBinder());
+                } catch (RemoteException e) {
+                }
+            }
         }
         
         void detach() {
@@ -622,7 +642,13 @@
         IWallpaperEngineWrapper(WallpaperService context,
                 IWallpaperConnection conn, IBinder windowToken,
                 int windowType, boolean isPreview, int reqWidth, int reqHeight) {
-            mCaller = new HandlerCaller(context, this);
+            if (DEBUG && mCallbackLooper != null) {
+                mCallbackLooper.setMessageLogging(new LogPrinter(Log.VERBOSE, TAG));
+            }
+            mCaller = new HandlerCaller(context,
+                    mCallbackLooper != null
+                            ? mCallbackLooper : context.getMainLooper(),
+                    this);
             mConnection = conn;
             mWindowToken = windowToken;
             mWindowType = windowType;
@@ -736,5 +762,18 @@
         return new IWallpaperServiceWrapper(this);
     }
     
+    /**
+     * This allows subclasses to change the thread that most callbacks
+     * occur on.  Currently hidden because it is mostly needed for the
+     * image wallpaper (which runs in the system process and doesn't want
+     * to get stuck running on that seriously in use main thread).  Not
+     * exposed right now because the semantics of this are not totally
+     * well defined and some callbacks can still happen on the main thread).
+     * @hide
+     */
+    public void setCallbackLooper(Looper looper) {
+        mCallbackLooper = looper;
+    }
+    
     public abstract Engine onCreateEngine();
 }
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index ebc5f7b..b7953af2 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -60,5 +60,5 @@
     /**
      * Called for wallpaper windows when their offsets change.
      */
-    void dispatchWallpaperOffsets(float x, float y);
+    void dispatchWallpaperOffsets(float x, float y, boolean sync);
 }
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 4d662d2..9b8b6d4 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -114,4 +114,6 @@
      * larger than the screen, set the offset within the screen.
      */
     void setWallpaperPosition(IBinder windowToken, float x, float y);
+    
+    void wallpaperOffsetsComplete(IBinder window);
 }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index f63c2f1..2cc243e 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -6042,12 +6042,11 @@
         int height = mBottom - mTop;
 
         final AttachInfo attachInfo = mAttachInfo;
-        final float scale = attachInfo.mApplicationScale;
+        final float scale = attachInfo != null ? attachInfo.mApplicationScale : 1.0f;
         width = (int) ((width * scale) + 0.5f);
         height = (int) ((height * scale) + 0.5f);
         
-        Bitmap bitmap = Bitmap.createBitmap(width > 0 ? width : 1,
-                height > 0 ? height : 1, quality);
+        Bitmap bitmap = Bitmap.createBitmap(width > 0 ? width : 1, height > 0 ? height : 1, quality);
         if (bitmap == null) {
             throw new OutOfMemoryError();
         }
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index b61465a..6748ade 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -2868,7 +2868,13 @@
             }
         }
         
-        public void dispatchWallpaperOffsets(float x, float y) {
+        public void dispatchWallpaperOffsets(float x, float y, boolean sync) {
+            if (sync) {
+                try {
+                    sWindowSession.wallpaperOffsetsComplete(asBinder());
+                } catch (RemoteException e) {
+                }
+            }
         }
     }
 
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 0f178e9..2329e21 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1394,6 +1394,7 @@
      * Reload the current url.
      */
     public void reload() {
+        clearTextEntry();
         switchOutDrawHistory();
         mWebViewCore.sendMessage(EventHub.RELOAD);
     }
diff --git a/core/java/android/widget/Gallery.java b/core/java/android/widget/Gallery.java
index e7b303a..f34823c 100644
--- a/core/java/android/widget/Gallery.java
+++ b/core/java/android/widget/Gallery.java
@@ -23,7 +23,6 @@
 import android.content.res.TypedArray;
 import android.graphics.Rect;
 import android.util.AttributeSet;
-import android.util.Config;
 import android.util.Log;
 import android.view.GestureDetector;
 import android.view.Gravity;
@@ -36,8 +35,6 @@
 import android.view.SoundEffectConstants;
 import android.view.ContextMenu.ContextMenuInfo;
 import android.view.animation.Transformation;
-import android.widget.AbsSpinner;
-import android.widget.Scroller;
 
 /**
  * A view that shows items in a center-locked, horizontally scrolling list.
@@ -59,7 +56,7 @@
 
     private static final String TAG = "Gallery";
 
-    private static final boolean localLOGV = Config.LOGV;
+    private static final boolean localLOGV = false;
 
     /**
      * Duration in milliseconds from the start of a scroll during which we're
@@ -514,6 +511,7 @@
             // We haven't been callbacking during the fling, so do it now
             super.selectionChanged();
         }
+        invalidate();
     }
     
     @Override
@@ -534,12 +532,9 @@
         
         int galleryCenter = getCenterOfGallery();
         
-        if (selView != null) {
-
-            // Common case where the current selected position is correct
-            if (selView.getLeft() <= galleryCenter && selView.getRight() >= galleryCenter) {
-                return;
-            }
+        // Common case where the current selected position is correct
+        if (selView.getLeft() <= galleryCenter && selView.getRight() >= galleryCenter) {
+            return;
         }
         
         // TODO better search
@@ -627,7 +622,6 @@
         View sel = makeAndAddView(mSelectedPosition, 0, 0, true);
         
         // Put the selected child in the center
-        Gallery.LayoutParams lp = (Gallery.LayoutParams) sel.getLayoutParams();
         int selectedOffset = childrenLeft + (childrenWidth / 2) - (sel.getWidth() / 2);
         sel.offsetLeftAndRight(selectedOffset);
 
@@ -733,9 +727,6 @@
             child = mRecycler.get(position);
             if (child != null) {
                 // Can reuse an existing view
-                Gallery.LayoutParams lp = (Gallery.LayoutParams) 
-                    child.getLayoutParams();
-
                 int childLeft = child.getLeft();
                 
                 // Remember left and right edges of where views have been placed
@@ -798,7 +789,7 @@
         int childRight;
 
         // Position vertically based on gravity setting
-        int childTop = calculateTop(child, lp, true);
+        int childTop = calculateTop(child, true);
         int childBottom = childTop + child.getMeasuredHeight();
 
         int width = child.getMeasuredWidth();
@@ -817,11 +808,9 @@
      * Figure out vertical placement based on mGravity
      * 
      * @param child Child to place
-     * @param lp LayoutParams for this view (just so we don't keep looking them
-     *        up)
      * @return Where the top of the child should be
      */
-    private int calculateTop(View child, Gallery.LayoutParams lp, boolean duringLayout) {
+    private int calculateTop(View child, boolean duringLayout) {
         int myHeight = duringLayout ? mMeasuredHeight : getHeight();
         int childHeight = duringLayout ? child.getMeasuredHeight() : child.getHeight(); 
         
diff --git a/core/java/com/android/internal/os/HandlerCaller.java b/core/java/com/android/internal/os/HandlerCaller.java
index 5825024..35b9251 100644
--- a/core/java/com/android/internal/os/HandlerCaller.java
+++ b/core/java/com/android/internal/os/HandlerCaller.java
@@ -57,6 +57,13 @@
         mCallback = callback;
     }
 
+    public HandlerCaller(Context context, Looper looper, Callback callback) {
+        mContext = context;
+        mMainLooper = looper;
+        mH = new MyHandler(mMainLooper);
+        mCallback = callback;
+    }
+
     public SomeArgs obtainArgs() {
         synchronized (mH) {
             SomeArgs args = mArgsPool;
diff --git a/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java b/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java
index 5357469..0bc70de 100644
--- a/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java
+++ b/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java
@@ -20,6 +20,8 @@
 import android.graphics.Canvas;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
+import android.os.HandlerThread;
+import android.os.Process;
 import android.service.wallpaper.WallpaperService;
 import android.view.MotionEvent;
 import android.view.SurfaceHolder;
@@ -33,20 +35,29 @@
  */
 public class ImageWallpaper extends WallpaperService {
     WallpaperManager mWallpaperManager;
+    private HandlerThread mThread;
 
     @Override
     public void onCreate() {
         super.onCreate();
         mWallpaperManager = (WallpaperManager) getSystemService(WALLPAPER_SERVICE);
+        mThread = new HandlerThread("Wallpaper", Process.THREAD_PRIORITY_FOREGROUND);
+        mThread.start();
+        setCallbackLooper(mThread.getLooper());
     }
 
     public Engine onCreateEngine() {
         return new DrawableEngine();
     }
 
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        mThread.quit();
+    }
+
     class DrawableEngine extends Engine {
         private final Object mLock = new Object();
-        private final Rect mBounds = new Rect();
         private WallpaperObserver mReceiver;
         Drawable mBackground;
         float mXOffset;
@@ -56,6 +67,9 @@
             public void onReceive(Context context, Intent intent) {
                 updateWallpaper();
                 drawFrame();
+                // Assume we are the only one using the wallpaper in this
+                // process, and force a GC now to release the old wallpaper.
+                System.gc();
             }
         }
 
@@ -67,7 +81,6 @@
             registerReceiver(mReceiver, filter);
             updateWallpaper();
             surfaceHolder.setSizeFromLayout();
-            //setTouchEventsEnabled(true);
         }
 
         @Override
@@ -137,11 +150,7 @@
 
         void updateWallpaper() {
             synchronized (mLock) {
-                mBackground = mWallpaperManager.getDrawable();
-                mBounds.left = mBounds.top = 0;
-                mBounds.right = mBackground.getIntrinsicWidth();
-                mBounds.bottom = mBackground.getIntrinsicHeight();
-                mBackground.setBounds(mBounds);
+                mBackground = mWallpaperManager.getFastDrawable();
             }
         }
     }
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index f4f6297..b8d19ac 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -90,6 +90,12 @@
     public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
     }
     
-    public void dispatchWallpaperOffsets(float x, float y) {
+    public void dispatchWallpaperOffsets(float x, float y, boolean sync) {
+        if (sync) {
+            try {
+                mSession.wallpaperOffsetsComplete(asBinder());
+            } catch (RemoteException e) {
+            }
+        }
     }
 }
diff --git a/core/java/com/android/internal/view/menu/IconMenuView.java b/core/java/com/android/internal/view/menu/IconMenuView.java
index b81c2b3..bba2ee2 100644
--- a/core/java/com/android/internal/view/menu/IconMenuView.java
+++ b/core/java/com/android/internal/view/menu/IconMenuView.java
@@ -282,7 +282,9 @@
         itemView.setIconMenuView(this);
         
         // Apply the background to the item view
-        itemView.setBackgroundDrawable(mItemBackground.getConstantState().newDrawable());
+        itemView.setBackgroundDrawable(
+                mItemBackground.getConstantState().newDrawable(
+                        getContext().getResources()));
 
         // This class is the invoker for all its item views 
         itemView.setItemInvoker(this);
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index 7748aba..5b6c7ea 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -32,6 +32,7 @@
 #include <sys/errno.h>
 #include <sys/resource.h>
 #include <sys/types.h>
+#include <cutils/sched_policy.h>
 #include <dirent.h>
 #include <fcntl.h>
 #include <grp.h>
@@ -186,58 +187,6 @@
     return -1;
 }
 
-static int add_pid_to_cgroup(int pid, const char *grp_name)
-{
-    int fd;
-    char path[255];
-    char text[64];
-
-    sprintf(path, "/dev/cpuctl/%s/tasks", grp_name);
-
-    if ((fd = open(path, O_WRONLY)) < 0)
-        return -1;
-
-    sprintf(text, "%d", pid);
-    if (write(fd, text, strlen(text)) < 0) {
-        close(fd);
-        return -1;
-    }
-
-    close(fd);
-    return 0;
-}
-
-void setSchedPolicy(JNIEnv* env, jobject clazz, int pid, SchedPolicy policy)
-{
-    static int __sys_supports_schedgroups = -1;
-
-    if (__sys_supports_schedgroups < 0) {
-        if (!access("/dev/cpuctl/tasks", F_OK)) {
-            __sys_supports_schedgroups = 1;
-        } else {
-            __sys_supports_schedgroups = 0;
-        }
-    }
-
-    if (__sys_supports_schedgroups) {
-        const char *grp = NULL;
-
-        if (policy == SP_BACKGROUND) {
-            grp = "bg_non_interactive";
-        }
-
-        if (add_pid_to_cgroup(pid, grp)) {
-            if (errno != ESRCH && errno != ENOENT)
-                signalExceptionForGroupError(env, clazz, errno);
-        }
-    } else {
-        struct sched_param param;
-
-        param.sched_priority = 0;
-        sched_setscheduler(pid, (policy == SP_BACKGROUND) ? 5 : 0, &param);
-    }
-}
-
 void android_os_Process_setThreadGroup(JNIEnv* env, jobject clazz, int pid, jint grp)
 {
     if (grp > ANDROID_TGROUP_MAX || grp < 0) { 
@@ -245,9 +194,10 @@
         return;
     }
 
-    setSchedPolicy(env, clazz, pid,
-                   (grp == ANDROID_TGROUP_BG_NONINTERACT) ?
-                           SP_BACKGROUND : SP_FOREGROUND);
+    if (set_sched_policy(pid, (grp == ANDROID_TGROUP_BG_NONINTERACT) ?
+                                      SP_BACKGROUND : SP_FOREGROUND)) {
+        signalExceptionForGroupError(env, clazz, errno);
+    }
 }
 
 void android_os_Process_setProcessGroup(JNIEnv* env, jobject clazz, int pid, jint grp) 
@@ -291,9 +241,10 @@
             continue;
         }
      
-        setSchedPolicy(env, clazz, t_pid,
-                       (grp == ANDROID_TGROUP_BG_NONINTERACT) ?
-                               SP_BACKGROUND : SP_FOREGROUND);
+        if (set_sched_policy(t_pid, (grp == ANDROID_TGROUP_BG_NONINTERACT) ?
+                                            SP_BACKGROUND : SP_FOREGROUND)) {
+            signalExceptionForGroupError(env, clazz, errno);
+        }
     }
     closedir(d);
 }
@@ -301,10 +252,16 @@
 void android_os_Process_setThreadPriority(JNIEnv* env, jobject clazz,
                                               jint pid, jint pri)
 {
+    int rc = 0;
+
     if (pri >= ANDROID_PRIORITY_BACKGROUND) {
-        setSchedPolicy(env, clazz, pid, SP_BACKGROUND);
+        rc = set_sched_policy(pid, SP_BACKGROUND);
     } else if (getpriority(PRIO_PROCESS, pid) >= ANDROID_PRIORITY_BACKGROUND) {
-        setSchedPolicy(env, clazz, pid, SP_FOREGROUND);
+        rc = set_sched_policy(pid, SP_FOREGROUND);
+    }
+
+    if (rc) {
+        signalExceptionForGroupError(env, clazz, errno);
     }
 
     if (setpriority(PRIO_PROCESS, pid, pri) < 0) {
diff --git a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
index ac96f20..58206d4 100644
--- a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
@@ -45,11 +45,11 @@
     private boolean mRunning;
 
     public AnimatedRotateDrawable() {
-        this(null);
+        this(null, null);
     }
 
-    private AnimatedRotateDrawable(AnimatedRotateState rotateState) {
-        mState = new AnimatedRotateState(rotateState, this);
+    private AnimatedRotateDrawable(AnimatedRotateState rotateState, Resources res) {
+        mState = new AnimatedRotateState(rotateState, this, res);
         init();
     }
 
@@ -296,9 +296,14 @@
         private boolean mCanConstantState;
         private boolean mCheckedConstantState;        
 
-        public AnimatedRotateState(AnimatedRotateState source, AnimatedRotateDrawable owner) {
+        public AnimatedRotateState(AnimatedRotateState source, AnimatedRotateDrawable owner,
+                Resources res) {
             if (source != null) {
-                mDrawable = source.mDrawable.getConstantState().newDrawable();
+                if (res != null) {
+                    mDrawable = source.mDrawable.getConstantState().newDrawable(res);
+                } else {
+                    mDrawable = source.mDrawable.getConstantState().newDrawable();
+                }
                 mDrawable.setCallback(owner);
                 mPivotXRel = source.mPivotXRel;
                 mPivotX = source.mPivotX;
@@ -312,7 +317,12 @@
 
         @Override
         public Drawable newDrawable() {
-            return new AnimatedRotateDrawable(this);
+            return new AnimatedRotateDrawable(this, null);
+        }
+        
+        @Override
+        public Drawable newDrawable(Resources res) {
+            return new AnimatedRotateDrawable(this, res);
         }
         
         @Override
diff --git a/graphics/java/android/graphics/drawable/AnimationDrawable.java b/graphics/java/android/graphics/drawable/AnimationDrawable.java
index 68718c9..fdc4c92 100644
--- a/graphics/java/android/graphics/drawable/AnimationDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimationDrawable.java
@@ -77,7 +77,7 @@
     private boolean mMutated;
 
     public AnimationDrawable() {
-        this(null);
+        this(null, null);
     }
 
     @Override
@@ -297,8 +297,9 @@
         private int[] mDurations;
         private boolean mOneShot;
 
-        AnimationState(AnimationState orig, AnimationDrawable owner) {
-            super(orig, owner);
+        AnimationState(AnimationState orig, AnimationDrawable owner,
+                Resources res) {
+            super(orig, owner, res);
 
             if (orig != null) {
                 mDurations = orig.mDurations;
@@ -311,7 +312,12 @@
 
         @Override
         public Drawable newDrawable() {
-            return new AnimationDrawable(this);
+            return new AnimationDrawable(this, null);
+        }
+
+        @Override
+        public Drawable newDrawable(Resources res) {
+            return new AnimationDrawable(this, res);
         }
 
         public void addFrame(Drawable dr, int dur) {
@@ -330,8 +336,8 @@
         }
     }
 
-    private AnimationDrawable(AnimationState state) {
-        AnimationState as = new AnimationState(state, this);
+    private AnimationDrawable(AnimationState state, Resources res) {
+        AnimationState as = new AnimationState(state, this, res);
         mAnimationState = as;
         setConstantState(as);
         if (state != null) {
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index 30cef67..e82f297 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -60,15 +60,15 @@
             Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG;
     private BitmapState mBitmapState;
     private Bitmap mBitmap;
+    private int mTargetDensity;
+
     private final Rect mDstRect = new Rect();   // Gravity.apply() sets this
 
     private boolean mApplyGravity;
     private boolean mRebuildShader;
     private boolean mMutated;
     
-    private int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
-
-    // These are scaled to match the target density.
+     // These are scaled to match the target density.
     private int mBitmapWidth;
     private int mBitmapHeight;
     
@@ -88,10 +88,7 @@
      */
     public BitmapDrawable(Resources res) {
         mBitmapState = new BitmapState((Bitmap) null);
-        if (res != null) {
-            setTargetDensity(res.getDisplayMetrics());
-            mBitmapState.mTargetDensity = mTargetDensity;
-        }
+        mBitmapState.mTargetDensity = mTargetDensity;
     }
 
     /**
@@ -101,7 +98,7 @@
      */
     @Deprecated
     public BitmapDrawable(Bitmap bitmap) {
-        this(new BitmapState(bitmap));
+        this(new BitmapState(bitmap), null);
     }
 
     /**
@@ -109,22 +106,51 @@
      * the display metrics of the resources.
      */
     public BitmapDrawable(Resources res, Bitmap bitmap) {
-        this(new BitmapState(bitmap));
-        if (res != null) {
-            setTargetDensity(res.getDisplayMetrics());
-            mBitmapState.mTargetDensity = mTargetDensity;
-        }
+        this(new BitmapState(bitmap), res);
+        mBitmapState.mTargetDensity = mTargetDensity;
     }
 
+    /**
+     * Create a drawable by opening a given file path and decoding the bitmap.
+     * @deprecated Use {@link #BitmapDrawable(Resources, String)} to ensure
+     * that the drawable has correctly set its target density.
+     */
     public BitmapDrawable(String filepath) {
-        this(new BitmapState(BitmapFactory.decodeFile(filepath)));
+        this(new BitmapState(BitmapFactory.decodeFile(filepath)), null);
         if (mBitmap == null) {
             android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + filepath);
         }
     }
 
+    /**
+     * Create a drawable by opening a given file path and decoding the bitmap.
+     */
+    public BitmapDrawable(Resources res, String filepath) {
+        this(new BitmapState(BitmapFactory.decodeFile(filepath)), null);
+        mBitmapState.mTargetDensity = mTargetDensity;
+        if (mBitmap == null) {
+            android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + filepath);
+        }
+    }
+
+    /**
+     * Create a drawable by decoding a bitmap from the given input stream.
+     * @deprecated Use {@link #BitmapDrawable(Resources, java.io.InputStream)} to ensure
+     * that the drawable has correctly set its target density.
+     */
     public BitmapDrawable(java.io.InputStream is) {
-        this(new BitmapState(BitmapFactory.decodeStream(is)));
+        this(new BitmapState(BitmapFactory.decodeStream(is)), null);
+        if (mBitmap == null) {
+            android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + is);
+        }
+    }
+
+    /**
+     * Create a drawable by decoding a bitmap from the given input stream.
+     */
+    public BitmapDrawable(Resources res, java.io.InputStream is) {
+        this(new BitmapState(BitmapFactory.decodeStream(is)), null);
+        mBitmapState.mTargetDensity = mTargetDensity;
         if (mBitmap == null) {
             android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + is);
         }
@@ -425,7 +451,12 @@
 
         @Override
         public Drawable newDrawable() {
-            return new BitmapDrawable(this);
+            return new BitmapDrawable(this, null);
+        }
+        
+        @Override
+        public Drawable newDrawable(Resources res) {
+            return new BitmapDrawable(this, res);
         }
         
         @Override
@@ -434,9 +465,15 @@
         }
     }
 
-    private BitmapDrawable(BitmapState state) {
+    private BitmapDrawable(BitmapState state, Resources res) {
         mBitmapState = state;
-        mTargetDensity = state.mTargetDensity;
+        if (res != null) {
+            mTargetDensity = res.getDisplayMetrics().densityDpi;
+        } else if (state != null) {
+            mTargetDensity = state.mTargetDensity;
+        } else {
+            mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
+        }
         setBitmap(state.mBitmap);
     }
 }
diff --git a/graphics/java/android/graphics/drawable/ClipDrawable.java b/graphics/java/android/graphics/drawable/ClipDrawable.java
index 95d4dd0..c387a9b 100644
--- a/graphics/java/android/graphics/drawable/ClipDrawable.java
+++ b/graphics/java/android/graphics/drawable/ClipDrawable.java
@@ -48,14 +48,14 @@
     public static final int VERTICAL = 2;
     
     ClipDrawable() {
-        this(null);
+        this(null, null);
     }
 
     /**
      * @param orientation Bitwise-or of {@link #HORIZONTAL} and/or {@link #VERTICAL}
      */
     public ClipDrawable(Drawable drawable, int gravity, int orientation) {
-        this(null);
+        this(null, null);
 
         mClipState.mDrawable = drawable;
         mClipState.mGravity = gravity;
@@ -241,9 +241,13 @@
         private boolean mCheckedConstantState;
         private boolean mCanConstantState;
 
-        ClipState(ClipState orig, ClipDrawable owner) {
+        ClipState(ClipState orig, ClipDrawable owner, Resources res) {
             if (orig != null) {
-                mDrawable = orig.mDrawable.getConstantState().newDrawable();
+                if (res != null) {
+                    mDrawable = orig.mDrawable.getConstantState().newDrawable(res);
+                } else {
+                    mDrawable = orig.mDrawable.getConstantState().newDrawable();
+                }
                 mDrawable.setCallback(owner);
                 mOrientation = orig.mOrientation;
                 mGravity = orig.mGravity;
@@ -253,7 +257,12 @@
 
         @Override
         public Drawable newDrawable() {
-            return new ClipDrawable(this);
+            return new ClipDrawable(this, null);
+        }
+
+        @Override
+        public Drawable newDrawable(Resources res) {
+            return new ClipDrawable(this, res);
         }
 
         @Override
@@ -271,8 +280,8 @@
         }
     }
 
-    private ClipDrawable(ClipState state) {
-        mClipState = new ClipState(state, this);
+    private ClipDrawable(ClipState state, Resources res) {
+        mClipState = new ClipState(state, this, res);
     }
 }
 
diff --git a/graphics/java/android/graphics/drawable/ColorDrawable.java b/graphics/java/android/graphics/drawable/ColorDrawable.java
index 226cc04..604c602 100644
--- a/graphics/java/android/graphics/drawable/ColorDrawable.java
+++ b/graphics/java/android/graphics/drawable/ColorDrawable.java
@@ -146,6 +146,11 @@
         }
 
         @Override
+        public Drawable newDrawable(Resources res) {
+            return new ColorDrawable(this);
+        }
+
+        @Override
         public int getChangingConfigurations() {
             return mChangingConfigurations;
         }
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 21b5e39..6a7b2d1 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -822,7 +822,26 @@
     }
 
     public static abstract class ConstantState {
+        /**
+         * Create a new drawable without supplying resources the caller
+         * is running in.  Note that using this means the density-dependent
+         * drawables (like bitmaps) will not be able to update their target
+         * density correctly.
+         */
         public abstract Drawable newDrawable();
+        /**
+         * Create a new Drawable instance from its constant state.  This
+         * must be implemented for drawables that change based on the target
+         * density of their caller (that is depending on whether it is
+         * in compatibility mode).
+         */
+        public Drawable newDrawable(Resources res) {
+            return newDrawable();
+        }
+        /**
+         * Return a bit mask of configuration changes that will impact
+         * this drawable (and thus require completely reloading it).
+         */
         public abstract int getChangingConfigurations();
     }
 
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index af1a289..3266f1e 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -16,6 +16,7 @@
 
 package android.graphics.drawable;
 
+import android.content.res.Resources;
 import android.graphics.*;
 
 public class DrawableContainer extends Drawable implements Drawable.Callback {
@@ -285,7 +286,8 @@
 
         boolean     mPaddingChecked = false;
 
-        DrawableContainerState(DrawableContainerState orig, DrawableContainer owner) {
+        DrawableContainerState(DrawableContainerState orig, DrawableContainer owner,
+                Resources res) {
             mOwner = owner;
 
             if (orig != null) {
@@ -299,7 +301,11 @@
 
                 final int N = mNumChildren;
                 for (int i=0; i<N; i++) {
-                    mDrawables[i] = origDr[i].getConstantState().newDrawable();
+                    if (res != null) {
+                        mDrawables[i] = origDr[i].getConstantState().newDrawable(res);
+                    } else {
+                        mDrawables[i] = origDr[i].getConstantState().newDrawable();
+                    }
                     mDrawables[i].setCallback(owner);
                 }
 
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index a7a8708..ddbbaf1 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -917,6 +917,11 @@
         }
         
         @Override
+        public Drawable newDrawable(Resources res) {
+            return new GradientDrawable(this);
+        }
+        
+        @Override
         public int getChangingConfigurations() {
             return mChangingConfigurations;
         }
diff --git a/graphics/java/android/graphics/drawable/InsetDrawable.java b/graphics/java/android/graphics/drawable/InsetDrawable.java
index 6047726..4fa9d44 100644
--- a/graphics/java/android/graphics/drawable/InsetDrawable.java
+++ b/graphics/java/android/graphics/drawable/InsetDrawable.java
@@ -49,7 +49,7 @@
     private boolean mMutated;
 
     /*package*/ InsetDrawable() {
-        this(null);
+        this(null, null);
     }
 
     public InsetDrawable(Drawable drawable, int inset) {
@@ -58,7 +58,7 @@
 
     public InsetDrawable(Drawable drawable, int insetLeft, int insetTop,
                          int insetRight, int insetBottom) {
-        this(null);
+        this(null, null);
         
         mInsetState.mDrawable = drawable;
         mInsetState.mInsetLeft = insetLeft;
@@ -263,9 +263,13 @@
         boolean mCheckedConstantState;
         boolean mCanConstantState;
 
-        InsetState(InsetState orig, InsetDrawable owner) {
+        InsetState(InsetState orig, InsetDrawable owner, Resources res) {
             if (orig != null) {
-                mDrawable = orig.mDrawable.getConstantState().newDrawable();
+                if (res != null) {
+                    mDrawable = orig.mDrawable.getConstantState().newDrawable(res);
+                } else {
+                    mDrawable = orig.mDrawable.getConstantState().newDrawable();
+                }
                 mDrawable.setCallback(owner);
                 mInsetLeft = orig.mInsetLeft;
                 mInsetTop = orig.mInsetTop;
@@ -277,7 +281,12 @@
 
         @Override
         public Drawable newDrawable() {
-            return new InsetDrawable(this);
+            return new InsetDrawable(this, null);
+        }
+        
+        @Override
+        public Drawable newDrawable(Resources res) {
+            return new InsetDrawable(this, res);
         }
         
         @Override
@@ -295,8 +304,8 @@
         }
     }
 
-    private InsetDrawable(InsetState state) {
-        mInsetState = new InsetState(state, this);
+    private InsetDrawable(InsetState state, Resources res) {
+        mInsetState = new InsetState(state, this, res);
     }
 }
 
diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
index c777205..389fd40 100644
--- a/graphics/java/android/graphics/drawable/LayerDrawable.java
+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
@@ -70,7 +70,7 @@
      * @param state The constant drawable state.
      */
     LayerDrawable(Drawable[] layers, LayerState state) {
-        this(state);
+        this(state, null);
         int length = layers.length;
         ChildDrawable[] r = new ChildDrawable[length];
 
@@ -87,19 +87,19 @@
     }
     
     LayerDrawable() {
-        this((LayerState) null);
+        this((LayerState) null, null);
     }
 
-    LayerDrawable(LayerState state) {
-        LayerState as = createConstantState(state);
+    LayerDrawable(LayerState state, Resources res) {
+        LayerState as = createConstantState(state, res);
         mLayerState = as;
         if (as.mNum > 0) {
             ensurePadding();
         }
     }
 
-    LayerState createConstantState(LayerState state) {
-        return new LayerState(state, this);
+    LayerState createConstantState(LayerState state, Resources res) {
+        return new LayerState(state, this, res);
     }
 
     @Override
@@ -563,7 +563,7 @@
         private boolean mCheckedConstantState;
         private boolean mCanConstantState;
 
-        LayerState(LayerState orig, LayerDrawable owner) {
+        LayerState(LayerState orig, LayerDrawable owner, Resources res) {
             if (orig != null) {
                 final ChildDrawable[] origChildDrawable = orig.mChildren;
                 final int N = orig.mNum;
@@ -577,7 +577,11 @@
                 for (int i = 0; i < N; i++) {
                     final ChildDrawable r = mChildren[i] = new ChildDrawable();
                     final ChildDrawable or = origChildDrawable[i];
-                    r.mDrawable = or.mDrawable.getConstantState().newDrawable();
+                    if (res != null) {
+                        r.mDrawable = or.mDrawable.getConstantState().newDrawable(res);
+                    } else {
+                        r.mDrawable = or.mDrawable.getConstantState().newDrawable();
+                    }
                     r.mDrawable.setCallback(owner);
                     r.mInsetL = or.mInsetL;
                     r.mInsetT = or.mInsetT;
@@ -599,7 +603,12 @@
 
         @Override
         public Drawable newDrawable() {
-            return new LayerDrawable(this);
+            return new LayerDrawable(this, null);
+        }
+        
+        @Override
+        public Drawable newDrawable(Resources res) {
+            return new LayerDrawable(this, res);
         }
         
         @Override
diff --git a/graphics/java/android/graphics/drawable/LevelListDrawable.java b/graphics/java/android/graphics/drawable/LevelListDrawable.java
index 7ae649f..ae8f224 100644
--- a/graphics/java/android/graphics/drawable/LevelListDrawable.java
+++ b/graphics/java/android/graphics/drawable/LevelListDrawable.java
@@ -57,7 +57,7 @@
     private boolean mMutated;
 
     public LevelListDrawable() {
-        this(null);
+        this(null, null);
     }
 
     public void addLevel(int low, int high, Drawable drawable) {
@@ -154,8 +154,8 @@
         private int[] mLows;
         private int[] mHighs;
 
-        LevelListState(LevelListState orig, LevelListDrawable owner) {
-            super(orig, owner);
+        LevelListState(LevelListState orig, LevelListDrawable owner, Resources res) {
+            super(orig, owner, res);
 
             if (orig != null) {
                 mLows = orig.mLows;
@@ -186,7 +186,12 @@
 
         @Override
         public Drawable newDrawable() {
-            return new LevelListDrawable(this);
+            return new LevelListDrawable(this, null);
+        }
+
+        @Override
+        public Drawable newDrawable(Resources res) {
+            return new LevelListDrawable(this, res);
         }
 
         @Override
@@ -201,8 +206,8 @@
         }
     }
 
-    private LevelListDrawable(LevelListState state) {
-        LevelListState as = new LevelListState(state, this);
+    private LevelListDrawable(LevelListState state, Resources res) {
+        LevelListState as = new LevelListState(state, this, res);
         mLevelListState = as;
         setConstantState(as);
         onLevelChange(getLevel());
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index 997efb8..803e7b1 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -61,7 +61,7 @@
      */
     @Deprecated
     public NinePatchDrawable(Bitmap bitmap, byte[] chunk, Rect padding, String srcName) {
-        this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding));
+        this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding), null);
     }
     
     /**
@@ -70,11 +70,8 @@
      */
     public NinePatchDrawable(Resources res, Bitmap bitmap, byte[] chunk,
             Rect padding, String srcName) {
-        this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding));
-        if (res != null) {
-            setTargetDensity(res.getDisplayMetrics());
-            mNinePatchState.mTargetDensity = mTargetDensity;
-        }
+        this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding), res);
+        mNinePatchState.mTargetDensity = mTargetDensity;
     }
     
     /**
@@ -84,7 +81,7 @@
      */
     @Deprecated
     public NinePatchDrawable(NinePatch patch) {
-        this(new NinePatchState(patch, null));
+        this(new NinePatchState(patch, null), null);
     }
 
     /**
@@ -92,18 +89,16 @@
      * based on the display metrics of the resources.
      */
     public NinePatchDrawable(Resources res, NinePatch patch) {
-        this(new NinePatchState(patch, null));
-        if (res != null) {
-            setTargetDensity(res.getDisplayMetrics());
-            mNinePatchState.mTargetDensity = mTargetDensity;
-        }
+        this(new NinePatchState(patch, null), res);
+        mNinePatchState.mTargetDensity = mTargetDensity;
     }
 
-    private void setNinePatchState(NinePatchState state) {
+    private void setNinePatchState(NinePatchState state, Resources res) {
         mNinePatchState = state;
         mNinePatch = state.mNinePatch;
         mPadding = state.mPadding;
-        mTargetDensity = state.mTargetDensity;
+        mTargetDensity = res != null ? res.getDisplayMetrics().densityDpi
+                : state.mTargetDensity;
         if (DEFAULT_DITHER != state.mDither) {
             // avoid calling the setter unless we need to, since it does a
             // lazy allocation of a paint
@@ -258,7 +253,8 @@
         }
 
         setNinePatchState(new NinePatchState(
-                new NinePatch(bitmap, bitmap.getNinePatchChunk(), "XML 9-patch"), padding, dither));
+                new NinePatch(bitmap, bitmap.getNinePatchChunk(), "XML 9-patch"),
+                padding, dither), r);
         mNinePatchState.mTargetDensity = mTargetDensity;
 
         a.recycle();
@@ -357,7 +353,12 @@
 
         @Override
         public Drawable newDrawable() {
-            return new NinePatchDrawable(this);
+            return new NinePatchDrawable(this, null);
+        }
+        
+        @Override
+        public Drawable newDrawable(Resources res) {
+            return new NinePatchDrawable(this, res);
         }
         
         @Override
@@ -366,8 +367,7 @@
         }
     }
 
-    private NinePatchDrawable(NinePatchState state) {
-        setNinePatchState(state);
+    private NinePatchDrawable(NinePatchState state, Resources res) {
+        setNinePatchState(state, res);
     }
 }
-
diff --git a/graphics/java/android/graphics/drawable/RotateDrawable.java b/graphics/java/android/graphics/drawable/RotateDrawable.java
index cb16cb7..c4a7822 100644
--- a/graphics/java/android/graphics/drawable/RotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/RotateDrawable.java
@@ -54,7 +54,7 @@
      * <p>Create a new rotating drawable with an empty state.</p>
      */
     public RotateDrawable() {
-        this(null);
+        this(null, null);
     }
 
     /**
@@ -64,8 +64,8 @@
      *
      * @param rotateState the state for this drawable
      */
-    private RotateDrawable(RotateState rotateState) {
-        mState = new RotateState(rotateState, this);
+    private RotateDrawable(RotateState rotateState, Resources res) {
+        mState = new RotateState(rotateState, this, res);
     }
 
     public void draw(Canvas canvas) {
@@ -291,9 +291,13 @@
         private boolean mCanConstantState;
         private boolean mCheckedConstantState;        
 
-        public RotateState(RotateState source, RotateDrawable owner) {
+        public RotateState(RotateState source, RotateDrawable owner, Resources res) {
             if (source != null) {
-                mDrawable = source.mDrawable.getConstantState().newDrawable();
+                if (res != null) {
+                    mDrawable = source.mDrawable.getConstantState().newDrawable(res);
+                } else {
+                    mDrawable = source.mDrawable.getConstantState().newDrawable();
+                }
                 mDrawable.setCallback(owner);
                 mPivotXRel = source.mPivotXRel;
                 mPivotX = source.mPivotX;
@@ -307,7 +311,12 @@
 
         @Override
         public Drawable newDrawable() {
-            return new RotateDrawable(this);
+            return new RotateDrawable(this, null);
+        }
+        
+        @Override
+        public Drawable newDrawable(Resources res) {
+            return new RotateDrawable(this, res);
         }
         
         @Override
diff --git a/graphics/java/android/graphics/drawable/ScaleDrawable.java b/graphics/java/android/graphics/drawable/ScaleDrawable.java
index 7125ab1..275e36f 100644
--- a/graphics/java/android/graphics/drawable/ScaleDrawable.java
+++ b/graphics/java/android/graphics/drawable/ScaleDrawable.java
@@ -47,11 +47,11 @@
     private final Rect mTmpRect = new Rect();
 
     ScaleDrawable() {
-        this(null);
+        this(null, null);
     }
 
     public ScaleDrawable(Drawable drawable, int gravity, float scaleWidth, float scaleHeight) {
-        this(null);
+        this(null, null);
 
         mScaleState.mDrawable = drawable;
         mScaleState.mGravity = gravity;
@@ -260,9 +260,13 @@
         private boolean mCheckedConstantState;
         private boolean mCanConstantState;
 
-        ScaleState(ScaleState orig, ScaleDrawable owner) {
+        ScaleState(ScaleState orig, ScaleDrawable owner, Resources res) {
             if (orig != null) {
-                mDrawable = orig.mDrawable.getConstantState().newDrawable();
+                if (res != null) {
+                    mDrawable = orig.mDrawable.getConstantState().newDrawable(res);
+                } else {
+                    mDrawable = orig.mDrawable.getConstantState().newDrawable();
+                }
                 mDrawable.setCallback(owner);
                 mScaleWidth = orig.mScaleWidth;
                 mScaleHeight = orig.mScaleHeight;
@@ -273,7 +277,12 @@
 
         @Override
         public Drawable newDrawable() {
-            return new ScaleDrawable(this);
+            return new ScaleDrawable(this, null);
+        }
+
+        @Override
+        public Drawable newDrawable(Resources res) {
+            return new ScaleDrawable(this, res);
         }
 
         @Override
@@ -291,8 +300,8 @@
         }
     }
 
-    private ScaleDrawable(ScaleState state) {
-        mScaleState = new ScaleState(state, this);
+    private ScaleDrawable(ScaleState state, Resources res) {
+        mScaleState = new ScaleState(state, this, res);
     }
 }
 
diff --git a/graphics/java/android/graphics/drawable/ShapeDrawable.java b/graphics/java/android/graphics/drawable/ShapeDrawable.java
index 6677a35..c699a82 100644
--- a/graphics/java/android/graphics/drawable/ShapeDrawable.java
+++ b/graphics/java/android/graphics/drawable/ShapeDrawable.java
@@ -396,6 +396,11 @@
         }
         
         @Override
+        public Drawable newDrawable(Resources res) {
+            return new ShapeDrawable(this);
+        }
+        
+        @Override
         public int getChangingConfigurations() {
             return mChangingConfigurations;
         }
diff --git a/graphics/java/android/graphics/drawable/StateListDrawable.java b/graphics/java/android/graphics/drawable/StateListDrawable.java
index 59cb226..b1d588e 100644
--- a/graphics/java/android/graphics/drawable/StateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/StateListDrawable.java
@@ -65,7 +65,7 @@
     private boolean mMutated;
 
     public StateListDrawable() {
-        this(null);
+        this(null, null);
     }
 
     /**
@@ -248,8 +248,8 @@
     static final class StateListState extends DrawableContainerState {
         private int[][] mStateSets;
 
-        StateListState(StateListState orig, StateListDrawable owner) {
-            super(orig, owner);
+        StateListState(StateListState orig, StateListDrawable owner, Resources res) {
+            super(orig, owner, res);
 
             if (orig != null) {
                 mStateSets = orig.mStateSets;
@@ -277,7 +277,12 @@
 
         @Override
         public Drawable newDrawable() {
-            return new StateListDrawable(this);
+            return new StateListDrawable(this, null);
+        }
+
+        @Override
+        public Drawable newDrawable(Resources res) {
+            return new StateListDrawable(this, res);
         }
 
         @Override
@@ -289,8 +294,8 @@
         }
     }
 
-    private StateListDrawable(StateListState state) {
-        StateListState as = new StateListState(state, this);
+    private StateListDrawable(StateListState state, Resources res) {
+        StateListState as = new StateListState(state, this, res);
         mStateListState = as;
         setConstantState(as);
         onStateChange(getState());
diff --git a/graphics/java/android/graphics/drawable/TransitionDrawable.java b/graphics/java/android/graphics/drawable/TransitionDrawable.java
index 358f889..97b45d8 100644
--- a/graphics/java/android/graphics/drawable/TransitionDrawable.java
+++ b/graphics/java/android/graphics/drawable/TransitionDrawable.java
@@ -16,6 +16,7 @@
 
 package android.graphics.drawable;
 
+import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.os.SystemClock;
 
@@ -72,7 +73,7 @@
      * 2 layers are required for this drawable to work properly.
      */
     public TransitionDrawable(Drawable[] layers) {
-        this(new TransitionState(null, null), layers);
+        this(new TransitionState(null, null, null), layers);
     }
 
     /**
@@ -82,11 +83,11 @@
      * @see #TransitionDrawable(Drawable[])
      */
     TransitionDrawable() {
-        this(new TransitionState(null, null));
+        this(new TransitionState(null, null, null), (Resources)null);
     }
 
-    private TransitionDrawable(TransitionState state) {
-        super(state);
+    private TransitionDrawable(TransitionState state, Resources res) {
+        super(state, res);
     }
 
     private TransitionDrawable(TransitionState state, Drawable[] layers) {
@@ -94,8 +95,8 @@
     }
 
     @Override
-    LayerState createConstantState(LayerState state) {
-        return new TransitionState((TransitionState) state, this);
+    LayerState createConstantState(LayerState state, Resources res) {
+        return new TransitionState((TransitionState) state, this, res);
     }
     
     /**
@@ -229,13 +230,19 @@
     }
 
     static class TransitionState extends LayerState {
-        TransitionState(TransitionState orig, TransitionDrawable owner) {
-            super(orig, owner);
+        TransitionState(TransitionState orig, TransitionDrawable owner,
+                Resources res) {
+            super(orig, owner, res);
         }
 
         @Override
         public Drawable newDrawable() {
-            return new TransitionDrawable(this);
+            return new TransitionDrawable(this, (Resources)null);
+        }
+
+        @Override
+        public Drawable newDrawable(Resources res) {
+            return new TransitionDrawable(this, res);
         }
 
         @Override
diff --git a/include/private/ui/SharedBufferStack.h b/include/private/ui/SharedBufferStack.h
index 6181f55..8b0f154 100644
--- a/include/private/ui/SharedBufferStack.h
+++ b/include/private/ui/SharedBufferStack.h
@@ -228,6 +228,8 @@
     friend struct Condition;
     friend struct DequeueCondition;
     friend struct LockCondition;
+    
+    int32_t computeTail() const;
 
     struct QueueUpdate : public UpdateBase {
         inline QueueUpdate(SharedBufferBase* sbb);
diff --git a/include/utils/threads.h b/include/utils/threads.h
index f5304f7..0fc533f 100644
--- a/include/utils/threads.h
+++ b/include/utils/threads.h
@@ -90,11 +90,6 @@
     ANDROID_TGROUP_MAX              = ANDROID_TGROUP_FG_BOOST,
 };
 
-typedef enum {
-    SP_BACKGROUND = 0,
-    SP_FOREGROUND = 1,
-} SchedPolicy;
-
 // Create and run a new thread.
 extern int androidCreateThread(android_thread_func_t, void *);
 
diff --git a/libs/surfaceflinger/SurfaceFlinger.cpp b/libs/surfaceflinger/SurfaceFlinger.cpp
index 8685f99..a352431 100644
--- a/libs/surfaceflinger/SurfaceFlinger.cpp
+++ b/libs/surfaceflinger/SurfaceFlinger.cpp
@@ -1524,13 +1524,24 @@
                 result.append( l->lcblk->dump("      ") );
                 sp<const Buffer> buf0(l->getBuffer(0));
                 sp<const Buffer> buf1(l->getBuffer(1));
+                uint32_t w0=0, h0=0, s0=0;
+                uint32_t w1=0, h1=0, s1=0;
+                if (buf0 != 0) {
+                    w0 = buf0->getWidth();
+                    h0 = buf0->getHeight();
+                    s0 = buf0->getStride();
+                }
+                if (buf1 != 0) {
+                    w1 = buf1->getWidth();
+                    h1 = buf1->getHeight();
+                    s1 = buf1->getStride();
+                }
                 snprintf(buffer, SIZE,
                         "      "
                         "format=%2d, [%3ux%3u:%3u] [%3ux%3u:%3u],"
                         " freezeLock=%p\n",
                         l->pixelFormat(),
-                        buf0->getWidth(), buf0->getHeight(), buf0->getStride(),
-                        buf1->getWidth(), buf1->getHeight(), buf1->getStride(),
+                        w0, h0, s0, w1, h1, s1,
                         l->getFreezeLock().get());
                 result.append(buffer);
                 buffer[0] = 0;
diff --git a/libs/ui/SharedBufferStack.cpp b/libs/ui/SharedBufferStack.cpp
index 436d793..7789a3f 100644
--- a/libs/ui/SharedBufferStack.cpp
+++ b/libs/ui/SharedBufferStack.cpp
@@ -246,19 +246,26 @@
         int surface, int num)
     : SharedBufferBase(sharedClient, surface, num), tail(0)
 {
+    tail = computeTail();
+}
+
+int32_t SharedBufferClient::computeTail() const
+{
     SharedBufferStack& stack( *mSharedStack );
-    int32_t avail;
-    int32_t head;
     // we need to make sure we read available and head coherently,
     // w.r.t RetireUpdate.
+    int32_t newTail;
+    int32_t avail;
+    int32_t head;
     do {
         avail = stack.available;
         head = stack.head;
     } while (stack.available != avail);
-    tail = head - avail + 1;
-    if (tail < 0) {
-        tail += num;
+    newTail = head - avail + 1;
+    if (newTail < 0) {
+        newTail += mNumBuffers;
     }
+    return newTail;
 }
 
 ssize_t SharedBufferClient::dequeue()
@@ -296,6 +303,9 @@
 {
     UndoDequeueUpdate update(this);
     status_t err = updateCondition( update );
+    if (err == NO_ERROR) {
+        tail = computeTail();
+    }
     return err;
 }
 
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index d905619..22c2f39 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -1266,6 +1266,8 @@
 
         CHECK_EQ(info->mOwnedByComponent, false);
 
+        CODEC_LOGV("freeing buffer %p on port %ld", info->mBuffer, portIndex);
+
         status_t err =
             mOMX->free_buffer(mNode, portIndex, info->mBuffer);
 
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index b0e4038..c844de2 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -418,6 +418,17 @@
     int mWallpaperAnimLayerAdjustment;
     float mLastWallpaperX;
     float mLastWallpaperY;
+    // Lock for waiting for the wallpaper.
+    final Object mWaitingOnWallpaperLock = new Object();
+    // This is set when we are waiting for a wallpaper to tell us it is done
+    // changing its scroll position.
+    WindowState mWaitingOnWallpaper;
+    // The last time we had a timeout when waiting for a wallpaper.
+    long mLastWallpaperTimeoutTime;
+    // We give a wallpaper up to 150ms to finish scrolling.
+    static final long WALLPAPER_TIMEOUT = 150;
+    // Time we wait after a timeout before trying to wait again.
+    static final long WALLPAPER_TIMEOUT_RECOVERY = 10000;
     
     AppWindowToken mFocusedApp = null;
 
@@ -1427,7 +1438,7 @@
                 WindowState wallpaper = token.windows.get(curWallpaperIndex);
                 
                 if (visible) {
-                    updateWallpaperOffsetLocked(wallpaper, dw, dh);                        
+                    updateWallpaperOffsetLocked(wallpaper, dw, dh, false);
                 }
                 
                 // First, make sure the client has the current visibility
@@ -1498,7 +1509,8 @@
         }
     }
 
-    boolean updateWallpaperOffsetLocked(WindowState wallpaperWin, int dw, int dh) {
+    boolean updateWallpaperOffsetLocked(WindowState wallpaperWin, int dw, int dh,
+            boolean sync) {
         boolean changed = false;
         boolean rawChanged = false;
         if (mLastWallpaperX >= 0) {
@@ -1536,8 +1548,37 @@
                 if (DEBUG_WALLPAPER) Log.v(TAG, "Report new wp offset "
                         + wallpaperWin + " x=" + wallpaperWin.mWallpaperX
                         + " y=" + wallpaperWin.mWallpaperY);
+                if (sync) {
+                    synchronized (mWaitingOnWallpaperLock) {
+                        mWaitingOnWallpaper = wallpaperWin;
+                    }
+                }
                 wallpaperWin.mClient.dispatchWallpaperOffsets(
-                        wallpaperWin.mWallpaperX, wallpaperWin.mWallpaperY);
+                        wallpaperWin.mWallpaperX, wallpaperWin.mWallpaperY, sync);
+                if (sync) {
+                    synchronized (mWaitingOnWallpaperLock) {
+                        if (mWaitingOnWallpaper != null) {
+                            long start = SystemClock.uptimeMillis();
+                            if ((mLastWallpaperTimeoutTime+WALLPAPER_TIMEOUT_RECOVERY)
+                                    < start) {
+                                try {
+                                    if (DEBUG_WALLPAPER) Log.v(TAG,
+                                            "Waiting for offset complete...");
+                                    mWaitingOnWallpaperLock.wait(WALLPAPER_TIMEOUT);
+                                } catch (InterruptedException e) {
+                                }
+                                if (DEBUG_WALLPAPER) Log.v(TAG, "Offset complete!");
+                                if ((start+WALLPAPER_TIMEOUT)
+                                        < SystemClock.uptimeMillis()) {
+                                    Log.i(TAG, "Timeout waiting for wallpaper to offset: "
+                                            + wallpaperWin);
+                                    mLastWallpaperTimeoutTime = start;
+                                }
+                            }
+                            mWaitingOnWallpaper = null;
+                        }
+                    }
+                }
             } catch (RemoteException e) {
             }
         }
@@ -1545,7 +1586,17 @@
         return changed;
     }
     
-    boolean updateWallpaperOffsetLocked() {
+    void wallpaperOffsetsComplete(IBinder window) {
+        synchronized (mWaitingOnWallpaperLock) {
+            if (mWaitingOnWallpaper != null &&
+                    mWaitingOnWallpaper.mClient.asBinder() == window) {
+                mWaitingOnWallpaper = null;
+                mWaitingOnWallpaperLock.notifyAll();
+            }
+        }
+    }
+    
+    boolean updateWallpaperOffsetLocked(boolean sync) {
         final int dw = mDisplay.getWidth();
         final int dh = mDisplay.getHeight();
         
@@ -1563,9 +1614,11 @@
                 while (curWallpaperIndex > 0) {
                     curWallpaperIndex--;
                     WindowState wallpaper = token.windows.get(curWallpaperIndex);
-                    if (updateWallpaperOffsetLocked(wallpaper, dw, dh)) {
+                    if (updateWallpaperOffsetLocked(wallpaper, dw, dh, sync)) {
                         wallpaper.computeShownFrameLocked();
                         changed = true;
+                        // We only want to be synchronous with one wallpaper.
+                        sync = false;
                     }
                 }
             }
@@ -1595,7 +1648,7 @@
                 curWallpaperIndex--;
                 WindowState wallpaper = token.windows.get(curWallpaperIndex);
                 if (visible) {
-                    updateWallpaperOffsetLocked(wallpaper, dw, dh);                        
+                    updateWallpaperOffsetLocked(wallpaper, dw, dh, false);
                 }
                 
                 if (wallpaper.mWallpaperVisible != visible) {
@@ -1782,8 +1835,10 @@
                 imMayMove = false;
             } else {
                 addWindowToListInOrderLocked(win, true);
-                if (attrs.type == TYPE_WALLPAPER ||
-                        (attrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
+                if (attrs.type == TYPE_WALLPAPER) {
+                    mLastWallpaperTimeoutTime = 0;
+                    adjustWallpaperWindowsLocked();
+                } else if ((attrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
                     adjustWallpaperWindowsLocked();
                 }
             }
@@ -1992,8 +2047,10 @@
             }
         }
 
-        if (win.mAttrs.type == TYPE_WALLPAPER ||
-                (win.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
+        if (win.mAttrs.type == TYPE_WALLPAPER) {
+            mLastWallpaperTimeoutTime = 0;
+            adjustWallpaperWindowsLocked();
+        } else if ((win.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
             adjustWallpaperWindowsLocked();
         }
         
@@ -2070,7 +2127,7 @@
             window.mWallpaperY = y;
             
             if (mWallpaperTarget == window) {
-                if (updateWallpaperOffsetLocked()) {
+                if (updateWallpaperOffsetLocked(true)) {
                     performLayoutAndPlaceSurfacesLocked();
                 }
             }
@@ -2258,7 +2315,7 @@
             performLayoutAndPlaceSurfacesLocked();
             if (displayed && win.mIsWallpaper) {
                 updateWallpaperOffsetLocked(win, mDisplay.getWidth(),
-                        mDisplay.getHeight());
+                        mDisplay.getHeight(), false);
             }
             if (win.mAppToken != null) {
                 win.mAppToken.updateReportedVisibilityLocked();
@@ -6303,6 +6360,10 @@
             }
         }
         
+        public void wallpaperOffsetsComplete(IBinder window) {
+            WindowManagerService.this.wallpaperOffsetsComplete(window);
+        }
+        
         void windowAddedLocked() {
             if (mSurfaceSession == null) {
                 if (localLOGV) Log.v(
@@ -6698,7 +6759,7 @@
 
             if (mIsWallpaper && (fw != frame.width() || fh != frame.height())) {
                 updateWallpaperOffsetLocked(this, mDisplay.getWidth(),
-                        mDisplay.getHeight());
+                        mDisplay.getHeight(), false);
             }
             
             if (localLOGV) {
diff --git a/tests/DumpRenderTree/assets/run_layout_tests.py b/tests/DumpRenderTree/assets/run_layout_tests.py
index c3e6b5b..c3627bb 100755
--- a/tests/DumpRenderTree/assets/run_layout_tests.py
+++ b/tests/DumpRenderTree/assets/run_layout_tests.py
@@ -197,7 +197,17 @@
     logging.error("DumpRenderTree crashed, output:\n" + adb_output)
 
     shell_cmd_str = adb_cmd + " shell cat /sdcard/android/running_test.txt"
-    crashed_test = subprocess.Popen(shell_cmd_str, shell=True, stdout=subprocess.PIPE).communicate()[0]
+    crashed_test = ""
+    while not crashed_test:
+      (crashed_test, err) = subprocess.Popen(
+          shell_cmd_str, shell=True, stdout=subprocess.PIPE,
+          stderr=subprocess.PIPE).communicate()
+      crashed_test = crashed_test.strip()
+      if not crashed_test:
+        logging.error('Cannot get crashed test name, device offline?')
+        logging.error('stderr: ' + err)
+        logging.error('retrying in 10s...')
+        time.sleep(10)
 
     logging.info(crashed_test + " CRASHED");
     crashed_tests.append(crashed_test);
diff --git a/tests/DumpRenderTree/assets/run_reliability_tests.py b/tests/DumpRenderTree/assets/run_reliability_tests.py
index 23f93df..59ac4a3 100755
--- a/tests/DumpRenderTree/assets/run_reliability_tests.py
+++ b/tests/DumpRenderTree/assets/run_reliability_tests.py
@@ -195,8 +195,18 @@
   while not DumpRenderTreeFinished(adb_cmd):
     logging.error("DumpRenderTree exited before all URLs are visited.")
     shell_cmd_str = adb_cmd + " shell cat " + TEST_STATUS_FILE
-    crashed_test = subprocess.Popen(shell_cmd_str, shell=True,
-                                    stdout=subprocess.PIPE).communicate()[0]
+    crashed_test = ""
+    while not crashed_test:
+      (crashed_test, err) = subprocess.Popen(
+          shell_cmd_str, shell=True, stdout=subprocess.PIPE,
+          stderr=subprocess.PIPE).communicate()
+      crashed_test = crashed_test.strip()
+      if not crashed_test:
+        logging.error('Cannot get crashed test name, device offline?')
+        logging.error('stderr: ' + err)
+        logging.error('retrying in 10s...')
+        time.sleep(10)
+
     logging.info(crashed_test + " CRASHED")
     crashed_tests.append(crashed_test)
     Bugreport(crashed_test, bugreport_dir, adb_cmd)
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
index 55fe4ac..0888fd8 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -1051,15 +1051,22 @@
             // pass for now.
         }
 
+        @SuppressWarnings("unused")
         public void setInsets(IWindow window, int touchable, Rect contentInsets,
                 Rect visibleInsets) {
             // pass for now.
         }
 
+        @SuppressWarnings("unused")
         public void setWallpaperPosition(IBinder window, float x, float y) {
             // pass for now.
         }
 
+        @SuppressWarnings("unused")
+        public void wallpaperOffsetsComplete(IBinder window) {
+            // pass for now.
+        }
+        
         public IBinder asBinder() {
             // pass for now.
             return null;
@@ -1114,7 +1121,7 @@
         }
 
         @SuppressWarnings("unused")
-        public void dispatchWallpaperOffsets(float x, float y) {
+        public void dispatchWallpaperOffsets(float x, float y, boolean sync) {
             // pass for now.
         }