More work on wallpapers.

- Do better about figuring out when to stop them and other related window
  management.
- Fix problem where we were not redrawing the surface when the orientation
  changed.  This was the cause of the device hang.
diff --git a/api/current.xml b/api/current.xml
index ee8d2eb..58c0bf8 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -60831,6 +60831,27 @@
 <parameter name="srcName" type="java.lang.String">
 </parameter>
 </method>
+<method name="createFromResourceStream"
+ return="android.graphics.drawable.Drawable"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="res" type="android.content.res.Resources">
+</parameter>
+<parameter name="value" type="android.util.TypedValue">
+</parameter>
+<parameter name="is" type="java.io.InputStream">
+</parameter>
+<parameter name="srcName" type="java.lang.String">
+</parameter>
+<parameter name="opts" type="android.graphics.BitmapFactory.Options">
+</parameter>
+</method>
 <method name="createFromStream"
  return="android.graphics.drawable.Drawable"
  abstract="false"
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index fd8776f..c5ca0a3 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -28,6 +28,7 @@
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.util.Log;
 import android.view.ViewRoot;
 
 import java.io.FileOutputStream;
@@ -82,7 +83,8 @@
             try {
                 ParcelFileDescriptor fd = mService.getWallpaper(this);
                 if (fd != null) {
-                    Bitmap bm = BitmapFactory.decodeFileDescriptor(fd.getFileDescriptor());
+                    Bitmap bm = BitmapFactory.decodeFileDescriptor(
+                            fd.getFileDescriptor(), null, null);
                     if (bm != null) {
                         // For now clear the density until we figure out how
                         // to deal with it for wallpapers.
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 2354519..7d412a7 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -23,6 +23,7 @@
 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;
@@ -1707,7 +1708,8 @@
                         InputStream is = mAssets.openNonAsset(
                                 value.assetCookie, file, AssetManager.ACCESS_BUFFER);
         //                System.out.println("Opened file " + file + ": " + is);
-                        dr = Drawable.createFromResourceStream(this, value, is, file);
+                        dr = Drawable.createFromResourceStream(this, value, is,
+                                file, null);
                         is.close();
         //                System.out.println("Created stream: " + dr);
                     } catch (Exception e) {
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 595b10c..0a3ffff 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -58,6 +58,7 @@
     private static final int MSG_UPDATE_SURFACE = 10000;
     private static final int MSG_VISIBILITY_CHANGED = 10010;
     private static final int MSG_WALLPAPER_OFFSETS = 10020;
+    private static final int MSG_WINDOW_RESIZED = 10030;
     
     /**
      * The actual implementation of a wallpaper.  A wallpaper service may
@@ -130,6 +131,13 @@
         };
         
         final BaseIWindow mWindow = new BaseIWindow() {
+            public void resized(int w, int h, Rect coveredInsets,
+                    Rect visibleInsets, boolean reportDraw) {
+                Message msg = mCaller.obtainMessageI(MSG_WINDOW_RESIZED,
+                        reportDraw ? 1 : 0);
+                mCaller.sendMessage(msg);
+            }
+            
             public void dispatchAppVisibility(boolean visible) {
                 Message msg = mCaller.obtainMessageI(MSG_VISIBILITY_CHANGED,
                         visible ? 1 : 0);
@@ -238,7 +246,7 @@
             
             final boolean creating = !mCreated;
             final boolean formatChanged = mFormat != mSurfaceHolder.getRequestedFormat();
-            final boolean sizeChanged = mWidth != myWidth || mHeight != myHeight;
+            boolean sizeChanged = mWidth != myWidth || mHeight != myHeight;
             final boolean typeChanged = mType != mSurfaceHolder.getRequestedType();
             if (force || creating || formatChanged || sizeChanged || typeChanged) {
 
@@ -286,8 +294,16 @@
                     if (DEBUG) Log.i(TAG, "New surface: " + mSurfaceHolder.mSurface
                             + ", frame=" + mWinFrame);
                     
-                    mCurWidth = mWinFrame.width();
-                    mCurHeight = mWinFrame.height();
+                    int w = mWinFrame.width();
+                    if (mCurWidth != w) {
+                        sizeChanged = true;
+                        mCurWidth = w;
+                    }
+                    int h = mWinFrame.height();
+                    if (mCurHeight != h) {
+                        sizeChanged = true;
+                        mCurHeight = h;
+                    }
                     
                     mSurfaceHolder.mSurfaceLock.unlock();
 
@@ -312,7 +328,7 @@
                                 }
                             }
                         }
-                        if (creating || formatChanged || sizeChanged) {
+                        if (force || creating || formatChanged || sizeChanged) {
                             onSurfaceChanged(mSurfaceHolder, mFormat,
                                     mCurWidth, mCurHeight);
                             if (callbacks != null) {
@@ -452,6 +468,16 @@
                     final int yPixels = availh > 0 ? -(int)(availh*yOffset+.5f) : 0;
                     mEngine.onOffsetsChanged(xOffset, yOffset, xPixels, yPixels);
                 } break;
+                case MSG_WINDOW_RESIZED: {
+                    final boolean reportDraw = message.arg1 != 0;
+                    mEngine.updateSurface(true);
+                    if (reportDraw) {
+                        try {
+                            mEngine.mSession.finishDrawing(mEngine.mWindow);
+                        } catch (RemoteException e) {
+                        }
+                    }
+                } break;
                 default :
                     Log.w(TAG, "Unknown message type " + message.what);
             }
diff --git a/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java b/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java
index bfe8696..7147ac0 100644
--- a/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java
+++ b/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java
@@ -67,8 +67,8 @@
         private final Object mLock = new Object();
         private final Rect mBounds = new Rect();
         Drawable mBackground;
-        int mXOffset;
-        int mYOffset;
+        float mXOffset;
+        float mYOffset;
 
         @Override
         public void onCreate(SurfaceHolder surfaceHolder) {
@@ -85,8 +85,8 @@
         @Override
         public void onOffsetsChanged(float xOffset, float yOffset,
                 int xPixels, int yPixels) {
-            mXOffset = xPixels;
-            mYOffset = yPixels;
+            mXOffset = xOffset;
+            mYOffset = xOffset;
             drawFrame();
         }
 
@@ -110,11 +110,20 @@
             SurfaceHolder sh = getSurfaceHolder();
             Canvas c = sh.lockCanvas();
             if (c != null) {
-                //final Rect frame = sh.getSurfaceFrame();
+                final Rect frame = sh.getSurfaceFrame();
                 synchronized (mLock) {
                     final Drawable background = mBackground;
-                    //background.setBounds(frame);
-                    c.translate(mXOffset, mYOffset);
+                    final int dw = frame.width();
+                    final int dh = frame.height();
+                    final int bw = mBackground.getIntrinsicWidth();
+                    final int bh = mBackground.getIntrinsicHeight();
+                    final int availw = bw-dw;
+                    final int availh = bh-dh;
+                    int xPixels = availw > 0
+                            ? -(int)(availw*mXOffset+.5f) : -(int)(availw/2);
+                    int yPixels = availh > 0
+                            ? -(int)(availh*mYOffset+.5f) : -(int)(availh/2);
+                    c.translate(xPixels, yPixels);
                     c.drawColor(0xff000000);
                     background.draw(c);
                 }
@@ -128,9 +137,6 @@
                 mBounds.left = mBounds.top = 0;
                 mBounds.right = mBackground.getIntrinsicWidth();
                 mBounds.bottom = mBackground.getIntrinsicHeight();
-                int offx = (getDesiredMinimumWidth() - mBounds.right) / 2;
-                int offy = (getDesiredMinimumHeight() - mBounds.bottom) / 2;
-                mBounds.offset(offx, offy);
                 mBackground.setBounds(mBounds);
             }
         }
diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java
index 076cd0c..2abb777 100644
--- a/graphics/java/android/graphics/BitmapFactory.java
+++ b/graphics/java/android/graphics/BitmapFactory.java
@@ -73,7 +73,7 @@
         public Bitmap.Config inPreferredConfig;
 
         /**
-         * If dither is true, the decoder will atttempt to dither the decoded
+         * If dither is true, the decoder will attempt to dither the decoded
          * image.
          */
         public boolean inDither;
@@ -452,6 +452,10 @@
             bm = nativeDecodeStream(is, tempStorage, outPadding, opts);
         }
 
+        return finishDecode(bm, outPadding, opts);
+    }
+
+    private static Bitmap finishDecode(Bitmap bm, Rect outPadding, Options opts) {
         if (bm == null || opts == null) {
             return bm;
         }
@@ -487,7 +491,7 @@
         
         return bm;
     }
-
+    
     /**
      * Decode an input stream into a bitmap. If the input stream is null, or
      * cannot be used to decode a bitmap, the function returns null.
@@ -507,7 +511,7 @@
     /**
      * Decode a bitmap from the file descriptor. If the bitmap cannot be decoded
      * return null. The position within the descriptor will not be changed when
-     * this returns, so the descriptor can be used again as is.
+     * this returns, so the descriptor can be used again as-is.
      *
      * @param fd The file descriptor containing the bitmap data to decode
      * @param outPadding If not null, return the padding rect for the bitmap if
@@ -524,13 +528,15 @@
                 int mappedlength = MemoryFile.getMappedSize(fd);
                 MemoryFile file = new MemoryFile(fd, mappedlength, "r");
                 InputStream is = file.getInputStream();
-                return decodeStream(is, outPadding, opts);
+                Bitmap bm = decodeStream(is, outPadding, opts);
+                return finishDecode(bm, outPadding, opts);
             }
         } catch (IOException ex) {
             // invalid filedescriptor, no need to call nativeDecodeFileDescriptor()
             return null;
         }
-        return nativeDecodeFileDescriptor(fd, outPadding, opts);
+        Bitmap bm = nativeDecodeFileDescriptor(fd, outPadding, opts);
+        return finishDecode(bm, outPadding, opts);
     }
 
     /**
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 193f399..33748ae 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -663,6 +663,15 @@
      */
     public static Drawable createFromResourceStream(Resources res, TypedValue value,
             InputStream is, String srcName) {
+        return createFromResourceStream(res, value, is, srcName);
+    }
+
+    /**
+     * Create a drawable from an inputstream, using the given resources and
+     * value to determine density information.
+     */
+    public static Drawable createFromResourceStream(Resources res, TypedValue value,
+            InputStream is, String srcName, BitmapFactory.Options opts) {
 
         if (is == null) {
             return null;
@@ -683,7 +692,7 @@
         // an application in compatibility mode, without scaling those down
         // to the compatibility density only to have them scaled back up when
         // drawn to the screen.
-        BitmapFactory.Options opts = new BitmapFactory.Options();
+        if (opts == null) opts = new BitmapFactory.Options();
         opts.inScreenDensity = DisplayMetrics.DENSITY_DEVICE;
         Bitmap  bm = BitmapFactory.decodeResourceStream(res, value, is, pad, opts);
         if (bm != null) {
diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java
index 9a293a9..6047742 100644
--- a/services/java/com/android/server/WallpaperManagerService.java
+++ b/services/java/com/android/server/WallpaperManagerService.java
@@ -325,10 +325,10 @@
             ComponentName realName = name;
             if (realName == null) {
                 // The default component is our static image wallpaper.
-                //realName = new ComponentName("android",
-                //        ImageWallpaper.class.getName());
-                clearWallpaperComponentLocked();
-                return;
+                realName = new ComponentName("android",
+                        ImageWallpaper.class.getName());
+                //clearWallpaperComponentLocked();
+                //return;
             }
             ServiceInfo si = mContext.getPackageManager().getServiceInfo(realName,
                     PackageManager.GET_META_DATA | PackageManager.GET_PERMISSIONS);
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index ac80071..6af85db 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -139,6 +139,7 @@
     static final boolean DEBUG_APP_TRANSITIONS = false;
     static final boolean DEBUG_STARTING_WINDOW = false;
     static final boolean DEBUG_REORDER = false;
+    static final boolean DEBUG_WALLPAPER = false;
     static final boolean SHOW_TRANSACTIONS = false;
     static final boolean MEASURE_LATENCY = false;
     static private LatencyTimer lt;
@@ -1187,19 +1188,26 @@
         while (i > 0) {
             i--;
             w = (WindowState)localmWindows.get(i);
-            if ((w.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0 && w.isReadyForDisplay()) {
+            if ((w.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0 && w.isReadyForDisplay()
+                    && !w.mDrawPending && !w.mCommitDrawPending) {
                 visible = true;
                 break;
             }
         }
 
         if (!visible) w = null;
-        //if (mWallpaperTarget != w) {
-        //    Log.v(TAG, "New wallpaper target: " + w);
-        //}
+        if (DEBUG_WALLPAPER && mWallpaperTarget != w) {
+            Log.v(TAG, "New wallpaper target: " + w);
+        }
         mWallpaperTarget = w;
         
         if (visible) {
+            // The window is visible to the compositor...  but is it visible
+            // to the user?  That is what the wallpaper cares about.
+            visible = !w.mObscured;
+            
+            // If the wallpaper target is animating, we may need to copy
+            // its layer adjustment.
             mWallpaperAnimLayerAdjustment = w.mAppToken != null
                     ? w.mAppToken.animLayerAdjustment : 0;
             
@@ -1239,7 +1247,7 @@
                 WindowState wallpaper = token.windows.get(curWallpaperIndex);
                 
                 if (visible) {
-                    updateWallpaperOffsetLocked(mWallpaperTarget, wallpaper, dw, dh);                        
+                    updateWallpaperOffsetLocked(w, wallpaper, dw, dh);                        
                 }
                 
                 // First, make sure the client has the current visibility
@@ -1247,7 +1255,7 @@
                 if (wallpaper.mWallpaperVisible != visible) {
                     wallpaper.mWallpaperVisible = visible;
                     try {
-                        if (DEBUG_VISIBILITY) Log.v(TAG,
+                        if (DEBUG_VISIBILITY || DEBUG_WALLPAPER) Log.v(TAG,
                                 "Setting visibility of wallpaper " + wallpaper
                                 + ": " + visible);
                         wallpaper.mClient.dispatchAppVisibility(visible);
@@ -1256,8 +1264,8 @@
                 }
                 
                 wallpaper.mAnimLayer = wallpaper.mLayer + mWallpaperAnimLayerAdjustment;
-                if (DEBUG_LAYERS) Log.v(TAG, "Wallpaper win " + wallpaper
-                        + " anim layer: " + wallpaper.mAnimLayer);
+                if (DEBUG_LAYERS || DEBUG_WALLPAPER) Log.v(TAG, "Wallpaper win "
+                        + wallpaper + " anim layer: " + wallpaper.mAnimLayer);
                 
                 // First, if this window is at the current index, then all
                 // is well.
@@ -1279,6 +1287,9 @@
                 }
                 
                 // Now stick it in.
+                if (DEBUG_WALLPAPER) Log.v(TAG, "Moving wallpaper " + wallpaper
+                        + " from " + oldIndex + " to " + i);
+                
                 localmWindows.add(i, wallpaper);
                 changed = true;
             }
@@ -1288,7 +1299,8 @@
     }
 
     void setWallpaperAnimLayerAdjustmentLocked(int adj) {
-        if (DEBUG_LAYERS) Log.v(TAG, "Setting wallpaper layer adj to " + adj);
+        if (DEBUG_LAYERS || DEBUG_WALLPAPER) Log.v(TAG,
+                "Setting wallpaper layer adj to " + adj);
         mWallpaperAnimLayerAdjustment = adj;
         int curTokenIndex = mWallpaperTokens.size();
         while (curTokenIndex > 0) {
@@ -1299,8 +1311,8 @@
                 curWallpaperIndex--;
                 WindowState wallpaper = token.windows.get(curWallpaperIndex);
                 wallpaper.mAnimLayer = wallpaper.mLayer + adj;
-                if (DEBUG_LAYERS) Log.v(TAG, "Wallpaper win " + wallpaper
-                        + " anim layer: " + wallpaper.mAnimLayer);
+                if (DEBUG_LAYERS || DEBUG_WALLPAPER) Log.v(TAG, "Wallpaper win "
+                        + wallpaper + " anim layer: " + wallpaper.mAnimLayer);
             }
         }
     }
@@ -1308,27 +1320,38 @@
     boolean updateWallpaperOffsetLocked(WindowState target,
             WindowState wallpaperWin, int dw, int dh) {
         boolean changed = false;
+        boolean rawChanged = false;
         if (target.mWallpaperX >= 0) {
             int availw = wallpaperWin.mFrame.right-wallpaperWin.mFrame.left-dw;
             int offset = availw > 0 ? -(int)(availw*target.mWallpaperX+.5f) : 0;
             changed = wallpaperWin.mXOffset != offset;
             if (changed) {
+                if (DEBUG_WALLPAPER) Log.v(TAG, "Update wallpaper "
+                        + wallpaperWin + " x: " + offset);
                 wallpaperWin.mXOffset = offset;
             }
+            if (wallpaperWin.mWallpaperX != target.mWallpaperX) {
+                wallpaperWin.mWallpaperX = target.mWallpaperX;
+                rawChanged = true;
+            }
         }
+        
         if (target.mWallpaperY >= 0) {
             int availh = wallpaperWin.mFrame.bottom-wallpaperWin.mFrame.top-dh;
             int offset = availh > 0 ? -(int)(availh*target.mWallpaperY+.5f) : 0;
             if (wallpaperWin.mYOffset != offset) {
+                if (DEBUG_WALLPAPER) Log.v(TAG, "Update wallpaper "
+                        + wallpaperWin + " y: " + offset);
                 changed = true;
                 wallpaperWin.mYOffset = offset;
             }
+            if (wallpaperWin.mWallpaperY != target.mWallpaperY) {
+                wallpaperWin.mWallpaperY = target.mWallpaperY;
+                rawChanged = true;
+            }
         }
         
-        if (wallpaperWin.mWallpaperX != target.mWallpaperX
-                || wallpaperWin.mWallpaperY != target.mWallpaperY) {
-            wallpaperWin.mWallpaperX = target.mWallpaperX;
-            wallpaperWin.mWallpaperY = target.mWallpaperY;
+        if (rawChanged) {
             try {
                 wallpaperWin.mClient.dispatchWallpaperOffsets(
                         wallpaperWin.mWallpaperX, wallpaperWin.mWallpaperY);
@@ -5997,6 +6020,7 @@
         int mAnimLayer;
         int mLastLayer;
         boolean mHaveFrame;
+        boolean mObscured;
 
         WindowState mNextOutsideTouch;
 
@@ -6767,6 +6791,12 @@
                         mWallpaperTarget.mAppToken.hasTransformation) {
                     appTransformation = mWallpaperTarget.mAppToken.transformation;
                 }
+                if (DEBUG_WALLPAPER && attachedTransformation != null) {
+                    Log.v(TAG, "WP target attached xform: " + attachedTransformation);
+                }
+                if (DEBUG_WALLPAPER && appTransformation != null) {
+                    Log.v(TAG, "WP target app xform: " + appTransformation);
+                }
             }
             
             if (selfTransformation || attachedTransformation != null
@@ -6919,7 +6949,8 @@
             final boolean animating = atoken != null
                     ? (atoken.animation != null) : false;
             return mSurface != null && mPolicyVisibility && !mDestroying
-                    && ((!mAttachedHidden && !mRootToken.hidden)
+                    && ((!mAttachedHidden && mViewVisibility == View.VISIBLE
+                                    && !mRootToken.hidden)
                             || mAnimation != null || animating);
         }
 
@@ -7119,7 +7150,8 @@
             pw.print(prefix); pw.print("mViewVisibility=0x");
                     pw.print(Integer.toHexString(mViewVisibility));
                     pw.print(" mLastHidden="); pw.print(mLastHidden);
-                    pw.print(" mHaveFrame="); pw.println(mHaveFrame);
+                    pw.print(" mHaveFrame="); pw.print(mHaveFrame);
+                    pw.print(" mObscured="); pw.println(mObscured);
             if (!mPolicyVisibility || !mPolicyVisibilityAfterAnim || mAttachedHidden) {
                 pw.print(prefix); pw.print("mPolicyVisibility=");
                         pw.print(mPolicyVisibility);
@@ -8141,7 +8173,8 @@
 
         for (i=0; i<N; i++) {
             WindowState w = (WindowState)mWindows.get(i);
-            if (w.mBaseLayer == curBaseLayer || w.mIsFloatingLayer) {
+            if (w.mBaseLayer == curBaseLayer || w.mIsImWindow
+                    || (i > 0 && w.mIsWallpaper)) {
                 curLayer += WINDOW_LAYER_MULTIPLIER;
                 w.mLayer = curLayer;
             } else {
@@ -8823,7 +8856,7 @@
                 }
 
                 // Update effect.
-                if (!obscured) {
+                if (!(w.mObscured=obscured)) {
                     if (w.mSurface != null) {
                         if ((attrFlags&FLAG_KEEP_SCREEN_ON) != 0) {
                             holdScreen = w.mSession;
@@ -8989,6 +9022,7 @@
         }
 
         // Destroy the surface of any windows that are no longer visible.
+        boolean wallpaperDestroyed = false;
         i = mDestroySurface.size();
         if (i > 0) {
             do {
@@ -8998,6 +9032,9 @@
                 if (mInputMethodWindow == win) {
                     mInputMethodWindow = null;
                 }
+                if (win == mWallpaperTarget) {
+                    wallpaperDestroyed = true;
+                }
                 win.destroySurfaceLocked();
             } while (i > 0);
             mDestroySurface.clear();
@@ -9026,7 +9063,12 @@
         if (focusDisplayed) {
             mH.sendEmptyMessage(H.REPORT_LOSING_FOCUS);
         }
-        if (animating) {
+        if (wallpaperDestroyed) {
+            wallpaperDestroyed = adjustWallpaperWindowsLocked();            
+        }
+        if (wallpaperDestroyed) {
+            requestAnimationLocked(0);
+        } else if (animating) {
             requestAnimationLocked(currentTime+(1000/60)-SystemClock.uptimeMillis());
         }
         mQueue.setHoldScreenLocked(holdScreen != null);