Merge "Fix for bug 7358703 Gmail ANR when trying to compose a message" into jb-mr1-dev
diff --git a/core/java/android/view/IDisplayContentChangeListener.aidl b/core/java/android/view/IDisplayContentChangeListener.aidl
index 8f23ff6..ef7edea 100644
--- a/core/java/android/view/IDisplayContentChangeListener.aidl
+++ b/core/java/android/view/IDisplayContentChangeListener.aidl
@@ -28,5 +28,6 @@
 oneway interface IDisplayContentChangeListener {
     void onWindowTransition(int displayId, int transition, in WindowInfo info);
     void onRectangleOnScreenRequested(int displayId, in Rect rectangle, boolean immediate);
+    void onWindowLayersChanged(int displayId);
     void onRotationChanged(int rotation);
 }
diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp
index 9fb61e4..4d16bb4 100644
--- a/libs/hwui/TextureCache.cpp
+++ b/libs/hwui/TextureCache.cpp
@@ -228,25 +228,22 @@
     texture->height = bitmap->height();
 
     glBindTexture(GL_TEXTURE_2D, texture->id);
-    if (!regenerate) {
-        glPixelStorei(GL_UNPACK_ALIGNMENT, bitmap->bytesPerPixel());
-    }
 
     switch (bitmap->getConfig()) {
     case SkBitmap::kA8_Config:
-        if (!regenerate) {
-            glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
-        }
+        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
         uploadToTexture(resize, GL_ALPHA, bitmap->rowBytesAsPixels(), texture->height,
                 GL_UNSIGNED_BYTE, bitmap->getPixels());
         texture->blend = true;
         break;
     case SkBitmap::kRGB_565_Config:
+        glPixelStorei(GL_UNPACK_ALIGNMENT, bitmap->bytesPerPixel());
         uploadToTexture(resize, GL_RGB, bitmap->rowBytesAsPixels(), texture->height,
                 GL_UNSIGNED_SHORT_5_6_5, bitmap->getPixels());
         texture->blend = false;
         break;
     case SkBitmap::kARGB_8888_Config:
+        glPixelStorei(GL_UNPACK_ALIGNMENT, bitmap->bytesPerPixel());
         uploadToTexture(resize, GL_RGBA, bitmap->rowBytesAsPixels(), texture->height,
                 GL_UNSIGNED_BYTE, bitmap->getPixels());
         // Do this after calling getPixels() to make sure Skia's deferred
@@ -255,6 +252,7 @@
         break;
     case SkBitmap::kARGB_4444_Config:
     case SkBitmap::kIndex8_Config:
+        glPixelStorei(GL_UNPACK_ALIGNMENT, bitmap->bytesPerPixel());
         uploadLoFiTexture(resize, bitmap, texture->width, texture->height);
         texture->blend = !bitmap->isOpaque();
         break;
diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
index 6877cba..0958f70 100644
--- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
@@ -31,8 +31,10 @@
 import android.renderscript.Matrix4f;
 import android.service.wallpaper.WallpaperService;
 import android.util.Log;
+import android.view.Display;
 import android.view.MotionEvent;
 import android.view.SurfaceHolder;
+import android.view.WindowManager;
 
 import javax.microedition.khronos.egl.EGL10;
 import javax.microedition.khronos.egl.EGLConfig;
@@ -108,6 +110,7 @@
 
         Bitmap mBackground;
         int mBackgroundWidth = -1, mBackgroundHeight = -1;
+        int mLastRotation = -1;
         float mXOffset;
         float mYOffset;
 
@@ -156,7 +159,7 @@
                     mBackgroundWidth = mBackgroundHeight = -1;
                     mBackground = null;
                     mRedrawNeeded = true;
-                    drawFrameLocked(false);
+                    drawFrameLocked();
                 }
             }
         }
@@ -225,7 +228,7 @@
         @Override
         public void onVisibilityChanged(boolean visible) {
             if (DEBUG) {
-                Log.d(TAG, "onVisibilityChanged: visible=" + visible);
+                Log.d(TAG, "onVisibilityChanged: mVisible, visible=" + mVisible + ", " + visible);
             }
 
             synchronized (mLock) {
@@ -234,7 +237,7 @@
                         Log.d(TAG, "Visibility changed to visible=" + visible);
                     }
                     mVisible = visible;
-                    drawFrameLocked(false);
+                    drawFrameLocked();
                 }
             }
         }
@@ -263,7 +266,7 @@
                     mYOffset = yOffset;
                     mOffsetsChanged = true;
                 }
-                drawFrameLocked(false);
+                drawFrameLocked();
             }
         }
 
