Suppress orientation changes during drag operations

Fixes bug 3322455

Change-Id: I21d4dbc3aaf6c8ba7afcb73a823d6443c61a4d1b
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 7b7a891..deafb36 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -505,6 +505,10 @@
         ArrayList<WindowState> mNotifiedWindows;
         boolean mDragInProgress;
 
+        boolean mPerformDeferredRotation;
+        int mRotation;
+        int mAnimFlags;
+
         private final Rect tmpRect = new Rect();
 
         DragState(IBinder token, Surface surface, int flags, IBinder localWin) {
@@ -526,6 +530,7 @@
             mData = null;
             mThumbOffsetX = mThumbOffsetY = 0;
             mNotifiedWindows = null;
+            mPerformDeferredRotation = false;
         }
 
         void register() {
@@ -666,9 +671,25 @@
             mDragState.unregister();
             mInputMonitor.updateInputWindowsLw();
 
+            // Retain the parameters of any deferred rotation operation so
+            // that we can perform it after the reset / unref of the drag state
+            final boolean performRotation = mPerformDeferredRotation;
+            final int rotation = mRotation;
+            final int animFlags = mAnimFlags;
+
             // free our resources and drop all the object references
             mDragState.reset();
             mDragState = null;
+
+            // Now that we've officially ended the drag, execute any
+            // deferred rotation
+            if (performRotation) {
+                if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-drag rotation");
+                boolean changed = setRotationUncheckedLocked(rotation, animFlags);
+                if (changed) {
+                    sendNewConfiguration();
+                }
+            }
         }
 
         void notifyMoveLw(float x, float y) {
@@ -812,6 +833,12 @@
 
             return touchedWin;
         }
+
+        void setDeferredRotation(int rotation, int animFlags) {
+            mRotation = rotation;
+            mAnimFlags = animFlags;
+            mPerformDeferredRotation = true;
+        }
     }
 
     DragState mDragState = null;
@@ -5076,6 +5103,14 @@
      * MUST CALL setNewConfiguration() TO UNFREEZE THE SCREEN.
      */
     public boolean setRotationUncheckedLocked(int rotation, int animFlags) {
+        if (mDragState != null) {
+            // Potential rotation during a drag.  Don't do the rotation now, but make
+            // a note to perform the rotation later.
+            if (DEBUG_ORIENTATION) Slog.v(TAG, "Deferring rotation during drag");
+            mDragState.setDeferredRotation(rotation, animFlags);
+            return false;
+        }
+
         boolean changed;
         if (rotation == WindowManagerPolicy.USE_LAST_ROTATION) {
             rotation = mRequestedRotation;
@@ -6496,24 +6531,28 @@
             }
 
             synchronized (mWindowMap) {
-                if (mDragState.mToken != token) {
-                    Slog.w(TAG, "Invalid drop-result claim by " + window);
-                    throw new IllegalStateException("reportDropResult() by non-recipient");
+                long ident = Binder.clearCallingIdentity();
+                try {
+                    if (mDragState.mToken != token) {
+                        Slog.w(TAG, "Invalid drop-result claim by " + window);
+                        throw new IllegalStateException("reportDropResult() by non-recipient");
+                    }
+
+                    // The right window has responded, even if it's no longer around,
+                    // so be sure to halt the timeout even if the later WindowState
+                    // lookup fails.
+                    mH.removeMessages(H.DRAG_END_TIMEOUT, window.asBinder());
+                    WindowState callingWin = windowForClientLocked(null, window, false);
+                    if (callingWin == null) {
+                        Slog.w(TAG, "Bad result-reporting window " + window);
+                        return;  // !!! TODO: throw here?
+                    }
+
+                    mDragState.mDragResult = consumed;
+                    mDragState.endDragLw();
+                } finally {
+                    Binder.restoreCallingIdentity(ident);
                 }
-
-                // The right window has responded, even if it's no longer around,
-                // so be sure to halt the timeout even if the later WindowState
-                // lookup fails.
-                mH.removeMessages(H.DRAG_END_TIMEOUT, window.asBinder());
-
-                WindowState callingWin = windowForClientLocked(null, window, false);
-                if (callingWin == null) {
-                    Slog.w(TAG, "Bad result-reporting window " + window);
-                    return;  // !!! TODO: throw here?
-                }
-
-                mDragState.mDragResult = consumed;
-                mDragState.endDragLw();
             }
         }