Optimize orientation changes.

Modified setRotation to allow it to restart a rotation in
progress as long as the rotation animation has not yet started.
This enables the system to recover more quickly from mispredicted
orientation changes.

Removed the call to System.gc() when freezing the display, which
added 60-80ms before we even started the orientation change.
We used to need this to make it less likely that an upcoming GC
would cause a pause during the window animation, but this is
not longer a concern with the concurrent GC in place.

Changed the wallpaper surface to be 32bit.  This accelerates
drawing and improves the overall appearance slightly.

Reduced code duplication in the WallpaperManager.

Change-Id: Ic6e5e8bdce4b970b11badddd0355baaed40df88a
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 113c610..3626bf5 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -25,6 +25,8 @@
 import android.graphics.ColorFilter;
 import android.graphics.Paint;
 import android.graphics.PixelFormat;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
 import android.graphics.Rect;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
@@ -115,7 +117,9 @@
 
         @Override
         public void draw(Canvas canvas) {
-            canvas.drawBitmap(mBitmap, mDrawLeft, mDrawTop, null);
+            Paint paint = new Paint();
+            paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
+            canvas.drawBitmap(mBitmap, mDrawLeft, mDrawTop, paint);
         }
 
         @Override
@@ -245,40 +249,20 @@
                 if (fd != null) {
                     int width = params.getInt("width", 0);
                     int height = params.getInt("height", 0);
-                    
-                    if (width <= 0 || height <= 0) {
-                        // Degenerate case: no size requested, just load
-                        // bitmap as-is.
-                        Bitmap bm = null;
-                        try {
-                            bm = BitmapFactory.decodeFileDescriptor(
-                                   fd.getFileDescriptor(), null, null);
-                        } catch (OutOfMemoryError e) {
-                            Log.w(TAG, "Can't decode file", e);
-                        }
+
+                    try {
+                        BitmapFactory.Options options = new BitmapFactory.Options();
+                        Bitmap bm = BitmapFactory.decodeFileDescriptor(
+                                fd.getFileDescriptor(), null, options);
+                        return generateBitmap(context, bm, width, height);
+                    } catch (OutOfMemoryError e) {
+                        Log.w(TAG, "Can't decode file", e);
+                    } finally {
                         try {
                             fd.close();
                         } catch (IOException e) {
                         }
-                        if (bm != null) {
-                            bm.setDensity(DisplayMetrics.DENSITY_DEVICE);
-                        }
-                        return bm;
                     }
-                    
-                    // 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.decodeFileDescriptor(
-                            fd.getFileDescriptor(), null, options);
-                    try {
-                        fd.close();
-                    } catch (IOException e) {
-                    }
-                    
-                    return generateBitmap(context, bm, width, height);
                 }
             } catch (RemoteException e) {
             }
@@ -292,42 +276,18 @@
                 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 = null;