@@ -276,80 +279,81 @@
             super.onSurfaceChanged(holder, format, width, height);
 
             synchronized (mLock) {
-                mRedrawNeeded = true;
-                mBackgroundWidth = mBackgroundHeight = -1;
-                drawFrameLocked(true);
+                drawFrameLocked();
             }
         }
 
         @Override
+        public void onSurfaceDestroyed(SurfaceHolder holder) {
+            super.onSurfaceDestroyed(holder);
+            mBackgroundWidth = mBackgroundHeight = -1;
+        }
+
+        @Override
+        public void onSurfaceCreated(SurfaceHolder holder) {
+            super.onSurfaceCreated(holder);
+            mBackgroundWidth = mBackgroundHeight = -1;
+        }
+
+        @Override
         public void onSurfaceRedrawNeeded(SurfaceHolder holder) {
             if (DEBUG) {
-                Log.d(TAG, "onSurfaceRedrawNeeded:");
+                Log.d(TAG, "onSurfaceRedrawNeeded");
             }
             super.onSurfaceRedrawNeeded(holder);
 
             synchronized (mLock) {
-                mRedrawNeeded = true;
-                drawFrameLocked(false);
+                drawFrameLocked();
             }
         }
 
-        void drawFrameLocked(boolean force) {
-            if (!force) {
-                if (!mVisible) {
-                    if (DEBUG) {
-                        Log.d(TAG, "Suppressed drawFrame since wallpaper is not visible.");
-                    }
-                    return;
-                }
-                if (!mRedrawNeeded && !mOffsetsChanged) {
-                    if (DEBUG) {
-                        Log.d(TAG, "Suppressed drawFrame since redraw is not needed "
-                                + "and offsets have not changed.");
-                    }
-                    return;
-                }
-            }
-            // If we don't yet know the size of the wallpaper bitmap,
-            // we need to get it now.
-            boolean updateWallpaper = mBackgroundWidth < 0 || mBackgroundHeight < 0 ;
-
-            // If we somehow got to this point after we have last flushed
-            // the wallpaper, well we really need it to draw again.  So
-            // seems like we need to reload it.  Ouch.
-            updateWallpaper = updateWallpaper || mBackground == null;
-
-            if (updateWallpaper) {
-                updateWallpaperLocked();
-            }
-
+        void drawFrameLocked() {
             SurfaceHolder sh = getSurfaceHolder();
             final Rect frame = sh.getSurfaceFrame();
             final int dw = frame.width();
             final int dh = frame.height();
+            int newRotation = ((WindowManager) getSystemService(WINDOW_SERVICE)).
+                    getDefaultDisplay().getRotation();
+
+            boolean redrawNeeded = dw != mBackgroundWidth || dh != mBackgroundHeight ||
+                    newRotation != mLastRotation;
+            if (!redrawNeeded && !mOffsetsChanged) {
+                if (DEBUG) {
+                    Log.d(TAG, "Suppressed drawFrame since redraw is not needed "
+                            + "and offsets have not changed.");
+                }
+                return;
+            }
+            mLastRotation = newRotation;
+
+            // Load bitmap if it is not yet loaded or if it was loaded at a different size
+            if (mBackground == null || dw != mBackgroundWidth || dw != mBackgroundHeight) {
+                if (DEBUG) {
+                    Log.d(TAG, "Reloading bitmap");
+                }
+                mWallpaperManager.forgetLoadedWallpaper();
+                updateWallpaperLocked();
+            }
+
             final int availw = dw - mBackgroundWidth;
             final int availh = dh - mBackgroundHeight;
             int xPixels = availw < 0 ? (int)(availw * mXOffset + .5f) : (availw / 2);
             int yPixels = availh < 0 ? (int)(availh * mYOffset + .5f) : (availh / 2);
 
             mOffsetsChanged = false;
-            if (!force && !mRedrawNeeded
-                    && xPixels == mLastXTranslation && yPixels == mLastYTranslation) {
+            mRedrawNeeded = false;
+            mLastXTranslation = xPixels;
+            mLastYTranslation = yPixels;
+            if (!redrawNeeded && xPixels == mLastXTranslation && yPixels == mLastYTranslation) {
                 if (DEBUG) {
                     Log.d(TAG, "Suppressed drawFrame since the image has not "
                             + "actually moved an integral number of pixels.");
                 }
                 return;
             }
-            mRedrawNeeded = false;
-            mLastXTranslation = xPixels;
-            mLastYTranslation = yPixels;
 
             if (DEBUG) {
-                Log.d(TAG, "drawFrameUnlocked(" + force + "): mBackgroundWxH=" + mBackgroundWidth + "x"
-                        + mBackgroundHeight + " SurfaceFrame=" + frame.toShortString()
-                        + " X,YOffset=" + mXOffset + "," + mYOffset);
+                Log.d(TAG, "Redrawing wallpaper");
             }
             if (mIsHwAccelerated) {
                 if (!drawWallpaperWithOpenGL(sh, availw, availh, xPixels, yPixels)) {
@@ -429,7 +433,6 @@
             final float bottom = top + mBackgroundHeight;
 
             final Rect frame = sh.getSurfaceFrame();
-
             final Matrix4f ortho = new Matrix4f();
             ortho.loadOrtho(0.0f, frame.width(), frame.height(), 0.0f, -1.0f, 1.0f);
 
@@ -437,7 +440,7 @@
 
             final int texture = loadTexture(mBackground);
             final int program = buildProgram(sSimpleVS, sSimpleFS);
-    
+
             final int attribPosition = glGetAttribLocation(program, "position");
             final int attribTexCoords = glGetAttribLocation(program, "texCoords");
             final int uniformTexture = glGetUniformLocation(program, "texture");
@@ -460,7 +463,7 @@
                 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
                 glClear(GL_COLOR_BUFFER_BIT);
             }
-    
+
             // drawQuad
             triangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET);
             glVertexAttribPointer(attribPosition, 3, GL_FLOAT, false,
@@ -471,12 +474,12 @@
                     TRIANGLE_VERTICES_DATA_STRIDE_BYTES, triangleVertices);
 
             glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
-    
+
             if (!mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) {
                 throw new RuntimeException("Cannot swap buffers");
             }
             checkEglError();
-    
+
             finishGL();
 
             return true;
diff --git a/services/java/com/android/server/accessibility/ScreenMagnifier.java b/services/java/com/android/server/accessibility/ScreenMagnifier.java
index c8931f4..d5a8537 100644
--- a/services/java/com/android/server/accessibility/ScreenMagnifier.java
+++ b/services/java/com/android/server/accessibility/ScreenMagnifier.java
@@ -850,6 +850,7 @@
         private static final int MESSAGE_ON_RECTANGLE_ON_SCREEN_REQUESTED = 3;
         private static final int MESSAGE_ON_WINDOW_TRANSITION = 4;
         private static final int MESSAGE_ON_ROTATION_CHANGED = 5;
+        private static final int MESSAGE_ON_WINDOW_LAYERS_CHANGED = 6;
 
         private final Handler mHandler = new MyHandler();
 
@@ -880,24 +881,8 @@
             mDisplayContentChangeListener = new IDisplayContentChangeListener.Stub() {
                 @Override
                 public void onWindowTransition(int displayId, int transition, WindowInfo info) {
-                    Message message = mHandler.obtainMessage(MESSAGE_ON_WINDOW_TRANSITION,
-                            transition, 0, WindowInfo.obtain(info));
-                    // TODO: This makes me quite unhappy but for the time being the
-                    //       least risky fix for cases where the keyguard is removed but
-                    //       the windows it force hides are not made visible yet. Hence,
-                    //       we would compute the magnified frame before we have a stable
-                    //       state. One more reason to move the magnified frame computation
-                    //       in the window manager!
-                    if (info.type == WindowManager.LayoutParams.TYPE_KEYGUARD
-                                || info.type == WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG
-                            && (transition == WindowManagerPolicy.TRANSIT_EXIT
-                                || transition == WindowManagerPolicy.TRANSIT_HIDE)) {
-                        final long delay = (long) (2 * mLongAnimationDuration
-                                * mWindowAnimationScale);
-                        mHandler.sendMessageDelayed(message, delay);
-                    } else {
-                        message.sendToTarget();
-                    }
+                    mHandler.obtainMessage(MESSAGE_ON_WINDOW_TRANSITION,
+                            transition, 0, WindowInfo.obtain(info)).sendToTarget();
                 }
 
                 @Override
@@ -917,6 +902,11 @@
                     mHandler.obtainMessage(MESSAGE_ON_ROTATION_CHANGED, rotation, 0)
                             .sendToTarget();
                 }
+
+                @Override
+                public void onWindowLayersChanged(int displayId) throws RemoteException {
+                    mHandler.sendEmptyMessage(MESSAGE_ON_WINDOW_LAYERS_CHANGED);
+                }
             };
 
             try {
@@ -1192,6 +1182,9 @@
                         final int rotation = message.arg1;
                         handleOnRotationChanged(rotation);
                     } break;
+                    case MESSAGE_ON_WINDOW_LAYERS_CHANGED: {
+                        mViewport.recomputeBounds(mMagnificationController.isMagnifying());
+                    } break;
                     default: {
                         throw new IllegalArgumentException("Unknown message: " + action);
                     }
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 1b3137e..fa450ae 100755
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -6569,6 +6569,36 @@
         }
     }
 
