Merge "AAPT2: Fix issue with parsing escape sequences when the parser only gives us part at a time"
diff --git a/core/java/com/android/internal/view/menu/CascadingMenuPopup.java b/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
index 4c829a2..4e3e40f2 100644
--- a/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
+++ b/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
@@ -15,6 +15,7 @@
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.view.ViewTreeObserver;
 import android.view.View.OnKeyListener;
 import android.widget.AdapterView;
 import android.widget.DropDownListView;
@@ -31,7 +32,8 @@
  * @hide
  */
 final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemClickListener,
-        MenuPresenter, OnKeyListener, PopupWindow.OnDismissListener {
+        MenuPresenter, OnKeyListener, PopupWindow.OnDismissListener,
+        ViewTreeObserver.OnGlobalLayoutListener, View.OnAttachStateChangeListener{
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({HORIZ_POSITION_LEFT, HORIZ_POSITION_RIGHT})
     public @interface HorizPosition {}
@@ -47,13 +49,15 @@
     private final int mLayoutDirection;
 
     private int mDropDownGravity = Gravity.NO_GRAVITY;
-    private View mAnchor;
+    private View mAnchorView;
+    private View mShownAnchorView;
     private List<DropDownListView> mListViews;
     private List<MenuPopupWindow> mPopupWindows;
     private List<int[]> mOffsets;
     private int mPreferredPosition;
     private boolean mForceShowIcon;
     private Callback mPresenterCallback;
+    private ViewTreeObserver mTreeObserver;
     private PopupWindow.OnDismissListener mOnDismissListener;
 
     /**
@@ -64,7 +68,7 @@
     public CascadingMenuPopup(Context context, View anchor, int popupStyleAttr,
             int popupStyleRes, boolean overflowOnly) {
         mContext = Preconditions.checkNotNull(context);
-        mAnchor = Preconditions.checkNotNull(anchor);
+        mAnchorView = Preconditions.checkNotNull(anchor);
         mPopupStyleAttr = popupStyleAttr;
         mPopupStyleRes = popupStyleRes;
         mOverflowOnly = overflowOnly;
@@ -94,7 +98,7 @@
                 mContext, null, mPopupStyleAttr, mPopupStyleRes);
         popupWindow.setOnItemClickListener(this);
         popupWindow.setOnDismissListener(this);
-        popupWindow.setAnchorView(mAnchor);
+        popupWindow.setAnchorView(mAnchorView);
         popupWindow.setDropDownGravity(mDropDownGravity);
         popupWindow.setModal(true);
         popupWindow.setTouchModal(false);
@@ -116,6 +120,14 @@
             popupWindow.show();
             mListViews.add((DropDownListView) popupWindow.getListView());
         }
+
+        mShownAnchorView = mAnchorView;
+        if (mShownAnchorView != null) {
+            final boolean addGlobalListener = mTreeObserver == null;
+            mTreeObserver = mShownAnchorView.getViewTreeObserver(); // Refresh to latest
+            if (addGlobalListener) mTreeObserver.addOnGlobalLayoutListener(this);
+            mShownAnchorView.addOnAttachStateChangeListener(this);
+        }
     }
 
     @Override
@@ -160,7 +172,7 @@
         lastListView.getLocationOnScreen(screenLocation);
 
         final Rect displayFrame = new Rect();
-        mAnchor.getWindowVisibleDisplayFrame(displayFrame);
+        mShownAnchorView.getWindowVisibleDisplayFrame(displayFrame);
 
         if (mPreferredPosition == HORIZ_POSITION_RIGHT) {
             final int right = screenLocation[0] + lastListView.getWidth() + nextMenuWidth;
@@ -352,6 +364,13 @@
         }
 
         if (mPopupWindows.size() == 0) {
+            if (mTreeObserver != null) {
+                if (!mTreeObserver.isAlive()) mTreeObserver =
+                        mShownAnchorView.getViewTreeObserver();
+                mTreeObserver.removeGlobalOnLayoutListener(this);
+                mTreeObserver = null;
+            }
+            mShownAnchorView.removeOnAttachStateChangeListener(this);
             // If every [sub]menu was dismissed, that means the whole thing was dismissed, so notify
             // the owner.
             mOnDismissListener.onDismiss();
@@ -379,7 +398,7 @@
 
     @Override
     public void setAnchorView(View anchor) {
-        mAnchor = anchor;
+        mAnchorView = anchor;
     }
 
     @Override
@@ -391,4 +410,32 @@
     public ListView getListView() {
         return mListViews.size() > 0 ? mListViews.get(mListViews.size() - 1) : null;
     }
+
+    @Override
+    public void onGlobalLayout() {
+        if (isShowing()) {
+            final View anchor = mShownAnchorView;
+            if (anchor == null || !anchor.isShown()) {
+                dismiss();
+            } else if (isShowing()) {
+                // Recompute window sizes and positions.
+                for (MenuPopupWindow popup : mPopupWindows) {
+                    popup.show();
+                }
+            }
+        }
+    }
+
+    @Override
+    public void onViewAttachedToWindow(View v) {
+    }
+
+    @Override
+    public void onViewDetachedFromWindow(View v) {
+        if (mTreeObserver != null) {
+            if (!mTreeObserver.isAlive()) mTreeObserver = v.getViewTreeObserver();
+            mTreeObserver.removeGlobalOnLayoutListener(this);
+        }
+        v.removeOnAttachStateChangeListener(this);
+    }
 }
\ No newline at end of file
diff --git a/core/java/com/android/internal/view/menu/MenuPopupHelper.java b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
index e0d7fee..ea79983 100644
--- a/core/java/com/android/internal/view/menu/MenuPopupHelper.java
+++ b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
@@ -16,10 +16,11 @@
 
 package com.android.internal.view.menu;
 
+import com.android.internal.view.menu.MenuPresenter.Callback;
+
 import android.content.Context;
 import android.view.Gravity;
 import android.view.View;
-import android.view.ViewTreeObserver;
 import android.widget.PopupWindow;
 
 /**
@@ -27,8 +28,7 @@
  *
  * @hide
  */
-public class MenuPopupHelper implements ViewTreeObserver.OnGlobalLayoutListener,
-        PopupWindow.OnDismissListener, View.OnAttachStateChangeListener {
+public class MenuPopupHelper implements PopupWindow.OnDismissListener {
     private final Context mContext;
     private final MenuBuilder mMenu;
     private final boolean mOverflowOnly;
@@ -37,9 +37,9 @@
 
     private View mAnchorView;
     private MenuPopup mPopup;
-    private ViewTreeObserver mTreeObserver;
 
     private int mDropDownGravity = Gravity.NO_GRAVITY;
+    private Callback mPresenterCallback;
 
     public MenuPopupHelper(Context context, MenuBuilder menu) {
         this(context, menu, null, false, com.android.internal.R.attr.popupMenuStyle, 0);
@@ -114,18 +114,15 @@
             return true;
         }
 
-        final View anchor = mAnchorView;
-        if (anchor != null) {
-            final boolean addGlobalListener = mTreeObserver == null;
-            mTreeObserver = anchor.getViewTreeObserver(); // Refresh to latest
-            if (addGlobalListener) mTreeObserver.addOnGlobalLayoutListener(this);
-            anchor.addOnAttachStateChangeListener(this);
-            mPopup.setAnchorView(anchor);
-            mPopup.setGravity(mDropDownGravity);
-        } else {
+        if (mAnchorView == null) {
             return false;
         }
 
+        mPopup = createMenuPopup();
+        mPopup.setAnchorView(mAnchorView);
+        mPopup.setGravity(mDropDownGravity);
+        mPopup.setCallback(mPresenterCallback);
+
         // In order for subclasses of MenuPopupHelper to satisfy the OnDismissedListener interface,
         // we must set the listener to this outer Helper rather than to the inner MenuPopup.
         // Not to worry -- the inner MenuPopup will call our own #onDismiss method after it's done
@@ -146,45 +143,15 @@
     @Override
     public void onDismiss() {
         mPopup = null;
-        if (mTreeObserver != null) {
-            if (!mTreeObserver.isAlive()) mTreeObserver = mAnchorView.getViewTreeObserver();
-            mTreeObserver.removeGlobalOnLayoutListener(this);
-            mTreeObserver = null;
-        }
-        mAnchorView.removeOnAttachStateChangeListener(this);
     }
 
     public boolean isShowing() {
         return mPopup != null && mPopup.isShowing();
     }
 
-    @Override
-    public void onGlobalLayout() {
-        if (isShowing()) {
-            final View anchor = mAnchorView;
-            if (anchor == null || !anchor.isShown()) {
-                dismiss();
-            } else if (isShowing()) {
-                // Recompute window size and position
-                mPopup.show();
-            }
-        }
-    }
-
-    @Override
-    public void onViewAttachedToWindow(View v) {
-    }
-
-    @Override
-    public void onViewDetachedFromWindow(View v) {
-        if (mTreeObserver != null) {
-            if (!mTreeObserver.isAlive()) mTreeObserver = v.getViewTreeObserver();
-            mTreeObserver.removeGlobalOnLayoutListener(this);
-        }
-        v.removeOnAttachStateChangeListener(this);
-    }
 
     public void setCallback(MenuPresenter.Callback cb) {
+        mPresenterCallback = cb;
         mPopup.setCallback(cb);
     }
 }
diff --git a/core/java/com/android/internal/view/menu/StandardMenuPopup.java b/core/java/com/android/internal/view/menu/StandardMenuPopup.java
index 9a30ffa..530b16a 100644
--- a/core/java/com/android/internal/view/menu/StandardMenuPopup.java
+++ b/core/java/com/android/internal/view/menu/StandardMenuPopup.java
@@ -10,6 +10,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.View.OnKeyListener;
+import android.view.ViewTreeObserver;
 import android.widget.AdapterView;
 import android.widget.ListView;
 import android.widget.MenuPopupWindow;
@@ -24,7 +25,8 @@
  * viewport.
  */
 final class StandardMenuPopup extends MenuPopup implements OnDismissListener, OnItemClickListener,
-        MenuPresenter, OnKeyListener {
+        MenuPresenter, OnKeyListener, ViewTreeObserver.OnGlobalLayoutListener,
+        View.OnAttachStateChangeListener {
 
     private final Context mContext;
     private final LayoutInflater mInflater;
@@ -34,15 +36,22 @@
     private final int mPopupMaxWidth;
     private final int mPopupStyleAttr;
     private final int mPopupStyleRes;
+    // The popup window is final in order to couple its lifecycle to the lifecycle of the
+    // StandardMenuPopup.
+    private final MenuPopupWindow mPopup;
 
     private PopupWindow.OnDismissListener mOnDismissListener;
 
     private View mAnchorView;
-    private MenuPopupWindow mPopup;
+    private View mShownAnchorView;
     private Callback mPresenterCallback;
+    private ViewTreeObserver mTreeObserver;
 
     private ViewGroup mMeasureParent;
 
+    /** Whether the popup has been dismissed. Once dismissed, it cannot be opened again. */
+    private boolean wasDismissed;
+
     /** Whether the cached content width value is valid. */
     private boolean mHasContentWidth;
 
@@ -88,18 +97,26 @@
             return true;
         }
 
+        if (mAnchorView == null) {
+            return false;
+        }
+
+        mShownAnchorView = mAnchorView;
+
         mPopup.setOnDismissListener(this);
         mPopup.setOnItemClickListener(this);
         mPopup.setAdapter(mAdapter);
         mPopup.setModal(true);
 
-        final View anchor = mAnchorView;
-        if (anchor != null) {
-            mPopup.setAnchorView(anchor);
-            mPopup.setDropDownGravity(mDropDownGravity);
-        } else {
-            return false;
+        final View anchor = mShownAnchorView;
+        final boolean addGlobalListener = mTreeObserver == null;
+        mTreeObserver = anchor.getViewTreeObserver(); // Refresh to latest
+        if (addGlobalListener) {
+            mTreeObserver.addOnGlobalLayoutListener(this);
         }
+        anchor.addOnAttachStateChangeListener(this);
+        mPopup.setAnchorView(anchor);
+        mPopup.setDropDownGravity(mDropDownGravity);
 
         if (!mHasContentWidth) {
             mContentWidth = measureIndividualMenuWidth(
@@ -141,14 +158,20 @@
 
     @Override
     public boolean isShowing() {
-        return mPopup != null && mPopup.isShowing();
+        return !wasDismissed && mPopup.isShowing();
     }
 
     @Override
     public void onDismiss() {
-        mPopup = null;
+        wasDismissed = true;
         mMenu.close();
 
+        if (mTreeObserver != null) {
+            if (!mTreeObserver.isAlive()) mTreeObserver = mShownAnchorView.getViewTreeObserver();
+            mTreeObserver.removeGlobalOnLayoutListener(this);
+            mTreeObserver = null;
+        }
+        mShownAnchorView.removeOnAttachStateChangeListener(this);
         mOnDismissListener.onDismiss();
     }
 
@@ -170,7 +193,8 @@
     public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
         if (subMenu.hasVisibleItems()) {
             MenuPopupHelper subPopup = new MenuPopupHelper(
-                    mContext, subMenu, mAnchorView, mOverflowOnly, mPopupStyleAttr, mPopupStyleRes);
+                    mContext, subMenu, mShownAnchorView, mOverflowOnly, mPopupStyleAttr,
+                    mPopupStyleRes);
             subPopup.setCallback(mPresenterCallback);
 
             boolean preserveIconSpacing = false;
@@ -243,4 +267,30 @@
     public ListView getListView() {
         return mPopup.getListView();
     }
+
+    @Override
+    public void onGlobalLayout() {
+        if (isShowing()) {
+            final View anchor = mShownAnchorView;
+            if (anchor == null || !anchor.isShown()) {
+                dismiss();
+            } else if (isShowing()) {
+                // Recompute window size and position
+                mPopup.show();
+            }
+        }
+    }
+
+    @Override
+    public void onViewAttachedToWindow(View v) {
+    }
+
+    @Override
+    public void onViewDetachedFromWindow(View v) {
+        if (mTreeObserver != null) {
+            if (!mTreeObserver.isAlive()) mTreeObserver = v.getViewTreeObserver();
+            mTreeObserver.removeGlobalOnLayoutListener(this);
+        }
+        v.removeOnAttachStateChangeListener(this);
+    }
 }
\ No newline at end of file
diff --git a/packages/DocumentsUI/res/color/item_doc_grid_overlay.xml b/packages/DocumentsUI/res/color/item_doc_grid_overlay.xml
index 6959c65..6dcbb38 100644
--- a/packages/DocumentsUI/res/color/item_doc_grid_overlay.xml
+++ b/packages/DocumentsUI/res/color/item_doc_grid_overlay.xml
@@ -17,7 +17,8 @@
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item
         android:state_activated="true"
-        android:color="?android:attr/colorControlHighlight" />
+        android:color="?android:attr/colorAccent"
+        android:alpha="0.1" />
     <item
         android:state_enabled="false"
         android:color="?android:attr/colorBackground"
diff --git a/packages/DocumentsUI/res/values/attrs.xml b/packages/DocumentsUI/res/values/attrs.xml
new file mode 100644
index 0000000..0afc3a2
--- /dev/null
+++ b/packages/DocumentsUI/res/values/attrs.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<resources>
+    <declare-styleable name="DocumentsBaseTheme">
+        <attr name="colorActionMode" format="color"/>
+    </declare-styleable>
+</resources>
diff --git a/packages/DocumentsUI/res/values/colors.xml b/packages/DocumentsUI/res/values/colors.xml
index 6002dde..cb6957d 100644
--- a/packages/DocumentsUI/res/values/colors.xml
+++ b/packages/DocumentsUI/res/values/colors.xml
@@ -19,18 +19,20 @@
     <color name="material_grey_300">#ffeeeeee</color>
     <color name="material_grey_600">#ff757575</color>
     <color name="material_grey_800">#ff424242</color>
-    <color name="material_blue_700">#ff1976d2</color>
-    <color name="material_blue_500">#ff2196f3</color>
 
     <color name="primary_dark">@*android:color/material_blue_grey_900</color>
     <color name="primary">@*android:color/material_blue_grey_800</color>
     <color name="accent">@*android:color/material_deep_teal_500</color>
 
+    <color name="platform_blue_100">#ffd0d9ff</color>
+    <color name="platform_blue_500">#ff5677fc</color>
+    <color name="platform_blue_700">#ff455ede</color>
+    <color name="platform_blue_a100">#ffa6baff</color>
+    <color name="platform_blue_a200">#ffff5177</color>
+    
     <color name="directory_background">@color/material_grey_300</color>
     <color name="item_doc_grid_background">#FFFFFFFF</color>
     <color name="item_doc_grid_protect_background">#88000000</color>
-    <color name="status_bar_background">@color/material_blue_700</color>
-    <color name="action_mode_status_bar_background">@color/material_grey_800</color>
     <color name="band_select_background">#88ffffff</color>
     <color name="band_select_border">#44000000</color>
 </resources>
diff --git a/packages/DocumentsUI/res/values/styles.xml b/packages/DocumentsUI/res/values/styles.xml
index e67f956..8301816 100644
--- a/packages/DocumentsUI/res/values/styles.xml
+++ b/packages/DocumentsUI/res/values/styles.xml
@@ -28,6 +28,7 @@
         <item name="android:colorPrimaryDark">@color/primary_dark</item>
         <item name="android:colorPrimary">@color/primary</item>
         <item name="android:colorAccent">@color/accent</item>
+        <item name="colorActionMode">@color/material_grey_800</item>
 
         <item name="android:listDivider">@*android:drawable/list_divider_material</item>
 
@@ -43,6 +44,7 @@
         <item name="actionBarWidgetTheme">@null</item>
         <item name="actionBarTheme">@style/ActionBarTheme</item>
         <item name="actionBarPopupTheme">@style/ActionBarPopupTheme</item>
+        <item name="colorActionMode">@color/material_grey_800</item>
 
         <item name="android:listDivider">@*android:drawable/list_divider_material</item>
 
@@ -68,16 +70,21 @@
     </style>
 
     <style name="AlertDialogTheme" parent="@android:style/Theme.Material.Light.Dialog.Alert">
-        <item name="android:colorAccent">@color/material_blue_700</item>
+        <item name="android:colorAccent">@color/platform_blue_700</item>
     </style>
 
     <style name="FilesTheme" parent="@style/DocumentsBaseTheme.FullScreen">
-        <item name="android:colorPrimaryDark">@color/material_blue_700</item>
-        <item name="android:colorPrimary">@color/material_blue_500</item>
-        <item name="android:colorAccent">@color/material_blue_700</item>
-        <item name="android:actionModeStyle">@style/ActionModeStyle</item>
+        <item name="android:colorPrimaryDark">@color/platform_blue_700</item>
+        <item name="android:colorPrimary">@color/platform_blue_500</item>
+        <item name="android:colorAccent">@color/platform_blue_700</item>
+        <item name="android:actionModeStyle">@style/FilesActionModeStyle</item>
+        <item name="colorActionMode">@color/platform_blue_700</item>
 
         <item name="android:alertDialogTheme">@style/AlertDialogTheme</item>
     </style>
 
+    <style name="FilesActionModeStyle" parent="@android:style/Widget.Material.Light.ActionMode">
+        <item name="android:background">@color/platform_blue_100</item>
+    </style>
+    
 </resources>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
index cfd4ecb..046f3df 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
@@ -637,27 +637,25 @@
         @Override
         public void onSelectionChanged() {
             mModel.getSelection(mSelected);
+            TypedValue color = new TypedValue();
             if (mSelected.size() > 0) {
                 if (DEBUG) Log.d(TAG, "Maybe starting action mode.");
                 if (mActionMode == null) {
                     if (DEBUG) Log.d(TAG, "Yeah. Starting action mode.");
                     mActionMode = getActivity().startActionMode(this);
-                    getActivity().getWindow().setStatusBarColor(
-                        getResources().getColor(R.color.action_mode_status_bar_background));
                 }
+                getActivity().getTheme().resolveAttribute(
+                    R.attr.colorActionMode, color, true);
                 updateActionMenu();
             } else {
                 if (DEBUG) Log.d(TAG, "Finishing action mode.");
                 if (mActionMode != null) {
                     mActionMode.finish();
                 }
-                // Obtain the original status bar color from the theme, and restore it.
-                TypedValue color = new TypedValue();
                 getActivity().getTheme().resolveAttribute(
                     android.R.attr.colorPrimaryDark, color, true);
-                getActivity().getWindow().setStatusBarColor(color.data);
-
             }
+            getActivity().getWindow().setStatusBarColor(color.data);
 
             if (mActionMode != null) {
                 mActionMode.setTitle(TextUtils.formatSelectedCount(mSelected.size()));
diff --git a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
index 8f9025a..450def7 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
@@ -90,10 +90,6 @@
 
         mClipper = new DocumentClipper(this);
         mDrawer = DrawerController.create(this);
-        if (mDrawer.isPresent()) {
-            setTheme(R.style.DocumentsNonDialogTheme);
-        }
-
 
         RootsFragment.show(getFragmentManager(), null);
         if (!mState.restored) {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 325196d..bfeddb3 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -234,7 +234,7 @@
             for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
                 final Task task = tasks.get(taskNdx);
                 task.getBounds(mTmpRect);
-                if (mTmpRect.contains(x, y)) {
+                if (task.inFreeformWorkspace() && mTmpRect.contains(x, y)) {
                     return task.mTaskId;
                 }
             }
@@ -299,7 +299,7 @@
                  * (For freeform focused task, the below logic will first remove the enlarged
                  * area, then add back the inner area.)
                  */
-                final boolean isFreeformed = win.inFreeformWorkspace();
+                final boolean isFreeformed = task.inFreeformWorkspace();
                 if (task != focusedTask || isFreeformed) {
                     mTmpRect.set(win.mVisibleFrame);
                     mTmpRect.intersect(win.mVisibleInsets);
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 07a850b..cc9efdb 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -426,6 +426,10 @@
         return (tokensCount != 0) && mAppTokens.get(tokensCount - 1).showForAllUsers;
     }
 
+    boolean inFreeformWorkspace() {
+        return mStack != null && mStack.mStackId == FREEFORM_WORKSPACE_STACK_ID;
+    }
+
     @Override
     public boolean isFullscreen() {
         return mFullscreen;
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index 6e4d1c3..8d377fd 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -85,6 +85,7 @@
 
     private int mTaskId;
     private TaskStack mStack;
+    private boolean mResizing;
     private final Rect mWindowOriginalBounds = new Rect();
     private final Rect mWindowDragBounds = new Rect();
     private float mStartDragX;
@@ -131,8 +132,8 @@
                             notifyMoveLocked(newX, newY);
                         }
                         try {
-                            mService.mActivityManager.resizeTask(mTaskId, mWindowDragBounds,
-                                    true /* resizedByUser */);
+                            mService.mActivityManager.resizeTask(
+                                    mTaskId, mWindowDragBounds, true /* resizedByUser */);
                         } catch(RemoteException e) {}
                     } break;
 
@@ -152,6 +153,11 @@
                 }
 
                 if (endDrag) {
+                    mResizing = false;
+                    try {
+                        mService.mActivityManager.resizeTask(
+                                mTaskId, mWindowDragBounds, true /* resizedByUser */);
+                    } catch(RemoteException e) {}
                     // Post back to WM to handle clean-ups. We still need the input
                     // event handler for the last finishInputEvent()!
                     mService.mH.sendEmptyMessage(H.FINISH_TASK_POSITIONING);
@@ -280,6 +286,10 @@
         mService.resumeRotationLocked();
     }
 
+    boolean isTaskResizing(final Task task) {
+        return mResizing && task != null && mTaskId == task.mTaskId;
+    }
+
     void startDragLocked(WindowState win, boolean resize, float startX, float startY) {
         if (DEBUG_TASK_POSITIONING) {
             Slog.d(TAG, "startDragLocked: win=" + win + ", resize=" + resize
@@ -300,6 +310,7 @@
             if (startY > visibleFrame.bottom) {
                 mCtrlType |= CTRL_BOTTOM;
             }
+            mResizing = true;
         }
 
         final Task task = win.getTask();
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 789354d..e467b19 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -557,7 +557,7 @@
 
         final Task task = mAppToken != null ? getTask() : null;
         final boolean nonFullscreenTask = task != null && !task.isFullscreen();
-        final boolean freeformWorkspace = inFreeformWorkspace();
+        final boolean freeformWorkspace = task != null && task.inFreeformWorkspace();
         if (nonFullscreenTask) {
             task.getBounds(mContainingFrame);
             final WindowState imeWin = mService.mInputMethodWindow;
@@ -897,6 +897,11 @@
         return stack == null ? mDisplayContent : stack.getDisplayContent();
     }
 
+    public DisplayInfo getDisplayInfo() {
+        final DisplayContent displayContent = getDisplayContent();
+        return displayContent != null ? displayContent.getDisplayInfo() : null;
+    }
+
     public int getDisplayId() {
         final DisplayContent displayContent = getDisplayContent();
         if (displayContent == null) {
@@ -935,7 +940,7 @@
         if (task != null) {
             task.getBounds(bounds);
             if (forTouch == BOUNDS_FOR_TOUCH) {
-                if (inFreeformWorkspace()) {
+                if (task.inFreeformWorkspace()) {
                     final int delta = calculatePixelFromDp(RESIZE_HANDLE_WIDTH_IN_DP);
                     bounds.inset(-delta, -delta);
                 }
@@ -1668,9 +1673,13 @@
     }
 
     boolean inFreeformWorkspace() {
-        final Task task = getTask();
-        return task != null && task.mStack != null &&
-                task.mStack.mStackId == FREEFORM_WORKSPACE_STACK_ID;
+        final Task task = mAppToken != null ? getTask() : null;
+        return task != null && task.inFreeformWorkspace();
+    }
+
+    boolean isDragResizing() {
+        final Task task = mAppToken != null ? getTask() : null;
+        return mService.mTaskPositioner != null && mService.mTaskPositioner.isTaskResizing(task);
     }
 
     private int calculatePixelFromDp(int dp) {
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 0ab96d6..dfc9784 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -804,8 +804,17 @@
                 width = w.mRequestedWidth;
                 height = w.mRequestedHeight;
             } else {
-                width = w.mCompatFrame.width();
-                height = w.mCompatFrame.height();
+                // When we're doing a drag-resizing, request a surface that's fullscreen size,
+                // so that we don't need to reallocate during the process. This also prevents
+                // buffer drops due to size mismatch.
+                final DisplayInfo displayInfo = w.getDisplayInfo();
+                if (displayInfo != null && w.isDragResizing()) {
+                    width = displayInfo.logicalWidth;
+                    height = displayInfo.logicalHeight;
+                } else {
+                    width = w.mCompatFrame.width();
+                    height = w.mCompatFrame.height();
+                }
             }
 
             // Something is wrong and SurfaceFlinger will not like this,
@@ -1315,9 +1324,15 @@
 
         final boolean fullscreen = w.isFullscreen(displayInfo.appWidth, displayInfo.appHeight);
         final Rect clipRect = mTmpClipRect;
-        // We use the clip rect as provided by the tranformation for non-fullscreen windows to
-        // avoid premature clipping with the system decor rect.
-        clipRect.set((mHasClipRect && !fullscreen) ? mClipRect : w.mSystemDecorRect);
+        if (w.isDragResizing()) {
+            // When we're doing a drag-resizing, the surface is set up to cover full screen.
+            // Set the clip rect to be the same size so that we don't get any scaling.
+            clipRect.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
+        } else {
+            // We use the clip rect as provided by the tranformation for non-fullscreen windows to
+            // avoid premature clipping with the system decor rect.
+            clipRect.set((mHasClipRect && !fullscreen) ? mClipRect : w.mSystemDecorRect);
+        }
 
         // Expand the clip rect for surface insets.
         final WindowManager.LayoutParams attrs = w.mAttrs;
@@ -1391,8 +1406,17 @@
             width  = w.mRequestedWidth;
             height = w.mRequestedHeight;
         } else {
-            width = w.mCompatFrame.width();
-            height = w.mCompatFrame.height();
+            // When we're doing a drag-resizing, request a surface that's fullscreen size,
+            // so that we don't need to reallocate during the process. This also prevents
+            // buffer drops due to size mismatch.
+            final DisplayInfo displayInfo = w.getDisplayInfo();
+            if (displayInfo != null && w.isDragResizing()) {
+                width = displayInfo.logicalWidth;
+                height = displayInfo.logicalHeight;
+            } else {
+                width = w.mCompatFrame.width();
+                height = w.mCompatFrame.height();
+            }
         }
 
         // Something is wrong and SurfaceFlinger will not like this,
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 52efa68..86da94f 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -712,7 +712,12 @@
                             }
                         }
                     }
-
+                    /*
+                     * Updates the shown frame before we set up the surface. This is needed because
+                     * the resizing could change the top-left position (in addition to size) of the
+                     * window. setSurfaceBoundariesLocked uses mShownFrame to position the surface.
+                     */
+                    winAnimator.computeShownFrameLocked();
                     winAnimator.setSurfaceBoundariesLocked(recoveringMemory);
                 }