-                        try {
-                            bm = BitmapFactory.decodeStream(is, null, null);
-                        } catch (OutOfMemoryError e) {
-                            Log.w(TAG, "Can't decode stream", e);
-                        }
+
+                    try {
+                        BitmapFactory.Options options = new BitmapFactory.Options();
+                        Bitmap bm = BitmapFactory.decodeStream(is, null, options);
+                        return generateBitmap(context, bm, width, height);
+                    } catch (OutOfMemoryError e) {
+                        Log.w(TAG, "Can't decode stream", e);
+                    } finally {
                         try {
                             is.close();
                         } catch (IOException e) {
                         }
-                        if (bm != null) {
-                            bm.setDensity(DisplayMetrics.DENSITY_DEVICE);
-                        }
-                        return bm;
-                    }
-                    
-                    // 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) {
-                    }
-                    
-                    try {
-                        return generateBitmap(context, bm, width, height);
-                    } catch (OutOfMemoryError e) {
-                        Log.w(TAG, "Can't generate default bitmap", e);
-                        return bm;
                     }
                 }
             } catch (RemoteException e) {
@@ -711,48 +671,54 @@
     
     static Bitmap generateBitmap(Context context, Bitmap bm, int width, int height) {
         if (bm == null) {
+            return null;
+        }
+
+        bm.setDensity(DisplayMetrics.DENSITY_DEVICE);
+
+        if (bm.getWidth() == width && bm.getHeight() == height) {
             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;
+        try {
+            Bitmap newbm = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+            newbm.setDensity(DisplayMetrics.DENSITY_DEVICE);
+
+            Canvas c = new Canvas(newbm);
+            Rect targetRect = new Rect();
+            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.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.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
+            c.drawBitmap(bm, null, targetRect, paint);
+
+            bm.recycle();
+            return newbm;
+        } catch (OutOfMemoryError e) {
+            Log.w(TAG, "Can't generate default bitmap", e);
+            return bm;
         }
-        
-        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/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index eae7574..8fc8b9d 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -181,7 +181,7 @@
         
         final BaseSurfaceHolder mSurfaceHolder = new BaseSurfaceHolder() {
             {
-                mRequestedFormat = PixelFormat.RGB_565;
+                mRequestedFormat = PixelFormat.RGBX_8888;
             }
 
             @Override
diff --git a/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java b/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java
index 85095cf..45f3bc1 100644
--- a/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java
+++ b/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java
@@ -25,6 +25,7 @@
 import android.graphics.Rect;
 import android.graphics.Region.Op;
 import android.graphics.drawable.Drawable;
+import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Looper;
 import android.os.Process;
@@ -46,19 +47,20 @@
 
     WallpaperManager mWallpaperManager;
     private HandlerThread mThread;
+    private Handler mHandler;
 
     @Override
     public void onCreate() {
         super.onCreate();
         mWallpaperManager = (WallpaperManager) getSystemService(WALLPAPER_SERVICE);
         Looper looper = WindowManagerPolicyThread.getLooper();
-        if (looper != null) {
-            setCallbackLooper(looper);
-        } else {
+        if (looper == null) {
             mThread = new HandlerThread("Wallpaper", Process.THREAD_PRIORITY_FOREGROUND);
             mThread.start();
-            setCallbackLooper(mThread.getLooper());
+            looper = mThread.getLooper();
         }
+        setCallbackLooper(looper);
+        mHandler = new Handler(looper);
     }
 
     public Engine onCreateEngine() {
@@ -96,10 +98,6 @@
                     updateWallpaperLocked();
                     drawFrameLocked();
                 }
-
-                // Assume we are the only one using the wallpaper in this
-                // process, and force a GC now to release the old wallpaper.
-                System.gc();
             }
         }
 
@@ -112,7 +110,7 @@
             super.onCreate(surfaceHolder);
             IntentFilter filter = new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED);
             mReceiver = new WallpaperObserver();
-            registerReceiver(mReceiver, filter);
+            registerReceiver(mReceiver, filter, null, mHandler);
 
             updateSurfaceSize(surfaceHolder);
 
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 819c16e..521e1d6 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -426,7 +426,6 @@
     boolean mDisplayFrozen = false;
     boolean mWaitingForConfig = false;
     boolean mWindowsFreezingScreen = false;
-    long mFreezeGcPending = 0;
     int mAppsFreezingScreen = 0;
     int mLastWindowForcedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
 
@@ -4967,9 +4966,11 @@
      * MUST CALL setNewConfiguration() TO UNFREEZE THE SCREEN.
      */
     public boolean setRotationUncheckedLocked(int rotation, int animFlags, boolean inTransaction) {
-        if (mDragState != null || mScreenRotationAnimation != null) {
-            // Potential rotation during a drag.  Don't do the rotation now, but make
-            // a note to perform the rotation later.
+        if (mDragState != null
+                || (mScreenRotationAnimation != null && mScreenRotationAnimation.isAnimating())) {
+            // Potential rotation during a drag or while waiting for a previous orientation
+            // change to finish (rotation animation will be dismissed).
+            // Don't do the rotation now, but make a note to perform the rotation later.
             if (DEBUG_ORIENTATION) Slog.v(TAG, "Deferring rotation.");
             if (rotation != WindowManagerPolicy.USE_LAST_ROTATION) {
                 mDeferredRotation = rotation;
@@ -6371,7 +6372,6 @@
                         if (mDisplayFrozen) {
                             return;
                         }
-                        mFreezeGcPending = 0;
                     }
                     Runtime.getRuntime().gc();
                     break;
@@ -8588,19 +8588,6 @@
 
         mScreenFrozenLock.acquire();
 
-        long now = SystemClock.uptimeMillis();
-        //Slog.i(TAG, "Freezing, gc pending: " + mFreezeGcPending + ", now " + now);
-        if (mFreezeGcPending != 0) {
-            if (now > (mFreezeGcPending+1000)) {
-                //Slog.i(TAG, "Gc!  " + now + " > " + (mFreezeGcPending+1000));
-                mH.removeMessages(H.FORCE_GC);
-                Runtime.getRuntime().gc();
-                mFreezeGcPending = now;
-            }
-        } else {
-            mFreezeGcPending = now;
-        }
-
         mDisplayFrozen = true;
         
         mInputMonitor.freezeInputDispatchingLw();