+    private void scheduleNotifyWindowLayersChangedIfNeededLocked(DisplayContent displayContent) {
+        if (displayContent.mDisplayContentChangeListeners != null
+                && displayContent.mDisplayContentChangeListeners.getRegisteredCallbackCount() > 0) {
+            mH.obtainMessage(H.NOTIFY_WINDOW_LAYERS_CHANGED, displayContent) .sendToTarget();
+        }
+    }
+
+    private void handleNotifyWindowLayersChanged(DisplayContent displayContent) {
+        RemoteCallbackList<IDisplayContentChangeListener> callbacks = null;
+        synchronized (mWindowMap) {
+            callbacks = displayContent.mDisplayContentChangeListeners;
+            if (callbacks == null) {
+                return;
+            }
+        }
+        try {
+            final int watcherCount = callbacks.beginBroadcast();
+            for (int i = 0; i < watcherCount; i++) {
+                try {
+                    callbacks.getBroadcastItem(i).onWindowLayersChanged(
+                            displayContent.getDisplayId());
+                } catch (RemoteException re) {
+                    /* ignore */
+                }
+            }
+        } finally {
+            callbacks.finishBroadcast();
+        }
+    }
+
     public void addWindowChangeListener(WindowChangeListener listener) {
         synchronized(mWindowMap) {
             mWindowChangeListeners.add(listener);
@@ -7215,12 +7245,13 @@
         public static final int NOTIFY_ROTATION_CHANGED = 28;
         public static final int NOTIFY_WINDOW_TRANSITION = 29;
         public static final int NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED = 30;
+        public static final int NOTIFY_WINDOW_LAYERS_CHANGED = 31;
 
-        public static final int DO_DISPLAY_ADDED = 31;
-        public static final int DO_DISPLAY_REMOVED = 32;
-        public static final int DO_DISPLAY_CHANGED = 33;
+        public static final int DO_DISPLAY_ADDED = 32;
+        public static final int DO_DISPLAY_REMOVED = 33;
+        public static final int DO_DISPLAY_CHANGED = 34;
 
-        public static final int CLIENT_FREEZE_TIMEOUT = 34;
+        public static final int CLIENT_FREEZE_TIMEOUT = 35;
 
         public static final int ANIMATOR_WHAT_OFFSET = 100000;
         public static final int SET_TRANSPARENT_REGION = ANIMATOR_WHAT_OFFSET + 1;
@@ -7692,6 +7723,12 @@
                     break;
                 }
 
+                case NOTIFY_WINDOW_LAYERS_CHANGED: {
+                    DisplayContent displayContent = (DisplayContent) msg.obj;
+                    handleNotifyWindowLayersChanged(displayContent);
+                    break;
+                }
+
                 case DO_DISPLAY_ADDED:
                     synchronized (mWindowMap) {
                         handleDisplayAddedLocked(msg.arg1);
@@ -8068,6 +8105,8 @@
             Slog.v(TAG, "Assigning layers", here);
         }
 
+        boolean anyLayerChanged = false;
+
         for (i=0; i<N; i++) {
             final WindowState w = windows.get(i);
             final WindowStateAnimator winAnimator = w.mWinAnimator;
@@ -8083,6 +8122,7 @@
             }
             if (w.mLayer != oldLayer) {
                 layerChanged = true;
+                anyLayerChanged = true;
             }
             oldLayer = winAnimator.mAnimLayer;
             if (w.mTargetAppToken != null) {
@@ -8101,6 +8141,7 @@
             }
             if (winAnimator.mAnimLayer != oldLayer) {
                 layerChanged = true;
+                anyLayerChanged = true;
             }
             if (layerChanged && mAnimator.isDimmingLocked(winAnimator)) {
                 // Force an animation pass just to update the mDimAnimator layer.
@@ -8115,6 +8156,10 @@
             //System.out.println(
             //    "Assigned layer " + curLayer + " to " + w.mClient.asBinder());
         }
+
+        if (anyLayerChanged) {
+            scheduleNotifyWindowLayersChangedIfNeededLocked(getDefaultDisplayContentLocked());
+        }
     }
 
     private final void performLayoutAndPlaceSurfacesLocked() {